]> gitweb.morketsmerke.org Git - mmdev.git/commitdiff
Przesłanie plików na prywatne repozytorium - snapshot przed wiekszymi zmianami
authorxf0r3m <jakubstasinski@protonmail.com>
Fri, 28 Jul 2023 19:13:22 +0000 (21:13 +0200)
committerxf0r3m <jakubstasinski@protonmail.com>
Fri, 28 Jul 2023 19:13:22 +0000 (21:13 +0200)
95 files changed:
README.md [new file with mode: 0755]
articles/bsd/20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html [new file with mode: 0755]
articles/bsd/OpenBSD_jako_bramka_sieciowa.html [new file with mode: 0755]
articles/bsd/dziennik_OpenBSD.html [new file with mode: 0755]
articles/bsd/index.html [new file with mode: 0755]
articles/bsd/instalacja_NetBSD.html [new file with mode: 0755]
articles/bsd/instalacja_OpenBSD.html [new file with mode: 0755]
articles/hardware/apple_macbook_a1181.html [new file with mode: 0755]
articles/hardware/index.html [new file with mode: 0755]
articles/immudex/aktualizacja_immudex.html [new file with mode: 0755]
articles/immudex/immudex.html [new file with mode: 0755]
articles/immudex/index.html [new file with mode: 0755]
articles/immudex/ingerencja_w_obraz_immudex_-_przewiniecie.html [new file with mode: 0755]
articles/immudex/instalacja_sterownika_dla_Nvidia_GF_920M.html [new file with mode: 0644]
articles/immudex/instalacja_systemu.html [new file with mode: 0755]
articles/immudex/koncepcje_immudex.html [new file with mode: 0755]
articles/immudex/lista_oprogramowania_immudex.html [new file with mode: 0644]
articles/immudex/odtworzenie_srodowiska_budowania_immudex_z_LiveCD.html [new file with mode: 0755]
articles/immudex/plik_wersji.html [new file with mode: 0755]
articles/immudex/transformacja_gnu_linux_debian_w_immudex.html [new file with mode: 0755]
articles/linux/Alpine_Linux_jako_bramka_sieciowa.html [new file with mode: 0644]
articles/linux/NFS_-_udostepnianie_i_montowanie_udziałów.html [new file with mode: 0644]
articles/linux/OTP/index.html [new file with mode: 0644]
articles/linux/OTP/instalacja.html [new file with mode: 0644]
articles/linux/Parabola_GNU_Linux-libre.html [new file with mode: 0644]
articles/linux/generowanie_certyfikatu_Let's_Encrypt_typu_wildcard.html [new file with mode: 0644]
articles/linux/generowanie_certyfikatów_self-signed_OpenSSL.html [new file with mode: 0644]
articles/linux/greenOS/btw_i_use_arch.html [new file with mode: 0644]
articles/linux/greenOS/index.html [new file with mode: 0644]
articles/linux/greenOS/instalacja_greenos.html [new file with mode: 0644]
articles/linux/greenOS/torwards_the_sun.html [new file with mode: 0644]
articles/linux/greenOSAE.html [new file with mode: 0644]
articles/linux/greenOSTe.html [new file with mode: 0644]
articles/linux/index.html [new file with mode: 0755]
articles/linux/instalacja_Alpine_Linux.html [new file with mode: 0644]
articles/linux/instalacja_Spotify_oraz_atom.io_za_pomocą_Snap.html [new file with mode: 0644]
articles/linux/instalacja_aktualizacja_pakietów_na_Arch_Linux.html [new file with mode: 0644]
articles/linux/instalacja_kontenerów_LXD.html [new file with mode: 0644]
articles/linux/instalacja_sandstorm.io.html [new file with mode: 0644]
articles/linux/instalacja_sterowników_Nvidii_na_Debian_11.html [new file with mode: 0755]
articles/linux/instalacja_systemu_z_własnego_obrazu_LiveCD_z_Debianem.html [new file with mode: 0644]
articles/linux/przekierowanie_portów_do_kontenerów_LXD.html [new file with mode: 0644]
articles/linux/samba_AD_DC_-_Instalacja.html [new file with mode: 0644]
articles/linux/samba_AD_DC_-_NTP.html [new file with mode: 0644]
articles/linux/szyfrowany_rootfs_na_greenOS.html [new file with mode: 0755]
articles/linux/szyfrowany_rootfs_na_greenOSTe.html [new file with mode: 0755]
articles/linux/tworzenie_RAID_programowych_w_systemach_GNU_Linux.html [new file with mode: 0644]
articles/linux/tworzenie_logicznych_woluminów_LVM.html [new file with mode: 0644]
articles/linux/uruchomienie_skryptu_podczas_ładowania_systemu_-_jednostka_systemd.html [new file with mode: 0644]
articles/linux/własne_LiveCD_z_Debianem.html [new file with mode: 0644]
articles/raspberrypi/Raspberry_Pi_Zero_jako_router_3G.html [new file with mode: 0644]
articles/raspberrypi/Raspberry_Pi_jako_przekaźnik_bluetooth.html [new file with mode: 0644]
articles/raspberrypi/Raspberry_Pi_jako_serwer_poczty.html [new file with mode: 0644]
articles/raspberrypi/Raspberry_Pi_jako_serwer_wydruku.html [new file with mode: 0644]
articles/raspberrypi/index.html [new file with mode: 0755]
articles/raspberrypi/mini_serwer_LXD_z_łącznością_bezprzewodową_na_Raspberry_Pi.html [new file with mode: 0644]
articles/raspberrypi/podłączanie_7-calowego_ekranu_dotykowego_do_Raspberry_Pi.html [new file with mode: 0644]
articles/raspberrypi/podłączanie_modułu_RDM_6300_do_Raspberry_Pi_oraz_odczyt_tagu_RFID.html [new file with mode: 0644]
articles/raspberrypi/połączenie_z_Raspberry_Pi_Zero_przez_USB.html [new file with mode: 0644]
articles/terminallog/BASH_bushido.html [new file with mode: 0755]
articles/terminallog/GNU_mailutils_jako_program_mailowy.html [new file with mode: 0755]
articles/terminallog/Git_-_podstawy_systemu_kontroli_wersji.html [new file with mode: 0755]
articles/terminallog/Linux.Podstawy.html [new file with mode: 0644]
articles/terminallog/RedHat_-_RHCSA.html [new file with mode: 0755]
articles/terminallog/cwiczenia_python.html [new file with mode: 0755]
articles/terminallog/index.html [new file with mode: 0755]
articles/terminallog/jak_działa_linux.html [new file with mode: 0644]
articles/terminallog/konfiguracja_HAProxy_dla_HTTP_i_HTTPS.html [new file with mode: 0755]
articles/terminallog/laboratorium_sieci_VPN.html [new file with mode: 0755]
articles/terminallog/sieci_VPN.html [new file with mode: 0644]
articles/terminallog/ściąga_z_PYTHONga.html [new file with mode: 0755]
articles/tnt/automatyczne_montowanie_partycji_przy_starcie_systemu.html [new file with mode: 0755]
articles/tnt/automatyczne_przewinięcie_strony_na_sam_dół_w_JS.html [new file with mode: 0755]
articles/tnt/dowiązania_symboliczne_na_udziale_samba.html [new file with mode: 0755]
articles/tnt/index.html [new file with mode: 0755]
articles/tnt/katalog_hostingu_WWW_poza_var_www.html [new file with mode: 0755]
articles/tnt/konfiguracja_programu_pocztowego_mutt.html [new file with mode: 0644]
articles/tnt/miejsce_montowania_udziału_samba_przez_GNOME_pliki.html [new file with mode: 0755]
articles/tnt/montowanie_virtualbox_shared_folder_na_Alpine_Linux.html [new file with mode: 0755]
articles/tnt/obsługa_uploadu_plików_za_pomocą_obszaru_dropzone_JS.html [new file with mode: 0755]
articles/tnt/pobieranie_filmów_z_xvideos.html [new file with mode: 0755]
articles/tnt/przekierowanie_na_HTTPS_w_pliku_hostingu_apache2.html [new file with mode: 0755]
articles/tnt/przenoszenie_systemu_operacyjnego_z_maszyny_wirtualnej_na_fizyczny_komputer.html [new file with mode: 0755]
articles/tnt/tworzenie_maszyn_wirtualnych_VirtualBox_z_poziomu_terminala.html [new file with mode: 0755]
articles/tnt/tworzenie_szyfrowanych_archiwów_za_pomocą_7-zip.html [new file with mode: 0755]
articles/tnt/uruchomienie_kodu_JS_w_tle_innego_skryptu_JS.html [new file with mode: 0755]
articles/tnt/uruchomienie_ssh_na_raspberry_pi.html [new file with mode: 0755]
articles/tnt/ustawienie_kodowania_polskich_znaków_w_MySQL.html [new file with mode: 0755]
articles/tnt/ustawienie_protokołu_VNC_dla_maszyn_VirtualBox_uruchamianych_w_trybie_headless.html [new file with mode: 0755]
articles/tnt/usunięcie_tablicy_RAID_madm.html [new file with mode: 0755]
articles/tnt/użycie_polecenia_rsync_w_PHP.html [new file with mode: 0755]
articles/tnt/zabezpieczenie_dostępu_RDP_do_maszyn_VirtualBox_hasłem.html [new file with mode: 0755]
articles/tnt/zwrot_wartości_logicznej_dla_sparsowanego_zapytania_SQL_w_PHP.html [new file with mode: 0755]
index.html [new file with mode: 0644]
style.css [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100755 (executable)
index 0000000..52d8599
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# morketsmerke-dev
+
+morketsmerke.github.io w wersji rozwojowej.
diff --git a/articles/bsd/20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html b/articles/bsd/20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html
new file mode 100755 (executable)
index 0000000..fc33fa6
--- /dev/null
@@ -0,0 +1,637 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <h1 class="title">Sun Netra T1 AC200 z NetBSD jako serwer mailowy</h1>
+                       <p>
+                       Czy można zmienić 20 letni serwer w coś użytecznego? I owszem. Czy jest to skuteczne, wszystko zależy od konfiguracji domen,
+                       do których będziemy wysyłać maile. Ja pomyślałem, że fajnie było by mieć serwer mailowy, chciaż patrząc na to jak często
+                       korzystam z wiadomości e-mail, to raczej jest on zbędny. Nie mniej jednak ciekawe wyzwanie, a żeby tego było mało za docelową
+                       maszynę wybrałem serwer <strong>Sun Netra T1 AC200</strong>, maszyna oparta na architekturze Sparc64, z procesorem ULTRASPARC 
+                       IIe V9 o taktowaniu 500MHz z 1 GB RAMU SDRAM ECC REG dwoma dyskami SCSI 17G. Dobór systemu operacyjnego to raczej był mus, anieżeli
+                       racjonalny wybór. Jak go kupiłem za całe 150 zł to pierwsze co chciałem zbootować na nim OpenBSD, ponieważ już ten 
+                       system trochę znałem (nie tak jak teraz, był 2016), jednak to się nie powiodło. Może jednak od początku. Sun Netra T1 AC200 
+                       jest serwerem, który nie posiada w ogóle żadnego układu graficznego, zatem do jego obsługi potrzebny jest PC lub Laptop ze 
+                       złączem COM/RS-232, to nie nie wszystko, bo złącze (<strong>SERIAL A/LOM</strong> - bo tak się nazywa to złącze, przez które 
+                       kontroluje się serwer) konsoli (można tak je chyba nazwać) to zwykłe gniazdo RJ-45. Sprawdziłem w oficjalnym podręczniku. 
+                       Do każdej Netry dołączany jest adapter <em>DB-25 - RJ-45</em>, oczywiście można skorzystać z <em>DB-9 - RJ-45</em>, ale ja 
+                       już nie pamiętam dlaczego jednak wybrałem  DB-25 oraz adapter <em>DB-25 - DB-9 (F-F)</em>. Adapter DB-25 - RJ-45 przychodzi 
+                       w dwóch częściach i trzeba włozyć odpowiednie kabelki w odpowiednie dziurki według dokumentacji. Jak to najlepiej zrobić, 
+                       otóż bierzemy kawałek UTP zarabiamy z jednej strony standard B z drugiej strony rozizolowywujemy wszystkie żyły, miernikiem 
+                       w teście diody sprawdzamy, który kabelek na adapterze łączy się, z którą żyłą UTP. Pamiętając o tym że będziemy w gniazdo 
+                       Serial A/LOM będziemy wtykać klasyczny patchcord ustawiamy piny na adapterze według dokumentacji. Pozłożeniu adaptera możemy 
+                       się podłączyć go do komputera, ja użyłem do tego komputera z Debianem z wiadomych dla siebie względów. W systemie należy 
+                       zainstalować program <strong>picocom</strong>. Samo połączenie wymaga jednego polecenia.
+                       </p>
+<pre class="code-block">
+$ sudo picocom -b 9600 /dev/ttyS
+</pre>
+                       <p>
+                       Po zwróceniu parametrów konfiguracyjnych połączenie zostanie wyświetlony napis <code class="code-inline">Terminal is ready</code>,
+                       naciskamy dwa razy klawisz <em>Enter</em> i w zależności od tego czy serwer jest włączony - dostaniemy odpowiedź 
+                       <code class="code-inline">ok</code> lub wyłączony - dostaniemy odpowiedź <code class="code-inline">lom&gt;</code>, jeśli jest
+                       wyłączony to możemy go włączyć za pomocą polecenia:
+                       </p>
+<pre class="code-block">
+lom&gt;poweron
+</pre>
+                       <p>
+                       Po włączeniu serwera uzyskamy odpowiedź <code class="code-inline">ok</code>. Kiedy serwer był już włączony możemy już bootwać jakiś
+                       system, oczywiście z płyty bo innej opcji poza siecią nie ma. Odnośnie systemów operacyjnych na ten serwer to sprawa wygląda tak że:
+                       </p>
+                       <ol>
+                               <li><strong>GNU/Linux Debian (port dla Sparc64)</strong> - Bootuje z płyty i jest się w stanie zainstalować, jednak nie mogłem
+                                       znaleźć żadnych mirrorów, aby móc cokolwiek zainstalować. Generalnie to jest mirror, ale wymaga wyższej konfiguracji,
+                                       niestety nie miałem chęci na zabawę tym.</li>
+                               <li><strong>FreeBSD 12.2 Sparc64</strong> - Próbował się bootować jednak wyświetlił kilka ciągów dziwnych znaków i każde 
+                                       naciśnięcie klawisza powodowalo wyświetlenie podobnych ciągów znaków.</li>
+                               <li><strong>OpenBSD 6.8 Sparc64</strong> - Po wydaniu polecenia bootwania z CD, serwer wyświetlił informacje 
+                                       <code class="code-inline">Fast Data Access MMU Miss</code>. Następnie zwrócł prompt <code class="code-inline">ok</code>
+                                       I to tyle w temacie OpenBSD na tym serwerze.</li>
+                               <li><strong>NetBSD 9.1 Sparc64</strong> - Bootuje się z płyty, instaluje się poprawnie (jeśli wybierzemy opcję instalacji
+                                       <code class="code-inline">Instalacja bez X11</code>. Jedyne co nie działa (przestało działać dzień po zainstalowaniu
+                                       systemu) manager instalacji pakietów binarnych, nie może pobrać paczki z bazą, podczas jej rozpakowywania zwraca
+                                       komunikat, który można zinterpretować jako plik jest uszkodzony. Można to ominąć. Instalując paczki z repozytorium
+                                       za pomocą narzędzia <strong>pkg_add</strong>, niestety musimy jako argument podać pełną ścieżkę do paczki w repo.
+                                       Jeszcze jedna rzecz, kiedy ja instalowałem to strasznie wolno pobierał te paczki, okazało się na początku próbował
+                                       połączyć się z CDN-em, za pomocą IPv6, które coś nie działało. Remedium na to było dodanie lokalnego resolwu 
+                                       <em>cdn.netbsd.org</em>, do pliku <em>/etc/hosts</em> na pierwszy napotkany adres IPv4.</li>
+
+                       </ol>
+                       <p>
+                       Bootowanie z płyty załączamy poleceniem:
+                       </p>
+<pre class="code-block">
+ok boot cdrom
+</pre>
+                       <p>
+                       Podczas instalacji z konsoli, jednym z pierwszych pytań zadanych przez instalator będzie wybranie rodzaju terminala z którego
+                       korzystamy, nalepiej wybrać <strong>xterm</strong>.
+                       </p>
+                       <p>
+                       Pod tym odnośnikiem znajduje się instrukcja jak zainstalować NetBSD:
+                       <a href="https://morketsmerke.github.io/articles/bsd/instalacja_NetBSD.html">
+                               https://morketsmerke.net/site/articles/bsd/instalacja_NetBSD.html
+                       </a>
+                       </p>
+                       <p>
+                       Jeśli system został już zainstalowany według instrukcji to po załadowaniu systemu ustawimy datę i czas, bateria mogłą się już w
+                       dawno rozładować. Pewnego razu po wywołaniu polecenia <code class="code-inline">date</code> zobaczyłem rok
+                       2019 a raz 2003 (mamy 2021). Aby ustawić date i czas dokonamy synchronizacji czasu z serwera NTP za pomocą polecenia:
+                       </p>
+<pre class="code-block">
+# ntpdate -b ntp1.inrim.it
+</pre>
+                       <p>
+                       Informacją zwrotną będzie to o ile sekund został przesunięty z zegar. Liczba może być naprawdę duża. Po synchronizacji
+                       dopiszmy do pliku <em>/etc/rc.conf</em> w linii <code class="code-inline">ntpdate=YES</code> adres hosta dla <em>ntpdate</em>
+                       <code class="code-inline">ntpdate_hosts="ntp2.inrim.it"</code>
+                       </p>
+                       <p>
+                       Do budowy serwera będziemy potrzebować kilku programów. Jednak jak je zainstalować z przy uszkodzonym źródle? Otóż sposób jest
+                       prosty. Pierwsze co to wywołujemy polecenie:
+                       </p>
+<pre class="code-block">
+$ host cdn.netbsd.org
+</pre>
+                       <p>
+                       Za pomocą pierwszego adresu IPv4 tworzymy wpis do pliku <em>/etc/hosts/</em>.
+                       </p>
+<pre class="code-block">
+151.101.1.6    cdn.netbsd.org
+</pre>
+                       <p>
+                       Następnie na komputerze, z którego łączymy się z serwerem czy to po konsoli szeregowej czy przez SSH, za pomocą przeglądarki 
+                       przechodzimy pod ten adres: <a href="http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/sparc64/9.1/All">
+                               http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/sparc64/9.1/All
+                       </a>
+                       Kilkając PPM na nazwę pakietu wybieramy opcję "Kopiuj adres odnośnika" i wklejamy do terminala jako argument polecenia 
+                       <code class="code-inline">pkg_add</code> podbnego programu jak na OpenBSD. W przypadku konsoli szeregowej może nie być to takie 
+                       łatwe, dlatego zalecam jednak połączenie przez SSH. Do pobrania mamy: <em>mc</em>, <em>vim</em>, <em>dovecot</em>, <em>openssl</em>,
+                       <em>ca-certificates</em>. 
+                       </p>
+                       <p>
+                       Po pobraniu tych programów możemy ustawić parametr <code class="code-inline">mydestination</code> na nazwę swojej domeny za pomocą 
+                       polecenia <code class="code-inline">postconf</code>.
+                       <p>
+<pre class="code-block">
+# postconf -e "mydestination=morketsmerke.net"
+</pre>
+                       <p>
+                       Następnie za pomocą <em>mc</em>, przejdziemy do katalogu <em>/etc/postfix</em> następnie w pliku <em>master.cf</em>, usuwamy znak 
+                       komentarza sprzed pierwszego wiersza w pierwszej tabeli.
+                       </p>
+<pre class="code-block">
+smtp   inet    n       -       n       -       -       smtpd
+</pre>
+                       <p>
+                       Teraz możemy połączyć się z serwerem SMTP za pomocą <em>telnet</em> i wyślemy mail do <em>roota</em>, żeby sprawdzić czy
+                       wspomniany wcześniej parametr działa.
+                       </p>
+<pre class="code-block">
+$ telnet localhost 25
+</pre>
+                       <p>
+                       Po podłączeniu się musimy wysłać maila za pomocą poleceń protokołu SMTP. Obecnie serwer nie posiada żadnych mechanizów bezpieczeństwa
+                       więc możemy od razu przejść do wysyłania maili. Pierwsze polecenie:
+                       </p>
+<pre class="code-block">
+mail from:&lt;xf0r3m@morketsmerke.net&gt;
+</pre>
+                       <p>
+                       W ten sposób przekazujemy serwerowi informacje że będziemy wysłać maila i w polu nadawcy będzie adres: xf0r3m@morketsmerke.net.
+                       Po zatwierdzeniu tego polecenia powinniśmy odpowiedź: <code class="code-inline">250 2.1.0 Ok</code>. 
+                       Uwaga! Ostre nawiasy są cześcią składni poleceń <code class="code-inline">mail from</code> oraz 
+                       <code class="code-inline">rcpt to</code>.
+                       </p>
+<pre class="code-block">
+rcpt to:&lt;root@morketsmerke.net&gt;
+</pre>
+                       <p>
+                       Powyższe polecenie wskazuje adresata wiadomości. Po jego podaniu serwer zwróci  
+                       <code class="code-inline">250 2.1.5 Ok</code>. Aby Rozpocząć redagowanie wiadomości wydajemy polecnie
+                       </p>
+<pre class="code-block">
+data
+</pre>
+                       <p>
+                       Serwer zwróci wtedy taki ciąg znaków jak <code class="code-inline">354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;</code>
+                       Oznacza to że aby zakończyć redagowanie wiadomości, należy przesłać do serwera linię z jedną kropką. Naciśnąć enter,
+                       kropka (<strong>.</strong>) i ponownie enter. Pola From, To oraz Subject (Temat) możemy definiować wewnątrz danych wiadomości.
+                       </p>
+<pre class="code-block">
+354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&lt;
+From: xf0r3m@morketsmerke.net
+To: root@morketsmerke.net
+Subject: Test serwera SMTP.
+
+Test serwera SMTP wewnątrz organizacji. Proszę o odpowiedź.
+.
+</pre>
+                       <p>
+                       Po wysłaniu maila sprawdźmy na koncie użytkownika <em>root</em> czy dostaliśmy wiadomość. Jeśli otrzymaliśmy wiadomość to teraz
+                       przejdziemy do zabezpieczenie serwera SMTP przed nieautoryzowanym dostępem.
+                       </p>
+                       <p>
+                       Opis konfiguracji SASL znajduje się pod adresem: 
+                       <a href="https://doc.dovecot.org/configuration_manual/howto/postfix_and_dovecot_sasl">
+                               https://doc.dovecot.org/configuration_manual/howto/postfix_and_dovecot_sasl
+                       </a>
+                       </p>
+                       <p>
+                       <em>Postfixa</em> na tym systemie nie instalowaliśmy, już był. Więc musimy sie upewnić czy został skompilowany wraz ze wspraciem dla
+                       <strong>Dovecot SASL</strong>.
+                       </p>
+<pre class="code-block">
+# postconf -a
+</pre>
+                       <p>
+                       Jeśli polecenie zwróci <code class="code-inline">dovecot</code>, to możemy przejść do konfiguracji SASL. W tym 
+                       przypadku, w pliku <em>/usr/pkg/etc/dovecot/conf.d/10-master.conf</em> musimy odnaleźć w sekcji 
+                       <code class="code-inline">auth</code>, deklaracje socketu.
+                       </p>
+<pre class="code-block">
+service auth {
+...
+       unix_listener /var/spool/postfix/private/auth {
+               mode = 0660
+               user = postfix
+               group = postfix
+       }
+...
+}
+
+auth_mechanisms = plain login
+</pre>
+                       <p>
+                       Następnie ustawić w niej użytkownika (<code class="code-inline">user</code>), grupę (<code class="code-inline">group</code>) oraz 
+                       prawa dostępu (<code class="code-inline">mode</code>), wartości do ustawienia zaprezentowano na powyższym przykładzie.
+                       Po ustawieniu tych informacji możemy przejść konfiguracji <em>Postfixa</em>. W pliku 
+                       <code class="code-inline">/etc/postfix/main.cf</code> na samym dole dopisujemy poniższe opcje.
+                       </p>
+<pre class="code-block">
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+smtpd_sasl_auth_enable = yes
+smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
+</pre>
+                       <p>
+                       Gdzie: 
+                       <ul>
+                               <li><code class="code-inline">smtpd_sasl_type</code> - typ implementacji SASL,</li>
+                               <li><code class="code-inline">smtpd_sasl_path</code> - ścieżka do socketu, względną ponieważ <em>Postfix</em> może mieć 
+                                       zapisany swój katalog roboczy, lub być <em>chroot-owany</em>,</li>
+                               <li><code class="code-inline">smtpd_sasl_auth_enable</code> - włączenie uwierzytelniania,</li>
+                               <li><code class="code-inline">smtpd_relay_restrictions</code> - ustawienie restrykcji dla przekazywania maili. Z racji
+                                       tego iż SMTP na porcie 25 będzie osiągalny z Internetu, aby otrzymywać maile z zewnątrz, to ograniczenia
+                                       ustawiono w taki sposób aby tylko uwierzytelnieni użytkownicy mogli wysyłać maile poza domenę.</li>
+                       </ul>
+                       </p>
+                       <p>
+                       Teraz skonfigurujemy dostęp do SMTP dla klientów przez SSL. Najlepiej rozpocząć to od przepisania konfiguracji z wcześniej 
+                       wymienionej strony dla usługi <strong>submission</strong>. Konfigurację umieszczamy w pliku <em>/etc/postfix/master.cf</em>. Możemy 
+                       zmodyfikować istniejący już tam wpis.
+                       <p>
+<pre class="code-block">
+submission     inet    n       -       n       -       -       smtpd
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_sasl_type=dovecot
+ -o smtpd_sasl_path=private/auth
+ -o smtpd_sasl_security_options=noanonymous
+ -o smtpd_sasl_local_domain=morketsmerke.net
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+ -o smtpd_sender_login_maps=hash:/etc/postfix/virtual
+ -o smtpd_sender_restrictions=reject_sender_login_mismatch
+ -o smtpd_recipient_restrictions=reject_non_fqdn_repcipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
+</pre>
+                       <p>
+                       Po zapisaniu konfiugracji, możemy teraz zmodyfikować konfigurację aby dostosować ją do <strong>smtps</strong>.
+                       </p>
+<pre class="code-block">
+smtps  inet    n       -       n       -       -       smtpd
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_tls_wrappermode=yes
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_sasl_type=dovecot
+ -o smtpd_sasl_path=private/auth
+ -o smtpd_sasl_security_options=noanonymous
+ -o smtpd_sasl_local_domain=morketsmerke.net
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+ -o smtpd_sender_login_maps=hash:/etc/postfix/virtual
+ -o smtpd_sender_restrictions=reject_sender_login_mismatch
+ -o smtpd_recipient_restrictions=reject_non_fqdn_repcipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
+</pre>
+                       <p>
+                       Gdzie:
+                       <ul>
+                               <li><code class="code-inline">smtpd_tls_security_level</code> - poziom bezpieczeństwa TLS,</li>
+                               <li><code class="code-inline">smtpd_tls_wrappermode</code> - umożliwienie użycia starszego SMTPS zamiast STARTTLS,</li>
+                               <li><code class="code-inline">smtpd_sasl_type</code> - typ implementacji SASL,</li>
+                               <li><code class="code-inline">smtpd_sasl_path</code> - ścieżka do socketu, dzięki któremu <em>Postfix</em> łączy się z
+                                       usługą SASL <em>Dovecot</em>,</li>
+                               <li><code class="code-inline">smtpd_sasl_security_options</code> - opcje bezpieczeństwa SASL przy ustawieniu 
+                                       <code class="code-inline">noanonymous</code> wyłącza się logowanie anonimowe na SMTP,</li>
+                               <li><code class="code-inline">smtpd_sasl_local_domain</code> - nazwa sfery uwierzytelniania SASL,</li>
+                               <li><code class="code-inline">smtpd_client_restrictions</code> - ograniczenia dla klientów,</li>
+                               <li><code class="code-inline">smtpd_sender_login_maps</code> - wskazanie mapowań loginów do adresów mailowych,</li>
+                               <li><code class="code-inline">smtpd_sender_restrictions</code> - ograniczenia wśród nadawców,</li>
+                               <li><code class="code-inline">smtpd_recipient_restrictions</code> - ograniczenia wśród odbiorców.</li>
+                       </ul>
+                       Generalnie takie opisy jak "ograniczenia wśród odbiorców" mogą nic nie mówić więc poniżej opisze ograniczenia w tych trzech grupach:
+                       <ul>
+                               <li>Ograniczenia wśród klientów: zezwól uwierzytelnionym klientom, resztę odrzuć.</li>
+                               <li>Ograniczenia wśród nadawców: odrzuć niezgodność loginu z adresem nadawcy według mapowania. Do tego potrzebne mapowanie
+                                       z opcji <code class="code-inline">smtpd_sender_login_maps</code>.</li>
+                               <li>Ograniczenia wśród odbiorców: odrzuć odbiorców bez nazw FQDN, odrzuć odbiorców z nieznanych domen,zezwól uwierzytelnionym
+                                       przez SASL, resztę odrzuć.</li>
+                       </ul>
+                       </p>
+                       <p>
+                       Teraz musimy umieść pliki certyfikatu w <em>/etc/openssl</em> i wskazać je w pliku konfiguracyjnym <em>Postfixa</em> 
+                       (<em>/etc/postfix/main.cf</em>).
+                       </p>
+<pre class="code-block">
+smtpd_tls_cert_file=/etc/openssl/fullchain1.pem
+smtpd_tls_cert_key=/etc/openssl/privkey1.pem
+</pre>
+                       <p>
+                       Do zrobienie pozostało utworzenie bazy danych, w której będą znajdować się odniesienia użytkowników systemowych do adresów poczty.
+                       Na początku musimy utworzyć plik <code class="code-inline">/etc/postfix/virtual</code>. Każda linia w pliku to jedno mapowanie.
+                       </p>
+<pre class="code-block">
+root@morketsmerke.net  root
+xf0r3m@morketsmerke.net        xf0r3m
+</pre>
+                       <p>
+                       Plik zapisujemy, następnie tworzymy plik bazy:
+                       </p>
+<pre class="code-block">
+# postmap /etc/postfix/virtual
+</pre>
+                       <p>
+                       Restartujemy <em>Postfixa</em>.
+                       </p>
+<pre class="code-block">
+# postfix reload
+</pre>
+                       <p>
+                       Możemy przestować konfigurację. Jednak żeby to zrobić musimy włączyć <em>Dovecot</em>. Z tego co mi wiadomo nie uruchomi się,  
+                       ponieważ posiada jakieś predefiniowane ścieżki do certyfikatów SSL w pliku <em>/usr/pkg/etc/dovecot/conf.d/10-ssl.conf</em> należy
+                       je wyłączyć stawiając na początku linii znak komentarza. Zapisujemy zmiany, teraz <em>dovecot</em> powinnien się uruchomić.
+                       Podłączamy się za pomocą poniższe polecenie:
+                       </p>
+<pre class="code-block">
+$ openssl s_client -connect mail.example.com:465
+</pre>
+                       <p>
+                       Po podłączeniu musimy określić jakiego zestawu poleceń będziemy używać, do tego służy polecenie <code class="code-inline">EHLO</code>.
+                       Jako argument polecenie przyjmuje nazwę hosta, aby użyć jej nie tylko w logach ale również w nagłówku wiadomości, którą będziemy 
+                       wysyłać.
+                       </p>
+<pre class="code-block">
+EHLO shiny.morketsmerke.net
+</pre>
+                       <p>
+                       Następną rzeczą jest uwierzytelnie się. Do wyboru mamy albo metodę <em>PLAIN</em>, albo metodę <em>LOGIN</em>.
+                       <ul>
+                               <li><strong>PLAIN</strong> - Polega na podaniu zakodowanego za pomocą Base64 ciągu składającego się z nazwy użytkownika, 
+                                       hasła oraz dwóch znaków pomocniczych. Taki ciąg możemy wygenerować z pomocą <em>Perla</em>. 
+<pre class="code-block">
+$ perl -MMIME::Base64 -e 'print encode_base64("\0nazwa_uzytkownika\0haslo");'
+</pre>
+                               </li>
+                               <li><strong>LOGIN</strong> - Polega na podobnej zasadzie co <em>PLAIN</em>, jednak zakodowane dane podaje się po kolei. 
+                                       Najpierw nazwę użytkownika, poźniej hasło. Komunikaty serwera róznież będą zakodowane. 
+<pre class="code-block">
+334 VXNlcm5hbWU6 =&gt; 334 Username:
+$ perl -MMIME::Base64 -e 'print encode_base64("uzytkownik");'
+dXp5dGtvd25paw==
+334 UGFzc3dvcmQ6 =&gt; 334 Password:
+$ perl -MMIME::Base64 -e 'print encode_base64("haslo");'
+aGFzbG8=
+</pre>
+                               </li>
+
+
+                       </ul>
+                       Po zalogowaniu niezależnie od wybranej metody dostaniemy poniższym komunikat:
+                       </p>
+<pre class="code-block">
+235 2.7.0 Authentication successful
+</pre>
+                       <p>
+                       Teraz możemy wysłać maila do siebie lub do <em>roota</em>. Jeśli otrzymamy wiadomość, oznacza to że SMTPS działa poprawnie. Teraz 
+                       przejdziemy do <em>Dovecot-a</em>. Pierwszą rzeczą, którą się zajmiemy będzie uruchamianie <em>Dovecot</em> wraz ze
+                       startem. Możemy to zrobić na dwa sposoby, jednym z nich jest skopiowanie z <em>/usr/pkg/share/examples/rc.d/dovecot</em> 
+                       pliku <em>dovecot</em> do <em>/etc/rc.d</em> następnie dodanie wpisu w plik <em>/etc/rc.conf</em>:
+                       </p>
+<pre class="code-block">
+dovecot=YES
+</pre>
+                       <p>
+                       Drugim sposobem jest dodanie <em>Dovecot</em> do listy daemonów lokalnych, nie potrzeba do tego dużej filozofii a jedynie informacji
+                       zwracanej przez polecenie <code class="code-inline">which</code>
+                       </p>
+<pre class="code-block">
+$ which dovecot
+/usr/pkg/sbin/dovecot
+</pre>
+                       <p>
+                       Po uzyskaniu odpowiedzi, mogę stworzyć warunek w plik <em>/etc/rc.local</em>:
+                       </p>
+<pre class="code-block">
+if [ -x /usr/pkg/sbin/dovecot ]; then
+       echo -n ' dovecot ';
+       /usr/pkg/sbin/dovecot
+fi
+</pre>
+                       <p>
+                       Kiedy serwer zostanie uruchomiony ponownie, <em>Dovecot</em> sam wystartuje. Plik
+                       konfiguracjne nie znajdują się jakby się mogło wydawać w katalog <em>/etc</em>, tylko w <em>/usr/pkg/etc/dovecot/conf.d</em>.
+                       Zaczniemy od znanego nam już pliku, <em>10-ssl.conf</em>. Usuwamy znak komentarza przez linii uruchamiającej SSL
+                       </p>
+<pre class="code-block">
+ssl = yes
+</pre>
+                       <p>
+                       Potem ustawiamy pliki certyfikatu, jak na przykładzie poniżej:
+                       </p>
+<pre class="code-block">
+ssl_cert=&lt;/etc/openssl/fullchain1.pem
+ssl_key=&lt;/etc/openssl/privkey1.pem
+</pre>
+                       <p>
+                       <strong>Uwaga!</strong> Nawiasy ostre są częścią składni wartości opcji.
+                       </p>
+                       <p>
+                       Po zapisaniu zmian w pliku, możemy korzystać z zabezpieczonych wersji protokołów IMAP oraz POP3, które wykorzystują SSL. Włączenie 
+                       IMAPS oraz POP3S wymaga  odkomentowania opcji <code class="code-inline">port</code> oraz <code class="code-inline">ssl</code>, 
+                       wewnątrz deklaracji <code class="code-inline">inet_listener imaps</code> oraz <code class="code-inline">inet_listener pop3s</code>.
+                       </p>
+<pre class="code-block">
+...
+inet_listener imaps {
+       port = 993
+       ssl = yes
+}
+
+...
+inet_listener pop3s {
+       port = 995
+       ssl = yes
+}
+</pre>
+                       <p>
+                       Podobną rzecz zrobimy z <em>submission</em> dostarczanym wraz <em>Dovecot</em>, tylko zamiast włączać, wyłączymy nadając mu port 0.
+                       </p>
+<pre class="code-block">
+service submission-login {
+       inet_listner submission {
+               port = 0
+       }
+}
+</pre>
+                       <p>
+                       Ostatnią rzeczą jaką należy zrobić jest ustawienie lokalizacji skrzynek mailowych. W pliku 
+                       <em>/usr/pkg/etc/dovecot/conf.d/10-mail.conf</em> usuwamy znak komentarza z przed opcji <code class="code-inline">mail_location</code>
+                       oraz nadajemy jej następującą wartość.
+                       </p>
+<pre class="code-block">
+mail_location = mbox:~/mail:INBOX=/var/mail/%u
+</pre>
+                       <p>
+                       Zapisujemy zmiany i możemy restartować <em>Dovecot</em>.
+                       </p>
+<pre class="code-block">
+# dovecot reload
+</pre>
+                       <p>
+                       Jeśli program nie zwrócił błędów, sprawdżmy jeszcze plik <em>/var/log/maillog</em> czy wszystko działa. Ten plik to plik logów
+                       usług pocztowych, tam będzie widać kto się podłączył oraz informacje o przechodzących mailach. Teraz przetestujemy  
+                       sobie IMAPS tak samo jak SMTPS, niestety polecenia dla tych protokołów są różne. Zaczynamy klasycznie od wykorzystania 
+                       <em>openssl</em> żeby się podłączyć przy użyciu TLS.
+                       </p>
+<pre class="code-block">
+openssl s_client -connect mail.example.com:993
+</pre>
+                       <p>
+                       Pierwsze co musimy się zrobić to się uwierzytelnić. W IMAPS implementacji <em>Dovecot</em> uwierzytelniamy się za pomocą polecenia
+                       </p>
+<pre class="code-block">
+a login nazwa_uzytkownika haslo
+</pre>
+                       <p>
+                       IMAPS nie wymga żadnych zakodowanych ciągów jak ma to miejsce SMTPS. W odpowiedzi dostaniemy:
+                       </p>
+<pre class="code-block">
+a OK [ ... ] Logged in
+</pre>
+                       <p>
+                       Teraz możemy sprawdzić ustawienia skrzynki
+                       </p>
+<pre class="code-block">
+b select inbox
+</pre>
+                       <p>
+                       W odpowiedzi powinniśmy dostać coś takiego:
+                       </p>
+<pre class="code-block">
+b select inbox
+* FLAGS (\Answered \Flagged \Deleted \Seen \Draft Old)
+* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft Old \*)] Flags permitted.
+* 9 EXISTS
+* 0 RECENT
+* OK [UNSEEN 6] First unseen.
+* OK [UIDVALIDITY 1262394945] UIDs valid
+* OK [UIDNEXT 11] Predicted next UID
+b OK [READ-WRITE] Select completed (0.008 + 0.000 + 0.008 secs)
+</pre>
+                       <p>
+                       Pod adresem <a href="https://wiki2.dovecot.org/TestInstallation">https://wiki2.dovecot.org/TestInstallation</a> znajduje się 
+                       obszerny artykuł na temat jak sprawdzić czy konfiguracja <em>Dovecot</em> rzeczywiście działa. Kiedy jesteśmy zalogowani możemy
+                       teraz pobrać wiadomości za pomocą poniższych poleceń.
+                       </p>
+<pre class="code-block">
+b select inbox
+b fetch 1:* (flags internaldate body.peek[header.fields (subject)])
+b fetch 1 body[text]
+</pre>
+                       <p>
+                       Znaki "<strong>b</strong>", to tagi poleceń IMAP, każde polecenie musi zaczynać się od tagu, a tagiem może być dowolny ciąg znaków.
+                       </p>
+                       <p>
+                       Piersze polecenie można powiedzieć że sprawdza skrzynkę, wyświetla podsumowanie liczbowe ile jest wiadomości w skrzynce. Drugie
+                       wyświeli nam listę wiadomości z flagami, datą oraz tematem, a ostatnie wyświetli zawartość pierwszej wiadomości. Jeśli wszystkie
+                       trzy polecenia powiodły się oznacza to że usługi mailowe, które konfigurowaliśmy działają poprawnie.
+                       </p>
+                       <p>
+                       Cięzko jest korzystać z poczty
+                       łącząc się bezpośredrednio z usługami, przy takich serwerach gdzie niema portalu WWW można zastosować klienty czy programy pocztowe
+                       jak np. <em>Mozilla Thunderbird</em>.
+                       </p>
+                       <p>
+                       Poniżej przedstawie jak skonfigurować <em>Thunderbirda</em> oraz <em>MUTTa</em>, można było w swobodny sposób korzystać z
+                       konfigurowanych przez nas usług pocztowych.
+                       </p>
+                       <p>
+                       <u>Thunderbird:</u>
+                       </p>
+                       <p>
+                       Jeśli do tej pory działaliśym w sieci lokalnej i z usługami łączyliśmy za pomocą adresu IP, to z racji użycia certyfikatów, a 
+                       <em>Thunderbird</em> kontroluje pole <em>CN</em> (<em>Common Name</em>), to jeśli adres serwera nie będzie zgadzał się z tym
+                       co jest w tym polu, to program zrzuci ostrzeżenie, odnośnie niezgodności z certyfikatem. Warto zainwestować chwilę czasu na
+                       budowę np. <em>Pi-Hole</em>. Prócz ogólnosieciowej blokady reklam zyskujemy jeszcze lokalnego DNS, a zasadzie <em>dnsmasq</em>
+                       oraz pliku <em>/etc/hosts</em>. 
+                       </p>
+                       <p>
+                       Konfigurację <em>Thunderbirda</em> rozpoczynamy od utworzenia nowego konta. W pole imię i nazwisko możemy wpisać swoje dane
+                       lub nazwę użytkownika, w adresie e-mail podajemy adres e-mail naszego konta. Hasło również możemy zapisać, chyba że nie chcemy.
+                       Po zatwierdzeniu tych informacji, przechodzimy do ustawień ręcznych. Dane konfiguracyjne dla serwera SMTP:
+                       </p>
+                       <ul>
+                               <li><strong>Nazwa serwera:</strong> mail.example.com</li>
+                               <li><strong>Port:</strong> 465</li>
+                               <li><strong>Bezpieczeństwo połączenia:</strong> SSL/TLS</li>
+                               <li><strong>Metoda uwierzytelniania:</strong> Normalne hasło</li>
+                               <li><strong>Użytkownik:</strong> user</li>
+                       </ul>
+                       <p>
+                       Dane konfiguracjne dla serwera IMAP:
+                       </p>
+                       <ul>
+                               <li><strong>Nazwa serwera:</strong> mail.example.com</li>
+                               <li><strong>Port:</strong> 993</li>
+                               <li><strong>Użytkownik:</strong> user</li>
+                               <li><strong>Bezpieczeństwo połączenia:</strong> SSL/TLS</li>
+                               <li><strong>Metoda uwierzytelnienia:</strong> Normalne hasło</li>
+                       </ul>
+                       <p>
+                       <u>MUTT</u>
+                       </p>
+                       <p>
+                       Nie wiem czy <em>MUTT</em> zrzuci komunikat o niezgodności adresu serwera z polem <em>CN</em>. Jednak jeśli będziemy mieli w planach
+                       wykorzystanie SSL, nie tylko w usługach pocztowych to warto się zaopatrzyć w lokalny DNS, aby uniknąć tych niepotrzebnych
+                       komunikatów. Kolejną rzeczą jest obsługa SASL przez <em>MUTT</em>, obsługa musi być dodana podczas kompilacji, w przypadku OpenBSD 
+                       istnieje odrębna wersja programu wraz z wsparciem dla SASL. Poniżej przedstawię plik konfiguracyjny umożliwiający użycie tego 
+                       programu jako klienta poczty dla konfigurowanych przez nas usług.
+                       </p>
+<pre class="code-block">
+set ssl_starttls=yes
+set ssl_force_tls=yes
+
+set imap_user='user'
+set imap_pass='passw0rd'
+set from='user@example.com'
+
+set realname='John Doe'
+set folder=imaps://mail.example.com/
+set spoolfile=imaps://mail.example.com/INBOX
+
+set header_cache="~/.mutt/cache/headers"
+set message_cachedir="~/.mutt/cache/bodies"
+set certificate_file="~/.mutt/certificates"
+
+set smtp_url="smtps://user@mail.example.com"
+set smtp_pass="passw0rd"
+set move = no
+set imap_keepalive = 300
+bind index G imap-fetch-mail
+</pre>
+                       <p>
+                       Opis co jest od czego, znajduje się w <a href="https://morketsmerke.github.io/articles/faq/index.html">
+                               https://morketsmerke.net/site/articles/faq/index.html</a>
+                       Jedyną opcją, która tam nie występuje jest ostatnia linia. Powoduje przypisanie G (duże G = <em>shift + g</em>) do polecenia 
+                       <code class="code-inline">imap-fetch-mail</code>, czyli odświeżania skrzynki pod klawiszem G (<em>shift + g</em>) 
+                       </p>
+                       <p>
+                       Ostatnia rzecz, która pozostała to  udostępnienie usług pocztowych w Internecie, potrzebny będzie usługodawca, który nie blokuje 
+                       portu SMTP <em>TCP/25</em>. Domena dzięki której będziemy mogi zdefiniować rekord <em>MX</em>. Rekord <em>MX</em> definiujemy w ten 
+                       sposób że na początku tworzymy klasyczny rekord <em>A</em>, który wskazuje na adres serwera, następnie tworzę rekord <em>MX</em> o 
+                       nazwie domeny wskazujący na nazwę rekordu <em>A</em> serwera. Ja swój serwer umieściłem w strefie DMZ z BINAT, oczywiście wymaga to 
+                       port forwardingu, jednak BINAT nie zmienia portów. Warto pamiętać o tym by port <em>TCP/25</em> był otwarty. Nie służy on klientom a 
+                       przesyłaniu maili do innych domen oraz otrzymwaniu wiadomości od innych serwerów. Jeśli ten port będzie zablokowany nie otrzymamy
+                       żadnej wiadomości.
+                       </p>
+                       <p>
+                       Na słowo zakończenia dodam jak wygląda reputacja takich usług mailowych? Otóż niezbyt dobrze. Wysłanie na maila GMAIL spowoduje
+                       umieszczenie takiej wiadomości w spamie. Inaczej ma to się przy wysyłaniu informacji do organizacji, którą posiada swoje
+                       maile na Googlu, tam mail trafił normalnie do skrzynki odbiorczej. Protomail identycznie, mail trafił do spamu. Jeśli komuś na tym
+                       zależy to może się pobawić w podniesienie reputacji. Załącznik w mailach działają bez żadnej dodatkowej konfiguracji. Odnośnie tego
+                       spamu, to jeśli my odpowiemy na maila, to wtenczas mail pojawi się klasycznie w wątku pod tym tematem. Jestem ciekaw jak ten 
+                       serwer długo pociągnie, online jest od 27.04.2021.
+                       </p>
+                       <p>
+                       ~xf0r3m
+                       </p>
+
+               </div>
+
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
+
+
diff --git a/articles/bsd/OpenBSD_jako_bramka_sieciowa.html b/articles/bsd/OpenBSD_jako_bramka_sieciowa.html
new file mode 100755 (executable)
index 0000000..d1fa3da
--- /dev/null
@@ -0,0 +1,201 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+<div class="main">
+<h1 class="title">OpenBSD jako bramka sieciowa</h1>
+<p>
+<strong>OpenBSD</strong> jest wersją systemu BSD, w której nacisk położono na silniejsze zabezpiecznia przez co świetnie sprawdza się jako system dla programowalnych urządzeń sieciowych. Jednak zdarzają się tacy hakerzy, którzy stosują go do codziennej pracy jako system ogólnego zastosowania. W Internetach można znależć wiele skonfigurowanych przez ludzi pulpitów oraz stricte poradników aby ten system mógł chociaż spróbować stać się systemem codziennego użytku, poki co my przy odrobinie chęci możemy zrobić z niego porządną bramę sieciową, z której sam korzystam w kilku sieciach. Warto dodać że ten system ma niewielkie wymagania systemowe patrząc na współczesny sprzęt. Dla architektury 32-bitowej 32 MB pamięci RAM oraz 600 MB wolnej przestrzeni na dysku to naprawdę nie wiele. Dla prawdziwego hakera wystarczył by komputer ze śmietnika, lub terminal z popularnego serwisu aukcyjnego za 20 zł.
+</p>
+<p>
+<strong>UWAGA! Wszystkie przedstawiowne tutaj polecenia są uruchamiane z poziomu użytkownika <em>root</em>.</strong>
+</p>
+<ol>
+<li>Instalacja systemu.<br />
+<p>
+Instalacja systemu OpenBSD została przedstawiona <a href="instalacja_OpenBSD.html">tutaj</a>. Jedyne co w tym wypadku możemy zmienić to ustawić intefejs podłączony do Internetu (w zależności od konfiguracji naszego ISP, warto pamiętać w jaki sposób został przydzielony nam adres IP. Będzie nam to potem potrzebne w regułach zapory dotyczących NAT-u) oraz interfejs sieci LAN, ze stałym adresem IP, będącym pierwszym adresem z puli (tak się przyjęło, chociaż ludzi na kursach CISCO uczono inaczej, że adresem bramy w sieci LAN pownien być ostatni adres z puli). W przypadku interfejsu podłączonego do Internetu ze stałym adresem, o adresy bramy, domenę oraz adresy DNS zostaniemy zapytani dopiero po zdefiniowaniu interfejsów sieci LAN. Co pokazano poniżej.
+</p>
+<pre class="code-block">
+#Interfejs WAN (podłączony do internetu)
+IPv4 address for em0 ? (or 'dhcp' or 'none') [dhcp] 157.190.112.10
+Netmask for em0 [255.255.255.0]
+</pre>
+<pre class="code-block">
+#Interfejs LAN
+IPv4 address for em1 ? (or 'dhcp' or 'none') [none] 192.168.0.1
+Netmask for em0 [255.255.255.0]
+</pre>
+<pre class="code-block">
+Default IPv4 route ? (IPv4 address or none) [none] 157.190.112.1
+DNS domain name (e.g. 'example.com') [my.domain] morketsmerke.net
+DNS nameservers? (IP address list or none) 157.190.112.1
+</pre>
+<p>
+Definiując interfejs WAN należy wpisać dane, które umożliwią nam połączenie z Internetem. Musimy mieć połączenie na naszej maszynie, aby zainstalować pakiet <em>dnsmasq</em>, który będzie niezbędny do obsługi DNS. Chyba że zrobimy z telefonu router i podłączymy go kablem USB, w OpenBSD działa to bez zarzutów.
+</p>
+</li>
+<li>Instalacja dnsmasq.<br />
+<p>
+Do osiągnięcia naszego celu, musimy zainstalować jeden program ponieważ reszta znajduje się już w systemie. Aby pobrać oprogramowanie z oficjalnego repozytorium wydajmy następujące polecenie:
+</p>
+<pre class="code-block">
+# pkg_add -a dnsmasq
+</pre>
+<p>
+Po zainstalowaniu daemona warto ustawić jego uruchamianie podczas startu systemu.
+</p>
+<pre class="code-block">
+# rcctl enable dnsmasq
+</pre>
+</li>
+<li>Konfiguracja DHCP<br />
+<p>
+W OpenBSD daemon DHCP jest preinstalowany a jego plik jest umieszczony bezpośrednio w katalogu <em>/etc</em>. Dla małej sieci nie potrzebujemy zbyt wielu opcji. Wystarczą te najbardziej podstawowe. Poniżej przedstawiono najprostszą do prawidłowego funkcjonowania sieci konfigurację DHCP. Otwieramy plik <em>/etc/dhcpd.conf</em>.
+</p>
+<pre class="code-block">
+subnet 192.168.0.0 netmask 255.255.255.0 {
+       range 192.168.0.100 192.168.0.200;
+       option routers 192.168.0.1;
+       option domain-name "morketsmerke.net";
+       option domain-name-servers 192.168.0.1;
+}
+</pre>
+<p>
+Jeśli nasza brama obsługuje więcej niż jedną sieć LAN, to powtarzamy deklaracje dla kolejnych podsieci.
+</p>
+</li>
+<li>Ustawienia interfejsów dla <em>dhcpd</em><br />
+<p>
+Do poprawnej pracy naszego serwera DHCP pozostaje jeszcze wskazać odpowiedenie interfejsy dla wpisanych w pliku konfiguracyjnym podsieci. Interfejsy wpisuje się w opcjach uruchomieniowych daemona w pliku <em>/etc/rc.conf.local</em>, te opcje odczytywane są podczas uruchamiania usług zaraz przed umożliwieniem użytkownikowi zalogowania do systemu. Wpis dla <em>dhcpd</em> ma następujący wzór:
+</p>
+<pre class="code-block">
+dhcpd_flags="interfejs1 interfejs2 ... interfejsN"
+</pre>
+<p>
+Warto dodać że przekaznie opcji uruchomieniowych (flag) do daemona jest równoznaczne z jego uruchomienie podczas startu, więc nie trzeba wydawać polecenia <code class="code-inline">rcctl enable dhcpd</code>.
+</p>
+</li>
+<li>Ustawienie interfejsu dla dnsmasq<br />
+<p>
+Jeśli ktoś ustawiał już <em>dnsmasq</em> na GNU/Linux to robi się to tutaj w ten sam sposób. W pliku konfiguracyjnym <em>/etc/dnsmasq.conf</em>, odnajdujemy opcję <code class="code-inline">#interface=</code>, usuwamy znajdujący się na początku znak komentarza i po znaku równości (<strong>=</strong>) podajemy nasz interfejs sieciowy, tak samo jak w przypadku wielu sieci LAN, kopiujemy opcje wraz z ustawionym kolejnym interfejsem.
+</p>
+<p>
+Teraz możemy użyć polecenia <code class="code-inline">netstat -ln | grep -e '^tcp' -e '^udp'</code> aby wyświetlić wszystkie otwarte porty TCP i UDP. Z wyników tego polecenia dowiemy się że dnsmasq nasłuchuje na wszystkich interfejsach a nie tylko na wskazanym, zostało to utworzone dla wygody w przypadku zmiany interfejsów lub ich adresów (w zależności od konfiguracji) nie trzeba zmieniać ustawień w pliku, a daemon nie odpowie na żądania, na które nie powinien. Jeśli jednak chcemy wymusić wyłączenie wyżej wspomnianej właściwości i respektowanie opcji <code class="code-inline">interface</code> to należy odblokować opecję <code class="code-inline">bind-interfaces</code>.
+</p>
+</li>
+<li>Ewnetualne wpisy w <em>/etc/hosts</em>*<br />
+<p>
+Za pomocą pliku <em>/etc/hosts</em>, możemy umieszczać nazwy domenowe na bramie dzięki temu uzyskamy odzworowanie nazw w naszej sieci lokalnej bez konfigurowania skomplikowanych systemów DNS takich jak <em>BIND9</em>. Oczywiście nie było by to możliwe bez dnsmasq. Wzór wpisu do plku <em>/etc/hosts</em> znajduje się poniżej.
+</p>
+<pre class="code-block">
+&lt;IP&gt;     &lt;FQDN&gt;    &lt;HOSTNAME&gt;
+</pre>
+<p>
+Dla przykładu wstawię tutaj jeden ze wpisów.
+</p>
+<pre class="code-block">
+192.168.0.2    serwer.morketsmerke.net serwer
+</pre>
+</li>
+<li>Firewall oraz NAT<br />
+<p>
+Do prawidłowego funkcjonowania naszej bramy potrzebny jest system <strong>NAT</strong> (Network Address Translation). Funkcje NAT-u w UNIX-ach przeważnie są realizowane przez oprogramowanie Firewall-a. Zapory sieciowe (firewall-e) są konfigurowane za pomocą reguł, a do działania NAT-u, czy to w przypadku systemów *BSD, gdzie zapora realizowana jest za pomocą pakietu <strong>PF</strong> (Packet Filter) czy za pomocą pakietu <em>iptables</em> używanego na systemach GNU/Linux wystarczy jedna reguła.
+</p>
+<pre class="code-block">
+pass out on &lt;interfejs podłączony do Internetu&gt; from &lt;interfejs LAN z sufiksem :network&gt; to any nat-to
+(&lt;publiczny adres IP / intefejs podłaczony do Internetu&gt;)
+</pre>
+<p>
+Taka konfiguracja jest wystarczająca, jednak warto pamiętać o tym że prawdopodobnie mamy włączone SSH, które nasłuchuje na wszystkich portach, więc aby nie dać możliwości ataków odgadywania hasła przez boty, warto albo ustawić adres, na którym ma nasłuchiwać w konfiguracji SSH lub użyć polityki zarządzania ruchem sieciowym polegającej na odcięciu całego ruchu sieciowego od firewalla a następnie dopuszczenia tylko tego najważniejszego dla zastosowań biurowo-domowych wystarczy odciąć cały ruch i jawnie go zadeklarować za pomocą odpowienich reguł.
+Tutaj warto opisać jak działa PF. PF jak każdy inny daemon czyta swoją konfiguracje z pliku <em>/etc/pf.conf</em>, to właśnie w nim są przechowane reguły. Dostosowuje je do swojego wewnętrznego formatu, aby optymalnie przypasowywać pakiety do istniejących reguł na tej zasadzie właśnie działają zapory sieciowe, a cechą charkterystyczną PF jest zasada "ostatni wygrywa", czyli jeśli pakiet pasuje do wielu reguł to akcja (<code class="code-inline">pass</code> lub <code class="code-inline">block</code>) ostatniej pasującej do pakietu reguły zostanie na nim zastosowana. Wracając do naszego pliku, otwieramy go do edycji, najlepiej usunąć to co tam jest poza jakimiś początkowymi komentarzami jeśli istnieją oczywiście. Na samym początku zdefiniujemy sobie kilka zmiennych, tak w regułach PF można definiować zmienne.
+</p>
+<pre class="code-block">
+red="Interfejs podłączony do internetu";
+green="Interfejs sieci LAN";
+greennet="Interfejs sieci LAN:network";
+</pre>
+<p>
+Skąd te nazwy zmiennych, otóż kiedyś korzystała z nich dystrybucja <strong>IPCop</strong> - GNU/Linuxowa dystrybucja przeznaczona właśnie na bramki. Kolory oznaczały interfejsy przypisane do konkretnych rodzajów sieci:
+</p>
+<ul>
+<li>czerwony - sieć Internet/sieć rozległa WAN - brak zaufania dla danych pochodzących z tej sieci</li>
+<li>zielony - sieć LAN - sieć niefiltrowana przez ten firewall (komputery z tej sieci miały dostęp do wyszystkich pozostałych sieci), sieć największego zaufania.</li>
+<li>niebieski - sieć mniejszego zaufania niż w sieci LAN, sieć niebieska nie mogła się komunikować z siecią zieloną, stosowana dla wydzielenia odrębnej sieci LAN dla sieci bezprzewodowej</li>
+<li>pomarańczowy - sieć ograniczonego zaufania - DMZ, komputery z tej sieci nie mogły łączyć się z żadną z powyższych sieci poza czerwoną, ale sieci niebieska oraz zielona bez przeszkód mogły łączyć się hostami sieci pomarańczowej.</li>
+</ul>
+<p>
+Jest to dla mnie dość zrozumiała wizja konfiguracji sieci, dlatego też korzystam z niej po dziś dzień. W skrócie <code class="code-inline">red</code> oznacza Internet, <code class="code-inline">green</code> sieć LAN, <code class="code-inline">greennet</code> służy głównie wygodniejszemu zapisowi interfejsu LAN z przyrostkiem (sufiksem) <code class="code-inline">:network</code> (<code class="code-inline">em1:network</code>). Pod naszymi zmiennymi zapisujemy pierwszą regułę.
+</p>
+<pre class="code-block">
+block all
+</pre>
+<p>
+To prosta a zarazem bardzo skuteczna reguła, powoduje blokadę wszystkich pakietów, odcina bramkę od jakiejkolwiek sieci nawet LAN. I teraz możemy zatrzymać się na chwilę i pomyśleć, czyli co? Teraz będę musiał dla każdego połączenia definiować oddzielną regułę oraz regułę zezwalającą na otrzymanie odpowiedzi od odległego serwera? Otóż nie, tu jest właśnie duża różnica pomiędzy PF a iptables. Przy użyciu tych samych polityk w PF nie trzeba dopuszczać oddzielną regułą odpowiedzi z serwera, wystarczy reguła, która pozwoli hostom z sieci LAN na rozpoczęcie polączenia. W PF jest realizowane automatycznie po przypasowaniu pakietu rozpoczynającego połączenie. Tworzony jest tak jakby tunel, który pozwoli na swobodny przepływ odpowiedzi na przypasowane pakiety wychodzące. Poniżej znajdują się reguły, które spowodują już dopuszczenie ruchu do i z bramki.
+</p>
+<pre class="code-block">
+pass in on $green from $greennet to any
+</pre>
+<p>
+Ta reguła powoduje dopuszczenie ruchu wejściowego na intefejsie sieci LAN do dowolnego hosta, między innymi również do bramki.
+</p>
+<pre class="code-block">
+pass out on $red from $red to any
+</pre>
+<p>
+Z racji tego że wszystko było odcięte przez <code class="code-inline">block all</code> daliśmy możliwość komunikacja bramki z siecią LAN, chcąc niechcąc adres interfejsu sieci LAN również znajduje się wewnątrz tej sieci. Aby bramka mogła połączyć się z Internetem musimy wypuścić ruch wychodzący z interfejsu WAN do dowolnego hosta. Teraz pozostało nam dopisać ostatnią odpowiedzialną za NAT regułę.
+</p>
+<pre class="code-block">
+pass out on $red from $greennet to any nat-to ($red)
+</pre>
+<p>
+Ta reguła mówi nam aby wypuścić ruch na interfejsie <code class="code-inline">red</code> z sieci lokalnej (<code class="code-inline">greennet</code>) gdziekolwiek z ustawieniem <em>NAT</em>-u do adresu interfejsu podłączonego do Internetu. Ujęcie w nawias zmiennej <code class="code-inline">red</code>, mówi <em>PF</em>, aby stale monitorował interfejs pod kątem zmian adresu, aby nie trzeba było wczytywać ponownie reguł <em>PF</em>, przy każdej jego zmianie .
+</p>
+<p>
+Do wczytania reguł <em>PF</em> służy polecenie <code class="code-inline">pfctl</code>, które wydajemy z opcją <code class="code-inline">-f</code>, po którym wskazujemy plik z regułami. Jednak przed wczytaniem reguł warto wydać polecenie <code class="code-inline">pfctl</code> wraz z przełącznikami <code class="code-inline">-nf</code> spowoduje to sprawdzenie pliku reguł pod kątem błędów bez wczytywania go. Warto o tym pamiętać kiedy dokonujemy zmian w pliku reguł, a jeden błąd uziemia PF i firewall w ogóle się nie uruchamia i nagle w firmie zaczyna brakować dostepu do Internetu...
+</p>
+</li>
+<li>Przekazywanie pakietów<br />
+<p>
+Na UNIX-ach aby była możliwość przesłania pakietów z jednego łącza (interfejsu) na drugie należy umożliwić to z poziomu jądra systemu po przez zmianę jednej z jego opcji. Przekazywanie pakietów jest uruchamiane za pomocą polecenia <code class="code-inline">sysctl</code>, wraz z opcją <code class="code-inline">net.inet.ip.forwarding</code> ustawioną na 1.
+</p>
+<pre class="code-block">
+# sysctl net.inet.ip.forwarding=1
+</pre>
+<p>
+Opcje zmieniane za pomocą polecenia <code class="code-inline">sysctl</code> w trakcie działania systemu działają tak długo jak system jest uruchomiony, oznacza to że po ponownym uruchomieniu opcja powróci do swojej pierwotnej wartości. Więc teraz musimy coś zrobić aby nie trzeba było logować sie do bramki i uruchamiać z "ręki" przekazywania pakietów. Rozwiązanie tego problemu jest bardzo proste, wystarczy dopisać opcje <code class="code-inline">net.inet.ip_forwarding</code> z wartością 1 do pliku <em>/etc/sysctl.conf</em>.
+</p>
+<pre class="code-block">
+# echo 'net.inet.ip.forwarding=1' &gt;&gt; /etc/sysctl.conf
+</pre>
+</li>
+</ol>
+<p>
+Jak pokazano wyżej za pomocą kilku prostych poleceń, wyedytowaniu kilku plików można przerobić ten jakże obcy dla wielu system, na naprawdę coś użytecznego. Warto dodać że ja najpierw nauczyłem się tworzyć bramki na OpenBSD, a dopiero później na GNU/Linux. Jeśli posiadamy naprawdę dużą wiedzę na temat systemu GNU/Linux to niestety przyda się ona w kilku/kilkunastu przypadkach. Systemom rodziny BSD, bliżej do macOS X i dziedzictwa UNIX-a niż do GNU/Linux. Nie są one skomplikowane, wręcz przeciwnie, ale brak elementarnej wiedzy powoduje że ten system może być dla nas abstrakcją. Tutaj jedną z niezrozumiałych rzeczy może być PF, zapraszam do dokumentacji PF na stronie projektu OpenBSD, która jest dostępna w postaci podręcznika <a href="https://www.openbsd.org/faq/pf/index.html">https://www.openbsd.org/faq/pf/index.html</a>. Może również pojawi się i tutaj w mojej streszczonej sprawdzonej wersji polskiej. Zabawy z PF.
+<p>
+<p>
+~xf0r3m
+</p>
+</div>
+<p class="footer">
+2021; COPYLEFT; ALL RIGHTS REVERSED
+</p>
+</body>
+</html>
diff --git a/articles/bsd/dziennik_OpenBSD.html b/articles/bsd/dziennik_OpenBSD.html
new file mode 100755 (executable)
index 0000000..52177bf
--- /dev/null
@@ -0,0 +1,805 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <h1 class="title">Dziennik OpenBSD</h1>
+                       <p>
+                               <strong>Dzień 1 - Instalacja, fluxbox, dwa monitory, dźwięk, youtube-dl i usmb</strong> - <em>2021-04-08</em><br />
+                               <br />
+                               <p>
+                               Do wykorzystania z OpenBSD wybrałem maszynę na której zainstalowełem oraz uruchomiłem system bez zarzutu. Czytając ostatni
+                               akapit materiału o instalacji OpenBSD można dojść do wniosku, iż nie zawsze jest to takie banalne jakby się mogło wydawać. Ta
+                               maszyna to składak z płytą ITX Sapphire PURE White IPC-E350M1W z procesorem AMD E-350, zintegrowaną grafiką Radeon HD 6310 i
+                               małym dyskiem SSD Intela jeszcze na SATA II, Do PC-eta podłączyłem dwa monitory, tak jakoś mi się wygodniej pracuje na dwóch.
+                               Po uruchomieniu systemu (podczas instalacji pozostawiłem włączone <strong>xenodm</strong>, więc system od razu uruchomił 
+                               środowisko graficzne) byłem przekonany, że obraz będzie na obu i to w rozszerzeniu. Już kiedyś uruchamiałem OpenBSD na
+                               laptopie z podłączonym dodatkowym monitorem, co ciekawe serwer <strong>x.org</strong> skonfigurował ten monitor jako
+                               podstawowy. Nie zwracając uwagi na domyślne ustawienia skonfigurowałem polecenie <strong>doas</strong>, które jest 
+                               odpowiednikiem 
+                               linuxowego polecenia <em>sudo</em>. Poźniej zainstalowałem  <em>Firefox-a</em>, następnie wrzuciłem w 
+                               wyszukiwarkę "How to install fluxbox on OpenBSD" przeszedłem na główną stronę projektu, oczywiście już nauczony 
+                               wcześniejszymi instalacjami OpenBSD na laptopach, że <strong>fluxbox</strong> jest dostępny w repozytorium, nie pamiętałem 
+                               jednak co należy zrobić aby <em>fluxbox</em> uruchamiał się po zalogowaniu, wykonałem więc czynności opisane na strone projektu 
+                               (jaki błąd!). Po zrestartowaniu nie zadziałało po zalogowaniu uruchomił się <em>FWVM</em>, <em>fluxbox</em> uruchomiał się 
+                               tylko na wyłączonym <em>xenodm</em> i uruchomianiu <em>X</em> z ręki przy użyciu polecnia <em>startx</em>. 
+                               Wróciłem do przeglądarki. Na stronie wyników
+                               wyszukiwania znalazłem podobnie brzmiący problem do mojego... Na <em>StackOverflow</em>, radzili użyć pliku 
+                               <em>~/.xsession</em> a nie <em>~/.xinitrc</em>, tak też zrobiłem i zadziałało. Następną rzeczą jak postanowiłem zrobić to
+                               zająć się ekranami, aby były identycznie ustawione jak monitory na biurku, wykorzystałem do tego te dwa poniższe polecenia,
+                               które są wykonywane przed uruchomieniem <em>fluxboxa</em> w pliku <em>.xsession</em>.
+                               </p>
+<pre class="code-block">
+xrandr --output DVI-0 --primary
+xrandr --output HDMI-0 --right-of DVI-0
+</pre>
+                               <p>
+                               Polecenie <code class="code-inline">xrandr</code> służy właśnie do sterowania ekranami środowiskach graficznych opartych 
+                               o <em>X</em>. Ustawienie monitora podłączonego przez DVI jako podstawowy (stoi po mojej lewej) jest zrozumiałe, ale do czego
+                               służy drugie polecenie? Kiedy przestawiłem monitor, okazało się (już wcześniej kiedy instalowałem <em>fluxbox</em>), że jeśli
+                               chcemy przenieść kursor na drugi monitor musimy zrobić to przez jego lewą krawedź co jest nienaturalne, bo monitor stoi po 
+                               prawej stronie ekranu podstawowego. Polecenie przestawia ekran <code class="code-inline">HDMI-0</code> na prawo od ekranu
+                               <code class="code-inline">DVI-0</code> Kiedy monitory ogarnięte, to pora na doinstalowanie dodatkowego oprogramownia. 
+                               Ja głównie
+                               wykorzystuje terminal (<em>xterm</em> jako emulator), z pomocą <em>tmux</em> dziele go na trzy części jedna podstawowa z
+                               <em>vim</em> oraz dwie mniejsze z odtwarzaczem <em>moc</em> oraz z wierszem polecenia, za pomocą którego np. obsługuje
+                               repozytorium git. Jako managera plików wykorzystuje <em>mc</em>, może czasami być potrzeba aby otworzyć jakiś plik wideo, więc
+                               <em>vlc</em>, generalnie chyba nie ma lepszego odtwarzacza od VLC ostatnim programem jest chyba <em>gkrellm</em> uruchamiany 
+                               w dolnym prawym rogu dodatkowego ekranu.
+                               </p>
+<pre class="code-block">
+$ doas pkg_add -iv mc vim moc vlc gkrellm
+</pre>
+                               <p>
+                               Kolejnym ciekawym epizodem, było sprawdzenie dźwięku (spoiler! Działa out-of-box, wystarczy zrobić głośniej). Żeby zrobić to
+                               w miarę szybko stwierdziłem że wejdę na YT, i oh, boy! Ten komputer raczej do YT się nie nadaje, jako alternatywę wymyśliłem
+                               że mogę użyć <em>smtube</em> i okazało się że w repozytorium jest zarówno <em>smtube</em> jak i <em>youtube-dl</em>. 
+                               <em>Smtube</em> oczywiście nie działa, ale ja mam dla niego inne zastosowanie, skoro jest w stanie wyszukiwać rzeczy to można
+                               użyć go jako wyszukiwarki bez używania <em>firefox-a</em>, potem możemy sobie to ściągnąć przy użyciu <em>youtube-dl</em>.
+                               Oczywiście nie namawiam do piractwa.
+                               </p>
+
+<pre class="code-block">
+$ doas pkg_add -iv smtube youtube-dl
+</pre>
+                               <p>
+                               Podgłaszanie z poziomu terminala (1 = 100%)
+                               </p>
+<pre class="code-block">
+$ sndioctl output.level=1
+</pre>
+                               <p>
+                               Przypomniałem sobie że mam dużo muzyki (aż 19 dni) na moim lokalnym NAS-ie. Z NAS-em możemy połączyć się zapomocą SMB, tylko
+                               jako to zrealizować w OpenBSD, na GNU/Linux wystarczy jedno polecenie, tutaj sprawa się komplikuje ponieważ nie ma
+                               oficjalnego wsparcia dla CIFS/SMB, możemy zrobić dwa sposoby <s>taki że wylewu można dostać</s> hakerski lub wygodny. Ja
+                               użyłem, wiadomo tego pierwszego i w pewnym momencie myślałem że zjem klawiaturę. Hakerski sposób wymaga pakietu 
+                               <strong>usmb</strong>, oraz utworzenia specjalnej konfiguracji w pliku <em>~/.usmb.conf</em>:
+                               </p>
+
+<pre class="code-block">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;usmbconfig&gt;
+
+       &lt;credentials id="nas"&gt;
+               &lt;domain&gt;WORKGROUP&lt;/domain&gt;
+               &lt;username&gt;admin&lt;/username&gt;
+               &lt;password&gt;P4ssW0rD&lt;/password&gt;
+       &lt;/credentials&gt;
+
+       &lt;mount id="nas" credentials="nas"&gt;
+               &lt;server&gt;nas.morketsmerke.net&lt;/server&gt;
+               &lt;share&gt;nas&lt;/share&gt;
+               &lt;mountpoint&gt;/home/xf0r3m/NAS&lt;/mountpoint&gt;
+               &lt;options&gt;allow_other,uid=1000,gid=1000&lt;/options&gt;
+       &lt;/mount&gt;
+
+&lt;/usmbconfig&gt;
+</pre>
+                               <p>
+                               Po zapisniu konfiguracji w pliku musimy nadać mu odpowiednie uprawnienia, bo inaczej skrypt <s>się spruje</s> że, zwróci uwagę
+                               nie są poprawne uprawnienia dla pliku konfiguracyjnego i zakończy działanie. Z racji tego że musimy uruchomić 
+                               <em>usmb</em> jako <em>root</em>, to prawa własności musimy ustawić na poniższe:
+                               </p>
+<pre class="code-block">
+$ doas chown root:wheel ~/.usmb.conf
+</pre>
+                               <p>
+                               To nie wszystko jeśli uprawnienia są za wysokie to skrypt znów <s>się spruje</s> nam zwróci uwagę na to że uprawnienia są
+                               za wysokie i odmówi wykonania zadania. Prawidłowe uprawnienia ustawimy za pomocą poniższego polecenia:
+                               </p>
+<pre class="code-block">
+$ doas chmod 600 ~/.usmb.conf
+</pre>
+                               <p>
+                               Kiedy już się uporamy z plikiem konfiguracyjnym, możemy wydać poniższe polecenie aby w końcu zamontować nasz udział w 
+                               systemie:
+                               </p>
+<pre class="code-block">
+$ doas usmb -c ~/.usmb.conf nas
+</pre>
+                               <p>
+                               Powiem tak... Montowanie udziału spełnia swoje podstawowe założenia pozwala na główne operacje na plikach. Jednak jak 
+                               chcielibyśmy odtworzyć muzykę w <em>moc</em> bezpośrednio z serwera to się nie da, ponieważ wczytywanie plików odbywa
+                               się bardzo wolno, na debug logu widać jak program się zapętla. Spróbuje jeszcze na innych odtwarzaczach, może to winna
+                               <em>moc</em>, ale póki co to duży minus.
+                               </p>
+                       </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Dzień 2 - Obsługa dysków, "Wykorzystanie systemu OpenBSD do codziennej pracy".</strong> - <em>2021-04-09</em><br />
+                               <br />
+                               <p>
+                               Generalnie to chciałem zrobić dzisiaj porządek na dysku, podłączę sobie dysk i zagram wszystko co potrzebne na NAS-a.
+                               Potem go przeformatuje. Jednak nie mogę ponieważ OpenBSD nie obsługuje systemu EXT4, generalnie kolejny minus. Jak się ich
+                               zbierze dużo to można grać nimi w bierki. Dysk musiałem podłączyć do GNU/Linuxa. Jak wygląda montowanie partycji w systemie
+                               OpenBSD. Za pomocą polecenia <code class="code-inline">dmesg</code> musimy namierzyć nasz dysk.
+                               </p>
+<pre class="code-block">
+sd1 at scsibus4 targ 1 lun 0: &lt;SSDPR-CL, 100-240-G2, 0&gt; serial.174c1153201701000004
+sd1: 228936MB, 512 bytes/sector, 468862128 sectors
+</pre>
+                               <p>
+                               Jeden z moich dysków wygląda tak. Jak znalazłem dysk to jeszcze muszę wskazać partycję do montowania. Do listowania 
+                               tablicy partycji (i nie tylko) służy polecenie <code class="code-inline">disklabel</code>
+                               </p>
+<pre class="code-block">
+# /dev/rsd1c:
+type: SCSI
+disk: SCSI disk
+label: 100-240-G2      
+duid: 04289ed5badd948f
+flags:
+bytes/sector: 512
+sectors/track: 63
+tracks/cylinder: 255
+sectors/cylinder: 16065
+cylinders: 29185
+total sectors: 468862128
+boundstart: 0
+boundend: 468862128
+drivedata: 0 
+
+16 partitions:
+#                size           offset  fstype [fsize bsize   cpg]
+  c:        468862128                0  unused                    
+  i:        466860032             2048  ext2fs                    
+  j:          1996800        466864128 unknown                    
+</pre>
+                               <p>
+                               Kiedy chcę podmontować tą partycję to za pomocą poniższego polecenia otrzymuje tylko komunikat:
+                               </p>
+<pre class="code-block">
+$ doas mount -t ext2fs /dev/sd1i /mnt
+mount_ext2fs: /dev/sd1i on /mnt: specified device does not match mounted device
+</pre>
+                               <p>
+                               Rozwinięcie tego komunikatu znajduje się w komunikatach systemowych dostępnych za pomocą polecenia <em>dmesg</em>.
+                               </p>
+<pre class="code-block">
+ext2fs: unsupported incompat features: 64bit
+</pre>
+                               <p>
+                               Niestety nie podmontuje tego dysku. Lista kompatybilnych systemów plików z OpenBSD znajduje się poniżej:
+                               </p>
+                               <ul>
+                                       <li>cd9600</li>
+                                       <li>ext2fs (ext2)</li>
+                                       <li>msdos (FAT-y)</li>
+                                       <li>nfs</li>
+                                       <li>ntfs</li>
+                                       <li>tmpfs</li>
+                                       <li>udf</li>
+                                       <li>vnd</li>
+                               </ul>
+                               <p>
+                               Czyli najlepszym systemem plików do przenoszenia danych między systemami zostanie <strong>FAT32</strong>. Na 
+                               <em>Reddicie</em> poświęconym  powyższemu problemowi z obsługą systemów plików, jeden z użytkowników napisał, że on to 
+                               korzysta głównie z <em>FAT32</em> do przenoszenia danych między OpenBSD a GNU/Linuxem, ale jest jeden haczyk system plików 
+                               należy utworzyć pod OpenBSD a nie GNU/Linux-em, w przeciwnym razie partycja utworznona na GNU/Linux nie będzie chciała się 
+                               montować w OpenBSD.
+                               </p>
+                               <p>
+                               Po przygodach z dyskiem wpadłem na pomysł, aby spisywać dzień po dniu, to co robie w systemie, o ilę będę robić coś wartego
+                               opisania, nie wiem jak to nazwać poki co robocza wersja "Wykorzystanie systemu OpenBSD do codziennej pracy", plik się nazywa
+                               <em>dziennik_OpenBSD.html</em>, nazwę się jeszcze dopracuje. Pisanie zajmuje znacznie więcej czasu niż wykonywanie rzeczy,
+                               więc mogę się nie wyrobić na "daily" upload. Pierwsze wersje zawsze piszę na brudno, potem trzeba to jeszcze redagować, ale
+                               spróbuje. Ponieważ już jest dzień 3, a ja cały czas pisze dzień drugi wczoraj nie dałem rady fizycznie, nie zawsze też będzie
+                               o czym pisać, więc mogą być przeskoki w dniach. Dziś jeszcze muszę przygotować materiał a mam godzinę czasu, jutro
+                               ewentualnie dokończe dzień 3, przeredaguje te 3 dni i zrobię upload. Mam całą listę rzeczy do zrobienia, a ja sobie robie
+                               "daily" z obsługi OpenBSD. Dobra, koniec dnia 2-go.
+                               </p>
+                       </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Dzień 3 - dysk do wymiany danych pomiędzy Linux-em a OpenBSD, ustawienie tapety na fluxbox</strong> 
+                               - <em>2021-04-10</em><br />
+                               <br />
+                               <p>
+                               Po skończeniu redagowania dnia 2, i ekscesach z niekompatybilnością systemów plików przyszedł czas na kompromis w sprawie.
+                               Stworzę partycję FAT32 na całej długości dysku pod OpenBSD (idąc za wskazówką z <em>Reddita</em>). Tworzenie partycji 
+                               zaczynam od ustawienia odpowiedniej partycji za pomocą polecenia <code class="code-inline">disklabel</code> z przełącznikiem
+                               <code class="code-inline">-E</code> aby uruchomić polecenie w trybie interaktywnym poniżej podałem wybierane polecenia.
+                               </p>
+<pre class="code-block">
+$ doas disklabel -E sd1
+sd1&gt; z
+sd1*&gt; a a
+offset: [0]
+size: [468862128]
+FS type: [4.2BSD] msdos
+sd1*&gt; q
+</pre>
+                               <p>
+                               Po utworzeniu partycji, przychodzi czas na jej sformatowanie. Partycje w OpenBSD przygotowujemy za pomocą róznych wersji 
+                               polecenia <code class="code-inline">newfs</code> wybrany system plików określamy poprzez przyrostek np. 
+                               <code class="code-inline">_msdos</code> - <code class="code-inline">newfs_msdos</code>, polecenia <em>newfs</em> do 
+                               określenia partycji
+                               używają <strong>surowych urządzeń</strong> (raw devices) - <em>/dev/rsd1a</em>. Formatowanie może nie co potrwać, w 
+                               zależności od wiekości dysku.
+                               </p>
+<pre class="code-block">
+$ doas newfs_msdos /dev/rsd1a
+</pre>
+                               <p>
+                               Po sformatowaniu partycji, warto sprawdzić jeszcze raz jej tablice partycji. Ja miałem tak, że tworzyłem partycje o literze
+                               <code class="code-inline">a</code>, kiedy już została sformatowana chciałem ją zamontować klasycznie:
+                               </p>
+<pre class="code-block">
+$ doas mount -t msdos /dev/sd1a /mnt
+</pre>
+                               <p>
+                               Dostałem komunikat o tym, że urządznie jest nie skonfigurowane. 
+                               </p>
+<pre class="code-block">
+mount_msdos: /dev/sd1a on /mnt: Device not configured
+</pre>
+                               <p>
+                               Coś poszło nie tak podczas formatowania? Pierwsze co zrobiłem to zajrzałem do tablicy partycji i okazało się, że po 
+                               formatowaniu zmieniła się litera dysku.
+                               </p>
+<pre class="code-block">
+# /dev/rsd1c:
+type: SCSI
+disk: SCSI disk
+label: 100-240-G2      
+duid: 0000000000000000
+flags:
+bytes/sector: 512
+sectors/track: 63
+tracks/cylinder: 255
+sectors/cylinder: 16065
+cylinders: 29185
+total sectors: 468862128
+boundstart: 0
+boundend: 468862128
+drivedata: 0 
+
+16 partitions:
+#                size           offset  fstype [fsize bsize   cpg]
+  c:        468862128                0  unused                    
+  i:        468862128                0   MSDOS                    
+</pre>
+                               <p>
+                               Więc kiedy poprawiłem literę w poleceniu, dysk został zamontowany.
+                               </p>
+<pre class="code-block">
+$ doas mount -t msdos /dev/sd1i /mnt/disk
+</pre>
+                               <p>
+                               Przed zamontowaniem dysku utworzyłem podkatalog, ponieważ w OpenBSD <strong>nie można zmienić właściciela podkatalogów 
+                               katalogu głównego, np. takiego jak <em>/mnt</em></strong>, a bez zmiany praw własności zwykły użytkownik nie będzie w 
+                               stanie nic na dysku zapisać.
+                               </p>
+                               <p>
+                               Kolejną rzeczą jaką zrobiłem to zmiana tapety, nie jest ona jakoś wybitnie skomplikowana. Po pierwsze trzeba
+                               zainstalować pakiet <em>feh</em>, który jest bardzo lekką przeglądarką plików graficznych.
+                               </p>
+<pre class="code-block">
+$ doas pkg_add -iv feh
+</pre>
+                               <p>
+                               Polecenie <code class="code-inline">fbsetbg</code> jest już wbudowane. Problem w tym, że raczej ono nie zadziała, ponieważ nie
+                               ma w systemie zainstalowanych pewnych pakietów. Nie trzeba ich instalować. Wystarczy że odnajdziemy ww. polecenie:
+                               </p>
+<pre class="code-block">
+$ which fbsetbg
+/usr/local/bin/fbsetbg
+</pre>
+                               <p>
+                               Rzeczony program do ustawiania tapety na <em>fluxbox</em> jest skryptem powłoki, więc aby program zaczął działać bez 
+                               instalacji dodatkowych rzeczy zmieńmy w nim linię:
+                               </p>
+<pre class="code-block">
+[ -n "$1" ] &amp;&amp; hash $1 2&gt; /dev/null
+</pre>
+                               <p>
+                               na:
+                               </p>
+<pre class="code-block">
+which $1 2&gt;&amp;1 &gt; /dev/null
+</pre>
+                               <p>
+                               Po zapisaniu pliku możemy zmienić nareszcie tapetę.
+                               </p>
+<pre class="code-block">
+$ fbsetbg -f ~/Obrazy/1920x1080_32bit.png
+</pre>
+                               
+                       </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Dzień 5 - Laptop z OpenBSD</strong> - <em>2021-04-12</em><br />
+                               <br />
+                               <p>
+                               Wieczorem dnia 4-tego stwierdziłem że zostawię laptop z GNU/Linux-em w domu a do pracy wezmę mojego rzęcha, którego kupłem za
+                               pierwsze zarobione
+                               pieniądze. Już kiedyś był zainstalowany na nim OpenBSD więc wiem że to działa. Ten laptop to Acer AspireOne D260, lekko go
+                               zmodyfikowałem stary dysk HDD, wymieniłem na 240GB SSD GoodRam-a, zamiast 1GB RAM dałem 2GB i chyba najważniejsza zmiana to 
+                               karta sieci bezprzewodowej Broadcom-a, z którym na Debianie miałem problem ze sterownikiem zmieniłem na kartę Atheros, która 
+                               działa bez zarzutu z OpenBSD. Tak poza tym to klasyczna instalacja, póki co jestem w pracy i łącze się po kablu, ale może 
+                               jutro pojawi się wpis z podłączaniem się do sieci bezprzewodowej.
+                               </p>
+                               <p>
+                               Odnośnie dźwieku na tym laptopie, to domyślne wyjście jest ustawione na gniazdo słuchawkowe. To nawet lepiej, bo ja zazwyczaj
+                               podłączam słuchawy albo Hi-Fi do laptopa.
+                               </p>
+                       </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Dzień 6 - Get Wi-Fi connection and get back to work</strong> - <em>2021-04-13</em><br />
+                               <br />
+                               <p>
+                               Instalując na laptopie OpenBSD musiałem wziąć pod uwagę to, że bedę musiał kiedyś skorzystać z sieci bezprzewodowej i warto było by
+                               się dowiedzieć jak to zrobić. Dużo wiedzy na temat samej obsługi OpenBSD znajduje się na stronie FAQ projektu 
+                               <a href="https://openbsd.org">openbsd.org</a>, tam też znalazłem tą na temat połączenia z siecią bezprzewodową. Oczywiście za
+                               pomocą terminala. Pierwsze co należy zrobić to włączyć samą kartę.
+                               </p>
+<pre class="code-block">
+$ doas ifconfig athn0 up
+</pre>
+                               <p>
+                               Po włączeniu karty musze znaleźć SSID mojej sieć, przeskanuje otoczenie.
+                               </p>
+<pre class="code-block">
+athn0: flags=808843&lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,AUTOCONF4&gt; mtu 1500
+       lladdr 74:f0:6d:39:2d:6a
+       index 2 priority 4 llprio 3
+       groups: wlan egress
+       media: IEEE802.11 autoselect (HT-MCS3 mode 11n)
+       status: active
+       ieee80211: nwid EnGenius578D00_1-2.4GHz chan 13 bssid 88:dc:96:57:8d:00 -50dBm wpakey wpaprotos wpa2 wpaakms psk wpaciphers ccmp wpagroupcipher ccmp
+               nwid EnGenius578D00_1-2.4GHz chan 13 bssid 88:dc:96:57:8d:00 -50dBm HT-MCS15 privacy,short_slottime,wpa2 
+               nwid 0x00000000 chan 2 bssid 14:dd:a9:73:15:a4 -86dBm HT-MCS15 privacy,short_slottime,wpa2 
+               nwid COMTREND-VI-3223u-5A8C chan 11 bssid d8:b6:b7:8e:5a:8d -87dBm HT-MCS15 privacy,short_slottime,wpa1 !wpaproto
+               nwid "DIRECT-95-HP M227f LaserJet" chan 6 bssid da:0f:99:3b:83:95 -93dBm HT-MCS15 privacy,spectrum_mgmt,short_slottime,wpa2 
+       inet 192.168.2.125 netmask 0xffffff00 broadcast 192.168.2.255
+</pre>
+                               <p>
+                               Po namierzeniu sieci mogę się już nią parować. Moja sieć jest zabezpieczona za pomocą WPA2, więc musze podać hasło po 
+                               SSID-zie. Do sieci podłączam się za pomocą poniższego polecenia.
+                               </p>
+<pre class="code-block">
+$ doas ifconfig athn0 nwid "EnGenius578D00_1-2.4GHz" wpakey 0xDEADBEEFx0
+</pre>
+                               <p>
+                               Po sparowaniu pobieram adres IP:
+                               </p>
+<pre class="code-block">
+$ doas dhclient
+</pre>
+                               <p>
+                               Kiedy polecenie zwróci mi prompt sprawdzam za pomocą polecenia <code class="code-inline">ping</code> czy połączenie się 
+                               powiodło.
+                               </p>
+<pre class="code-block">
+$ ping wp.pl
+</pre>
+                               <p>
+                               Jeśli chciałbym zapisać sieć, po to aby system łączył się z nią automatycznie podczas ustawiania interfejsów sieciowych, to 
+                               muszę stworzyć plik <em>/etc/hostname.athn0</em> (athn0 - nazwa interfejsu). W zależności od tego czy będzie to tylko jedna 
+                               sieć:
+                               </p>
+<pre class="code-block">
+nwid "SSID" wpakey WPA-PSK
+dhcp
+</pre>
+                               <p>
+                               lub wiele:
+                               </p>
+<pre class="code-block">
+join morketsmerke.net wpakey 1234Test1234
+join EnGenius578D00_1-2.4GHz wpakey 0xDEADBEEFx0
+dhcp
+</pre>
+                               <p>
+                               Po podłączeniu się do sieci można wrócić do pracy. Moja praca polega w jakieś częsci na tworzeniu materiałów na tą stronę. 
+                               Muszę od czasu do czasu obejrzeć wyniki klepanego HTML-a w przeglądarce, jednak pod OpenBSD <em>Firefox</em>, jest strasznie 
+                               ogranicznony, bez pozwolenia wydanego w pliku konfiguracyjnym nie mogę sobie od tak przejść w dowolne miejsce w systemie 
+                               plików nawet na swoim katalogu domowy, gdzie zapisane są moje materiały. Muszę najpierw w plikach 
+                               <em>/etc/firefox/unveil.main</em>, <em>/etc/firefox/unveil.content</em> wpisać ścieżkę do konkretnego katalogu, następnie 
+                               przypisać dla niego odpowiednie uprawnienia.
+                               </p>
+<pre class="code-block">
+~/Cloud r
+</pre>
+                               <p>
+                               W obydwu plikach wpisałem identyczne ścieżki oraz uprawnienia. Po ponownym uruchomieniu <em>Firefox-a</em>, mam dostęp do 
+                               plików poprzez wpisanie adresu <em>file:///home/xf0r3m/Cloud</em>, ale kiedy spróbuje przejść powyżej tego katalogu dostaje 
+                               błąd <em>File not found</em>. Dla przeciętnego użytkownika jest to spore utrudnienie, ponieważ bez utworzenia katalogu 
+                               <em>~/Downloads</em> nic nie można ścignąć a dla wrzucenia plików trzeba również określić jakiś katalog gdzie będą pliki 
+                               przeznaczone do uploadu, a operowanie na wybiórczych katalogach nie jest wcale takie łatwe. Za pomocą magicznego znaku 
+                               tyldy możemy w oknie dialogowym <em>Firefox-a</em> uruchomonić pasek adresu. Jednak patrząc na to jak wielkie są przeglądarki
+                               w obecnych czasach - stają się subsystemami - myślę że lepsze to niż nic.
+                               </p>
+                       </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Dzień 7 - Spotify na openbsd.</strong> - <em>2021-04-14</em>
+                               <p>
+                               Zainstalowanie Spotify na OpenBSD jest łatwiejsze niż na różnych GNU/Linux-ach konfigurowanych od zera. Realizowane jest to 
+                               za pomocą pakietu <em>ncspot</em> z <strong>drzewa portów</strong>. Porty lub drzewo portów jest czymś w rodzaju repozytorium
+                               <em>community</em>, tylko zamiast pre-kompilowanych binariów jak to jest w przypadku paczek z oficjalnego repo mamy kod 
+                               źródłowy, przygotowany (na tyle ile się dało [aby dalej pozostawał kodem]) do kompilacji pod OpenBSD.
+                               </p>
+                               <p>
+                               Cały proces kompilacji programu <em>ncspot</em> z portów jest opisany tutaj: 
+                               <a href="https://ogrul.org/articles/spotify-on-openbsd.html">https://ogrul.org/articles/spotify-on-openbsd.html</a>.
+                               Opisuje go tu tylko w celach kopii zapasowej, gdyby źródło stało się niedostępne.
+                               </p>
+                               <p>
+                               Kompilację rozpocznę od pobrania paczki z portami z oficjalnego źródła, najlepiej do  <em>/tmp</em>
+                               plik zniknie po restarcie nie pozostawiając po sobie bałaganu, a i tak będę musiał go rozpakować do <em>/usr</em>.
+                               </p>
+<pre class="code-block">
+$ cd /tmp
+$ ftp https://cdn.openbsd.org/pub/OpenBSD/$(uname -r)/{ports.tar.gz,SHA256.sig}
+</pre>
+                               <p>
+                               Sprawdzam czy plik nie został podmieniony (jakimś cudem [jeśli ktoś podszył się pod źródło, z którego pobrałem porty]) na 
+                               podstawie ściągniętej wraz z paczką sygnatury. 
+                               </p>
+<pre class="code-block">
+$ signify -Cp /etc/signify/openbsd-$(uanem -r | cut -c 1,3)-base.pub -x SHA256.sig ports.tar,gz
+</pre>
+                               <p>
+                               W odpowiedzi dostałem coś takiego:
+                               </p>
+<pre class="code-block">
+Signature Verified
+ports.tar.gz: OK
+</pre>
+                               <p>
+                               Po sprawdzeniu pliku, rozpakowuje paczkę z portami bezpośrednio w katalogu <em>/usr</em>.
+                               </p>
+<pre class="code-block">
+$ cd /usr
+$ doas tar -xzvf /tmp/ports.tar.gz
+</pre>
+                               <p>
+                               Następnie w pliku <em>/etc/mk.conf</em> wskazuje katalogi robocze używane podczas kompilacji.
+                               <p>
+<pre class="code-block">
+WRKOBJDIR=/usr/obj/ports
+DISTDIR=/usr/distfiles
+PACKAGE_REPOSITORY=/usr/packages
+</pre>
+                               <p>
+                               Przechodzę z powrotem do katalogu gdzie wypakowałem porty i wydaje polecenie:
+                               </p>
+<pre class="code-block">
+$ doas make search key=ncspot
+</pre>
+                               <p>
+                               Polecenie za pierwszym razem zwróci błąd. Zawsze zwraca, do działania potrzebuje pakietu 
+                               <code class="code-inline">portslist</code>.
+                               </p>
+<pre class="code-block">
+$ doas pkg_add -iv portslist
+</pre>
+                               <p>
+                               Po zainstalowaniu pakietu ponownie wydaje polecenie <code class="code-inline">$ doas make search key=ncspot</code>, wynik 
+                               polecenia powinien być następujący:
+                               </p>
+<pre class="code-block">
+Port:  ncspot-0.2.2p0
+Path:  audio/ncspot
+Info:  ncurses Spotify client
+Maint: Henrik Friedrichsen &lt;henrik@diff.cc&gt;
+Index: audio lang/rust
+L-deps:        audio/portaudio-svn x11/dbus,-main
+B-deps:        STEM-&gt;=1.30:lang/rust devel/cargo-generate-vendor lang/rust
+R-deps:        
+Archs: any
+</pre>
+                               <p>
+                               Żeby w ogóle rozpocząć proces kompilacji muszę zainstalować wszystko co znajduje się w polu 
+                               <code class="code-inline">B-deps:</code> - zależności kompilacji. W tym konkretnym przypadku akurat mam szczęście, że te
+                               programy znajdują się w repo i nie trzeba ich kompilować. Instalacja oprogramowania przez kompilację kodu to trochę
+                               błędne koło, ponieważ musisz spełnić zależności kompilowanego programu, kiedy chcesz to zrobić i znów musisz 
+                               kompilować wtedy wracamy do punktu wyjścia bo musimy znów spełnić zależności, zależności kompilacji programu macierzystego 
+                               i być może znów będziemy musieli je kompilować. Kompilacja daje możliwość dostosowania oprogramowania do własnych potrzeb.
+                               </p>
+<pre class="code-block">
+$ doas pkg_add -iv rust cargo-generate-vendor
+</pre>
+                               <p>
+                               Po zainstalowaniu zależności uruchamiam kompilacje. Ścieżka do kodu aplikacji jest wskazana przez pole 
+                               <code class="code-inline">Path:</code> informacji zwracanych przez polecenie <code class="code-inline">make search</code>.
+                               <p>
+<pre class="code-block">
+$ cd audio/ncspot
+$ doas make install
+</pre>
+                               <p>
+                               Po zbudowaniu projektu, co trochę trwa w zależności od mocy przerobowej komputera, mogę wreszcie uruchomić <em>ncspot</em>:
+                               </p>
+<pre class="code-block">
+$ ncspot
+</pre>                         
+                               <p>
+                               zalogować się i korzystać z usługi. Oczywiście jak wszystkie te aplikacje wykorzystujące API, potrzebne jest konto premium. 
+                               Nie tyle o same Spotify chodziło, co o możliwie najprostrze przedstawienie systemu portów.
+                               </p>
+                       
+               </p>
+               <p>&nbsp;</p>
+               <p>
+                       <strong>Dzień 9 - Płyty pod OpenBSD</strong> - <em>2021-04-17</em>
+                       <p>
+                       8-go dnia stwierdziłem że muszę zrobić porządek z płytami, na których miałem pozgrywaną muzykę żeby ją odtwarzać na wieży. Z racji 
+                       tego że wieża wspierała zarówno format <em>Audio CD</em> jak zwykłe płyty nagrane jako "płyta z danymi" z plikami <em>MP3</em>, 
+                       posiadałem płyty nagrane w różnych formatach. Podłączyłem napęd do komputera, włożyłem płytę i zacząłem szukać w necie jak to zrobić.
+                       Pierwszą rzeczą jakiej  się dowiedziałem (nie z Internetu, a z autopsji) było rozpoznawanie płyt, które są nagrane w formacie 
+                       <em>Audio CD</em>, a które z plikami <em>MP3</em>.
+                       </p>
+<pre class="code-block">
+$ doas disklabel cd0
+</pre>
+                       <p>
+                       Jeśli jest to płyta z danymi to w tabeli partycji, pojawią się dwie partycje: <code class="code-inline">a</code> oraz 
+                       <code class="code-inline">c</code>. Jeśli zaś jest to i <em>Audio CD</em> to tabela będzie pusta.
+                       </p>
+                       <p>
+                       <u>MP3:</u>
+                       </p>
+
+<pre class="code-block">
+# /dev/rcd0c:
+type: ATAPI
+disk: 110124_1858     
+label:                 
+duid: 0000000000000000
+flags:
+bytes/sector: 2048
+sectors/track: 100
+tracks/cylinder: 1
+sectors/cylinder: 100
+cylinders: 3390
+total sectors: 338911
+boundstart: 0
+boundend: 338911
+drivedata: 0 
+
+16 partitions:
+#                size           offset  fstype [fsize bsize   cpg]
+  a:           338911                0 ISO9660                    
+  c:           338911                0 ISO9660                   
+</pre>
+                       <p>
+                       <u>Audio CD:</u>
+                       </p>
+<pre class="code-block">
+# /dev/rcd0c:
+type: ATAPI
+disk: ATAPI CD-ROM
+label: fictitious
+duid: 0000000000000000
+flags:
+bytes/sector: 2048
+sectors/track: 100
+tracks/cylinder: 1
+sectors/cylinder: 100
+cylinders: 1738
+total sectors: 173758
+boundstart: 0
+boundend: 0
+drivedata: 0 
+
+0 partitions:
+#                size           offset  fstype [fsize bsize   cpg]
+</pre>
+                       <p>
+                       Na podstawie tego, płytę z danymi montuje najzwyczajniej w świecie jak zwykły dysk. Trzeba jeszcze spojrzeć na system plików użyty na 
+                       płycie. OpenBSD natywnie wspiera <em>ISO9660</em> oraz <em>UDF</em>. Na moich płytach z <em>MP3</em> używałem formatu 
+                       <em>ISO9660</em>.
+                       </p>
+<pre class="code-block">
+$ doas mount_iso9660 /dev/cd0a /mnt
+</pre>
+                       <p>
+                       Po skopiowaniu danych odmontowuje ją (<code class="code-inline">doas umount /mnt</code>).
+                       </p>
+
+                       <p>
+                       W przypadku formatu <em>Audio CD</em> trzeba użyć innego narzędzia. Do obsługi tego typu płyt wykorzystuje się program 
+                       <strong>cdio</strong>. Za pomocą tego programu można taką płytę odtworzyć lub zripować. Ten program potrafi np. połączyć się z 
+                       bazą GNU i ściągnąć tagi dla ścieżek zapisanych na płycie. Poniżej znajdują się polecenia odtwarzania i ripowania.
+                       </p>
+                       <p>
+                       <u>Odtworzenie Audio CD:</u>
+                       </p>
+<pre class="code-block">
+$ doas cdio -f /dev/cd0c cdplay
+</pre>
+                       <p>
+                       <u>Ripowanie Audio CD:</u>
+                       </p>
+<pre class="code-block">
+$ doas cdio -f /dev/cd0c cdrip
+</pre>
+                       <p>
+                       Warto dodać żeby uniknąć bałaganu, uruchamiałem polecenie do ripowania w przeznaczonym dla tej płyty katalogu. Jako bonus
+                       polecenie do sprawdzenia płyty w gnudb.org
+                       </p>
+<pre class="code-block">
+$ doas cdio -f /dev/cd0c cddbinfo
+</pre>
+                       <p>
+                       Wynik polecenia może być różny w zależności od tego co uda mu się znaleźć na płycie.
+                       </p>
+               </p>
+               <p>&nbsp;</p>
+               <p>
+                       <strong>Dzień 11 - Raspberry Pi Zero podłączone przez USB do laptopa z OpenBSD i torrenty z terminala</strong> - 
+                       <em>2021.04.19</em>
+                       <p>
+                       Potrzebowałem serwera www najlepiej z Git-em, do pisania pewnych aplikacji. Mój Acer Aspire One, strasznie by się spocił przy 
+                       hostowaniu maszyn wirtualnych, ale nie należało go skreślać bo kiedyś korzystałem z terminala HP z podobnym procesorem, który
+                       hostował dwie maszyny wirtualne. Zużycie procesora 100% bez przerwy za nim coś zrobiłem to trochę minęło, ale jakoś jakoś
+                       dawał radę. Miałbym go do dzisiaj gdyby nie zalało pomieszczenia, którym się znajdował, a że leżał na podłodze,
+                       woda go uszkodziła i niestety trafił na złom. Wracając do głównego tematu. Pomyślałem, a co gdyby użyć RPI, trzeba by podłączać
+                       to do sieci, nosić zasilacz lub używac powerbank-a. No dobra, a Raspberry Pi Zero? Podłączone do Acera... Tak tylko że na
+                       tym laptopie jest przecież zainstalowane OpenBSD. No to mam problem.
+                       </p>
+                       <p>
+                       Nie taki diabeł straszny jak go malują. Po zainstalowaniu obrazu na karcie przy użyciu tego laptopa, musiałem niestety użyć 
+                       zewnętrznego czytnika kart, bo ten wbudowany nie miał generalnie wsparcia na systemach *BSD. Kolejny przeszkodą mogła być
+                       konfiguracji <strong>RNDIS</strong>, bo trzeba to ustawić na karcie na partycji <em>Boot</em>, jednak <em>RasPiOS</em> 
+                       wykorzystuje partycję <em>Boot</em> sformatowaną na <em>MSDOS</em> (<em>FAT32</em>). Na chwilę przeskoczę do tego jak w ogóle
+                       zdobyłem obraz.
+                       </p>
+                       <p>
+                       Obraz zdobyłem za pomocą sieci BitTorrent, nie miałem jednak wiedzy nt. klientów BT na OpenBSD. Sprawdziłem z ciekawości program,
+                       który ożywam od lat <strong>Transmission</strong>. Ten program jest stworzony w architekturze klient-serwer i można go 
+                       używać na wiele róznych sposobów za pomocą przeglądarki, klasycznego okna czy to na czym mi zależało z poziomu terminala. 
+                       Więc wchodzę na stronę projektu <em>Transmission</em>, a tam pod OpenBSD widnieje napis "Official packages". I teraz wiem
+                       że jestem w domu. Sciągam paczkę z <em>Transmission</em>.
+                       </p>
+<pre class="code-block">
+$ doas pkg_add -iv transmission
+</pre>
+                       <p>
+                       Informacje o tym jak używać <em>Transmission</em> znalazłem za pomoc DuckDuckGo na tej stronie: 
+                       <a href="https://cli-ck.io/transmission-cli-user-guide">https://cli-ck.io/transmission-cli-user-guide</a>
+                       Po zainstalowaniu się pakietu, wskazuję daemonowi <em>Transmission</em> katalog dla pobranych.
+                       </p>
+<pre class="code-block">
+$ transmissions-daemon --download-dir ~/Downloads
+</pre>
+                       <p>
+                       Daemona uruchamiamy tym samym poleceniem tylko bez żadnych przełączników czy opcji.
+                       </p>
+<pre class="code-block">
+$ transmissions-daemon
+</pre>
+                       <p>
+                       Pliki <em>torrent</em> czy <em>magnet linki</em>, dodajemy za pomocą poniższego polecnia z wraz z opcją 
+                       <code class="code-inline">-a</code>. 
+                       </p>
+<pre class="code-block">
+$ transmission-remote -a &lt;plik_torrent/magnet_link&gt;
+</pre>
+                       <p>
+                       Do monitorowania daemona (sprawdzenia postępów ściągania) służy polecenie:
+                       </p>
+<pre class="code-block">
+$ transmissions-remote -l
+</pre>
+                       <p>
+                       Po pobraniu, nagraniu obrazu na kartę oraz skonfigurowaniu systemu, przyszedł czas na podłączenie RPI do laptopa. 
+                       Po podłączeniu w systemie pojawił się nowy interfejs sieciowy <strong>urndis0</strong> i nic poza tym. Każdy 
+                       interfejs żeby mógł się komunikować z kimkolwiek musi mieć jakiś adres. Stworzyłem więc plik 
+                       <em>/etc/hostname.urndis0</em> o takiej zawartości:
+                       </p>
+<pre class="code-block">
+inet 192.168.56.1 255.255.255.0
+</pre>
+                       <p>
+                       Zrestartowałem sieć.
+                       <p>
+<pre class="code-block">
+$ doas sh /etc/netstart
+</pre>
+                       <p>
+                       No tak, ja mam adres a Raspberry? Nope. Jak można nadać adres hostowi bez możliwości jakiej kolwiek konfiguracji?
+                       Za pomocą DHCP. Utworzyłem konfigurację w <em>/etc/dhcpd.conf</em> z bardzo małym zakresem:
+                       </p>
+<pre class="code-block">
+subnet 192.168.56.0 netmask 255.255.255.0 {
+
+       range 192.168.56.5 192.168.56.10;
+       option routers 192.168.56.1;
+       option domain-name "local";
+       option domain-name-servers 192.168.56.1;
+}
+</pre>
+                       <p>
+                       Uruchomiłem z reki daemona DHCP.
+                       </p>
+<pre class="code-block">
+$ doas dhcpd urndis0
+</pre>
+                       <p>
+                       I czekałem na przydzielenie adresu sprawdzając co jakiś czas plik <em>/var/db/dhcpd.leases</em>, aż moim oczom ukazał
+                       się taki o to wpis:
+                       </p>
+<pre class="code-block">
+lease 192.168.56.7 {
+       starts 1 2021/04/19 07:32:45 UTC;
+       ends 1 2021/04/19 19:32:45 UTC;
+       hardware ethernet aa:9a:fc:ef:b5:83;
+       uid 01:aa:9a:fc:ef:b5:83;
+       client-hostname "raspberrypi";
+}
+</pre>
+                       <p>
+                       Teraz mogłem się połączyć z Raspberry. Żeby nie musieć za każdym razem uruchamiać DHCP, ustawiłem na nim statyczny
+                       adres i tak byłby wymagany do <em>Gogs-a</em>. Oczywiście żeby zainstalować tym sprzęcie cokolwiek potrzebne jest
+                       połączenie z Internetem. Musiałem przerobić tego laptopa na bramkę na żądanie, doinstalować dnsmasq (nie potrzeba
+                       go konfigurować), na podstawie obecnego pliku PF, utworzyłem plik z regułą <strong>NAT-u</strong> oraz włączyć
+                       przekazywanie pakietów.
+                       </p>
+<pre class="code-block">
+$ doas pkg_add -iv dnsmasq
+
+pass out on alc0 from urndis0:network to any nat-to (alc0)
+
+sysctl net.inet.ip.forwarding=1
+</pre>
+                       <p>
+                       <code class="code-inline">Alc0</code> to interfejs przez, który mój laptop łączy się z siecią lokalną w budynku. Całość
+                       skonfigurowałem wraz z instalacją <em>Gogs-a</em> i mimo <strong>LAMP Stacka</strong> to Raspberry Pi Zero radzi sobie
+                       nadzwyczaj dobrze.
+                       </p>
+
+               </p>
+               <p>
+               ~xf0r3m
+               </p>
+               </div>
+
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/bsd/index.html b/articles/bsd/index.html
new file mode 100755 (executable)
index 0000000..4203133
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <ul class="special_list">
+        <li><a href="20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html">20 letni Sun Netra T1 jako serwer mailowy_z_wykorzystaniem_NetBSD</a></li>
+        <li><a href="dziennik_OpenBSD.html">Dziennik OpenBSD</a></li>
+        <li><a href="instalacja_NetBSD.html">Instalacja NetBSD</a></li>
+        <li><a href="instalacja_OpenBSD.html">Instalacja OpenBSD</a></li>
+        <li><a href="OpenBSD_jako_bramka_sieciowa.html">OpenBSD jako bramka sieciowa</a></li>
+                       </ul>
+               </div>
+
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/bsd/instalacja_NetBSD.html b/articles/bsd/instalacja_NetBSD.html
new file mode 100755 (executable)
index 0000000..d3c2f40
--- /dev/null
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <h1 class="title">Instalacja NetBSD</h1>
+                       <p>
+                       System <strong>NetBSD</strong> ma jedną bardzo ważną cechę, został przygotowany i jest nadal utrzymywany dla bardzo wielu platform. 
+                       To sprawiło, że 
+                       zainteresowałem się nim przy chęci wykorzystania go na starym serwerze Sun Microsystems. Jako jedyny z wiodącej trójki systemów
+                       BSD poprawnie zainstalował się i uruchomił na wspomnianym serwerze. Obecnie zapewnia dostęp do usług poczty elektronicznej.
+                       Jedną z jego wad jest dość długa i mająca tendencje do niepowdzenia instalacja, przynajmniej w 
+                       przypadku platformy Sparc64. Poniżej za pomocą zrzutów ekranu oraz krótkich opisów postaram się przybliżyć instalację. Instalowałem 
+                       większość dystrybucji BSD i nie wliczając GhostBSD oraz nomadBSD, ten system ma chyba najbardzie user-friendly instalator, 
+                       pasujący bardziej do GNU/Linux-ów.
+                       </p>
+                       <p>
+                       Płytka w napędzie? No to jadziem!
+                       </p>
+                       <p>
+                       Instalację rozpoczynamy od wyboru języka instalatora. Chyba jedyna dystrybucja BSD z polskim językiem instalatora (potrzebne źródło).
+                       Wybieramy opcje <code class="code-inline">e: Komunikaty instalacyjne w języku polskim</code>.
+                       <p>
+                       <p>
+                       Z poziomu instalatora możemy np. zaktualizować zainstalowany już system. Póki co to nie mamy nawet tego, więc wybieramy 
+                       <code class="code-inline">a: Zainstaluj NetBSD na twardym dysku</code>. Fun fact o tym instalatorze: możemy poruszać po nim znacznie
+                       szybciej naciskając na klawiaturze te literki po lewej stronie opcji.
+                       </p>
+                       <p>
+                       Standardowe pytanie o to czy rzeczywiście chcemy instalować ten system. Wybieramy <code class="code-inline">b: Tak</code>, chyba że
+                       zmieniliśmy zdanie.
+                       </p>
+                       <p>
+                       Wybieramy docelowy dysk dla systemu. W moim przypadku jest to <code class="code-inline">a: wd0 (8.0G)</code>.
+                       </p>
+                       <p>
+                       Następnie ustalamy sposób partycjonowania, możemy wyczyścić dysk i ustawić partycje ręcznie lub automatycznie. Póki co 
+                       wybierzemy <code class="code-inline">b: Użyj domyślnych rozmiarów partycji</code>.
+                       </p>
+                       <p>
+                       Zatwierdzamy ustawione przez instalator partycje, <code class="code-inline">x: Rozmiary partycji w porządku</code>.
+                       </p>
+                       <p>
+                       Póki co nie zostały wprowadzane żadne zmiany na dysku, dopiero wybranie opcji <code class="code-inline">b: Tak</code>, spowoduje
+                       ustawienie partycji i sformatowanie pod określony system plików.
+                       </p>
+                       <p>
+                       Instalacja NetBSD jest podzielona na trzy główne kolekcje. Dla serwera wystarczy 
+                       <code class="code-inline">b: Instalacja bez X11</code>.
+                       </p>
+                       <p>
+                       NetBSD można zainstalować z wielu źródeł. Na serwerze, na którym próbowałem zainstalować NetBSD z płyty to był wielki problem,
+                       bo system nie mógł dobrać poziomu <em>DMA</em> dla napędu więc użyłem <code class="code-inline">b: HTTP</code>.
+                       </p>
+                       <p>
+                       Teraz mamy możliwość ustawienia mirror-u. Wykorzystanie źródła <em>HTTP</em> wymaga skonfigurowania sieci, dlatego też wybieramy
+                       opcje <code class="code-inline">j: Skonfiguruj siec</code>.
+                       </p>
+                       <p>
+                       Wybieramy kartę sieciową, w moim przypadku jest to <code class="code-inline">a: hme0</code>
+                       </p>
+                       <p>
+                       Typ interfejsu sieciowego pozostawiamy domyślnie czyli <code class="code-inline">autoselect</code>, następnie decydujemy czy wybrać 
+                       autokonfigurację - pobrać z dhcp.
+                       </p>
+                       <p>
+                       Po pobraniu konfiguracji zostaniem zapytani o nazwę domeny, jeśli serwer nie będzie dostępny pod żadną możemy wpisać cokolwiek.
+                       Po zatwierdzeniu pokaże nam się podsumowanie konfiguracji i zapytanie czy te dane są poprawne.
+                       </p>
+                       <p>
+                       Po potwierdzeniu konfiguracji, wracamy do ustawień źródła pakietów dystrybucji. Teraz wybieramy opcje 
+                       <code class="code-inline">x: Ściągnij dystrybucje</code>. A samo pobranie dystrybucji w raz z instalacją pobranych paczek może
+                       chwilę potrwać.
+                       </p>
+                       <p>
+                       Konfiguracja sieci z pobierania dystrybucji może zostać zapisana jako stała konfiguracja sieciowa systemu, teraz możemy o tym 
+                       zdecydować. Jeśli maszyna znajduje się już w docelowej sieci i nadaliśmy mu już przeznaczony dla niego adresu, badź zrobił to serwer 
+                       DHCP możemy zapisać konfiguracje <code class="code-inline">b: Tak</code>.
+                       </p>
+                       <p>
+                       Teoretycznie to system jest już zainstalowany jednak nie uruchomi się bez konfiguracji w plikach <em>rc</em>. Ustawiamy:
+                       </p>
+                       <ul>
+                               <li>
+                               Strfę czasową ustawiamy na <code class="code-inline">Poland</code> lub <code class="code-inline">Europe/Warsaw</code>
+                               </li>
+                               <li>Powłokę <em>roota</em>, na <em>/bin/ksh</em>.</li>
+                               <li>Hasło <em>roota</em>.</li>
+                               <li>Włączamy <em>sshd</em></li>
+                               <li>Właczamy <em>ntpdate</em> (dla <em>ntpdate</em>, potrzebny będzie jeszcze serwer, z którego synchonizował będzie date i 
+                                       czas, ale to już ustawia sie po pierwszym załadowaniu systemu.</li>
+                               <li>Tworzymy zwykłego użytkownika, dodajemy go do grupy <em>wheel</em>. Grupa <strong>wheel</strong>, umożliwią należącym
+                                       do niej użytkownikom na wykonanie polecenia <code class="code-inline">su root</code>.</li>
+
+
+                       </ul>
+                       <p>
+                       Teraz możemy zakończyć konfigurację poinstalacyjną wybierając opcje <code class="code-inline">x: zakończ konfigurację</code>.
+                       Zostanie nam wyświetlony komunikat o tym że zainstalowaliśmy NetBSD, za pomocą klawisza <em>enter</em> wracamy do menu gdzie
+                       wybieraliśmy tryb instalacji.
+                       </p>
+                       <p>
+                       Teraz możemy uruchomić ponownie nasz komputer wybierając opcję <code class="code-inline">d: Zrestartuj komputer</code>.
+                       </p>
+                       <p>
+                       ~xf0r3m
+                       </p>
+               </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/bsd/instalacja_OpenBSD.html b/articles/bsd/instalacja_OpenBSD.html
new file mode 100755 (executable)
index 0000000..7ed69d1
--- /dev/null
@@ -0,0 +1,246 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+88                             88
+88                             88
+88                             88
+88,dPPYba,  ,adPPYba,  ,adPPYb,88
+88P'    "8a I8[    "" a8"    `Y88
+88       d8  `"Y8ba,  8b       88
+88b,   ,a8" aa    ]8I "8a,   ,d88
+8Y"Ybbd8"'  `"YbbdP"'  `"8bbdP"Y8
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+<h1 class="title">Instalacja OpenBSD</h1>
+<p>
+Eksperymentując długo przed poznaniem <strong>OpenBSD</strong> z GNU/Linux-owymi dystrybucjami przeznaczonymi na routery, głównie z <em>IPCop</em>, poźniej <em>IPFire</em>, następnie przesiadłem się na <em>PFsense</em>, który był oparty o firewall <strong>PF</strong>. Utworzywszy w PFsense kilka reguł okazało się że żadna z nich nie działa. Porzuciłem routery. Przyszedł czas mojej pierwszej pracy. Po ogarnięciu bałaganu sieciowego, firmowy router zaczał się wieszać... Wziąłem go na warsztat, był dosć ciekawie skonfigurowany, serwerowa płyta Intela  z socketem 478. Był tak zakurzony, że po rozkręceniu było tyle syfu że można było pomyśleć że ktoś tam piachu nasypał, ale płyta cała. Wszystkie kondestatory sprawne, ram testowany memtestem - sprawny. Dobra, czyli zmieniamy system. Tylko jakoś niechciałem GNU/Linuxa i iptables. Przypomniałem sobie o  PF. Wpisując "PF packet filter" w wyszukiwarkę, znalazłem na oficjalnej stronie OpenBSD świetną dokumentację PF, to pomyślałem o OpenBSD jako docelowym systemie. Można spróbować. Mam system operacyjny wraz z pakietem firewalla. Dokumentacja na stronie projektu była pierwszym moim przeczytanym ze zrozumieniem anglojęzycznym, technicznym tekstem. Po zapoznaniu się z PF trzeby by zainstalować sobie OpenBSD i trochę po go testować.
+</p>
+<pre class="code-block">
+(I)nstall, (U)pgrade, (A)utoinstall, or (S)hell? I
+</pre>
+<p>
+Instalacje OpenBSD rozpoczynamy od wyboru trybu pracy w środowisku instalacyjnym. Wybieramy instalacje, czyli <code class="code-inline">I</code>.
+</p>
+<p>
+Następnym krokiem jest wybór layoutu klawiatury, możemy wybrać literę <code class="code-inline">l</code> lub znak <code class="code-inline">?</code> co wyświetli nam dostępne układy, oczywiście wybieramy <code class="code-inline">pl</code>.
+</p>
+<p>
+Kolejną rzeczą do ustawienia podczas instalacji jest nazwa hosta. Na przykład <em>foo</em>.
+</p>
+<pre class="code-block">
+System hostname (short form e.g. 'foo') foo
+</pre>
+<p>
+Następnie instalator wyświetli nam listę dostępnych w systemie interfejsów sieciowych. Zapyta czy chcemy je teraz konfigurować, jeśli nie, wystarczy wpisać <code class="code-inline">done</code>. Tą wartością możemy również przerwać konfiguracje. Powiedzmy że mamy trzy interfejsy w systemie, ustawiliśmy jeden i to wystarczy. Kiedy instalator zapyta o następny, wpisujemy <code class="code-inline">done</code>. Dla pierwszego interfejsu, konfiguracja wygląda w taki sposób że po podaniu (zaakceptowaniu) nazwy (podanej przez instalator), podajemy adres IP pod jakim będzie on dostępny w sieci lub jeśli ma pobrać adres z DHCP wpisujemy <code class="code-inline">dhcp</code>. Jeśli wpisaliśmy adres, to następne pytanie będzie o maskę podsieci. System zasugeruje nam maskę, jeśli pasuje ona do naszej konfiguracji sieci to możemy ją zatwierdzić, jeśli nie to podajemy swoją.
+</p>
+<pre class="code-block">
+IPv4 address for em0 ? (or 'dhcp' or 'none') [dhcp] 10.0.0.1
+Netmask for em0 [255.255.255.0] 255.0.0.0
+</pre>
+<p>
+Możemy ją zaakceptować lub wpisać swoją. Następną konfiguracją będzie IPv6, konfigurujemy ją wedle własnego uznania, ja przeważnie wybieram opcje domyślną czyli <code class="code-inline">none</code>.
+</p>
+<pre class="code-block">
+IPv6 address for em0 ? (or 'autoconf' or 'none) [none]
+</pre>
+<p>
+Po tej konfiguracji przechodzimy do kolejnego interfejsu, tu możemy przerwać konfiguracje sieci, jeśli to zrobimy, to od razu przejdziemy do pytań o:
+</p>
+<ol>
+<li>
+<p>
+Bramę domyślną (o ile wybraliśmy statyczną konfigurację interfejsu)
+</p>
+<pre class="code-block">
+Default IPv4 route ? (IPv4 address or none) [none]
+</pre>
+</li>
+<li>
+<p>
+Domenę (dla statycznej, jak i DHCP)
+</p>
+<pre class="code-block">
+DNS domain name (e.g. 'example.com') [my.domain] morketsmerke.net
+</pre>
+</li>
+<li>
+<p>
+Adresy serwerów DNS (o ile wybraliśmy statyczną konfigurację)
+</p>
+<pre class="code-block">
+DNS nameservers? (IP address list or none) 192.168.1.1
+</pre>
+</li>
+</ol>
+<p>
+Po konfiguracji sieci, czas na ustawienia hasła użytkownika <em>root</em>.
+</p>
+<pre class="code-block">
+Password for root account ? (will not echo)
+</pre>
+<p>
+Po tym zostaniemy zapytani o to czy domyślnie uruchamiać <em>sshd</em> oraz <em>xenodm</em> wraz ze startem systemu i czy zmienić domyślną konsole na port COM. Na pytania opowiadamy w zależności od potrzeb.
+</p>
+<p>
+Na serwerach na pierwsze pytanie odpowiadamy <code class="code-inline">yes</code>.
+</p>
+<pre class="code-block">
+Start sshd(8) by default? [yes]
+</pre>
+<p>
+Na powyższym przykładzie nie ma odpowiedzi, ponieważ akceptujemy odpowiedź zasugerowaną przez instalator. Na drugie odpowiadamy <code class="code-inline">no</code> (Jeśli instalujemy OpenBSD z zamiarem uruchamiania środowiska graficznego to możemy opowiedzieć <code class="code-inline">yes</code>.)
+</p>
+<pre class="code-block">
+Do you expect to run the X Window System? [yes] no
+</pre>
+<p>
+trzecie... Tu sprawa się komplikuje. <strong>Przepuszczanie konsoli, przez port COM to</strong> generalnie fajna sprawa jeśli mamy ograniczone miejsce, podpinamy kabelek USB do laptopa na następnie podpinamy kabel do ser... okazuje się że kable usb - rs232 (czy COM) mają złącze rs232 męskie i w serwerze prawdopodobnie złacze też jest męskie, <strong>potrzebujemy kabla rs232 żeńsko-żeńskiego</strong>. Jeśli ktoś posiada wymagane okablowanie oraz odpowiednie umiejętności może wybrać tutaj <code class="code-inline">yes</code>, jednak do powszechnego użytku przekierowanie konsoli, nie będzie nam potrzebne (<code class="code-inline">no</code>).
+</p>
+<p>
+Po odpowiedzi na te trzy pytania, zostaniemy poproszeni o nazwę pierwszego użytkownika systemu. Jego będziemy wykorzystywać jako użytkownika do logowania się przez SSH do systemu.
+</p>
+<pre class="code-block">
+Setup a user? (enter a lower-case loginname, or 'no') [no] admin
+</pre>
+<p>
+Po podaniu nazwy użytkownika, zostaniemy zapytani o jego pełną nazwę czyli imię i nazwisko. Pozostawiamy tę wartość domyślną, która jest równa nazwie uzytkownika.
+</p>
+<pre class="code-block">
+Full name for user admin? [admin]
+</pre>
+<p>
+Następnie instalator zapyta nas o hasło dla nowopowstałego użytkownika.
+</p>
+<pre class="code-block">
+Password for user admin? (will not echo)
+</pre>
+<p>
+Teraz zostaniemy powiadomieni o tym że użytkownik <em>root</em>, jest celem ataków odgadywania hasła, oraz że używanie w jego przypadku kluczy publicznych do logowania przez SSH jest bezpieczniejsze, po tej informacji zostajemy zapytani o to czy zezwolić na logowanie przez SSH użytkownika <em>root</em>? Do wyboru mamy <code class="code-inline">yes</code>, <code class="code-inline">no</code> lub <code class="code-inline">prohibit-password</code>. Wybieramy wedle własnego uznania, chociaż warto wspomnieć że stworzony przed chwilą użytkownik będzie znajdować się w specjalnej grupie, która ma możliwość wykonania polecenia <code class="code-inline">su root</code>.
+</p>
+<pre class="code-block">
+Warning: root is targeted by password guessing attacks, pubkeys are safer.
+Allow root ssh login? (yes, no, prohibit-password) [no]
+</pre>
+<p>
+Pora na ustawienia właściwej strefy czasowej, znakiem zapytania <code class="code-inline">?</code> możemy wylistować sobie dostępne strefy. Może być wielce prawdopodobne że zostanie ona sama prawidłowo zasugerowana bazując na wybranym układzie klawiatury.
+</p>
+<pre class="code-block">
+What timezone are you in? ('?' for list) [Europe/Warsaw]
+</pre>
+<p>
+Teraz możemy przejść do partycjonowania. Zostanie nam przedstawiona lista dostępnych w systemie dysków.
+</p>
+<pre class="code-block">
+Available disks are: wd0
+</pre>
+<p>
+Zostaniemy poproszeni o wskazanie głównego systemu plików, system zasugeruje na dysk pierwszy na liście.
+</p>
+<pre class="code-block">
+Which disk is the root disk? ('?' for details) [wd0]
+</pre>
+<p>
+Oczywiście możemy to zmienić. W tym momencie musimy wybrać pomiędzy całym wykorzystaniem dysku z tablicą MBR a tablicą GPT lub ręcznym wydzieleniem miejsca dla BSD, w zależności od tego czy nasz dysk
+przekracza 2TB wybieramy <code class="code-inline">G</code>PT a jeśli nie to <code class="code-inline">whole</code> co oznacza MBR.
+</p>
+<pre class="code-block">
+Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [whole]
+</pre>
+<p>
+Po wybraniu trybu zostanie nam wyświetlona automatyczna alokacja miejsca na dysku (partycji) (dla powszechnego użytku jest wystarczająca). Możemy ją edytować lub utworzyć swoją własną. Utworzoną alokację potwierdzamy literką <code class="code-inline">a</code>. Teraz następuję rzeczywiste ustawianie partycji.
+</p>
+<pre class="code-block">
+Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a]
+</pre>
+<p>
+Po tej czynności nadchodzi czas na instalacje systemu, na początku wybieramy źródło plików do instalacji, systemy BSD są systemami które mogą wystartować z instalacją z dyskietki 3,5" a następnie pobrać pakiety systemowe z Internetu. My wybieramy <code class="code-inline">cd0</code> lub <code class="code-inline">disk</code> Instalator zasugeruje nam nośnik z plikami, z którego został uruchomiony lub <code class="code-inline">http</code>.
+</p>
+<pre class="code-block">
+Location of sets? (cd0 disk http or 'done') [cd0]
+</pre>
+<p>
+W przypadku uruchomienia z dysku USB wybramy opcję <code class="code-inline">disk</code> będziemy musieli odpowiedzieć na pytanie czy dysk został zamontowany. Zasugerowana odpowiedź będzie <code class="code-inline">yes</code>, ale my wpisujemy <code class="code-inline">no</code>.
+</p>
+<pre class="code-block">
+Is the disk partition already mounted? [yes] no
+</pre>
+<p>
+Następnie zostanie nam wyświetlona lista dysków (jak do wyboru dysku systemowego) wraz z zapytaniem, który z dysków zawiera pliki instalacjyne.
+</p>
+<pre class="code-block">
+Available disk are: wd0 wd1.
+Which disk contains the install media? (or 'done') [wd0]
+</pre>
+<p>
+W moim przypadku z racji tego iż uruchamiam to na QEMU obraz dysku instalacjnego jest pierwszym dyskiem na mojej maszynie. Po wybraniu dysku zostanie wyświetlona nam list partycji
+</p>
+<pre class="code-block">
+ a:    1358848         1024    4.2BSD  2048 16384 16142
+ i:        960           64     MSDOS
+Available wd0 partitions are: a i.
+Which wd0 partition has the install sets? (or 'done') [a]
+</pre>
+<p>
+Partycja z plikami instalcyjnymi jest sformatowana jako <strong>4.2BSD</strong>, i zgodnie z sugestią instalatora wybierzemy partycję oznaczoną literą 'a'. Teraz partycja zostanie przeszukana pod kątem plików instalacyjnych, o znalezieniu plików instalcyjnych zostaniemy poinformowani w sugestii instalatora na odpowiedź poniższego pytania.
+</p>
+<pre class="code-block">
+Pathname to the sets? (or 'done') [6.5/amd64]
+</pre>
+<p>
+Akceptujemy znalezioną ścieżke. Jeśli instalujemy system z płyty instalator od razu zacznie szukać ścieżki, co spowoduje przeskok do powyższego pytania.
+</p>
+<p>
+Teraz możemy wybrać jakie pakiety chcemy zainstalować. Warto wszystkie. Dlaczego? Otóż, nie które z programów uruchamianych w konsoli mogą używać czcionek, które dostępne są w pakietach ze środowiskiem graficznym. Nikt nam nie każe uruchamiać środowiska ze startem systemu jak i ręcznie, ale te pakiety warto posiadać. Czasami uruchomienie środowiska może usprawnić pracę.
+</p>
+<img src="https://i.ibb.co/BZQggnX/instalacja-openbsd-0.png" style="width: 100%;" />
+<p>
+Po zatwierdzeniu zbioru pakietów, zostaniemy poinformowani o tym że na ścieżce nie znaleziono pliku z podpisem oryginalności plików instalacyjnych (dla paranoików). Na tym etapie możemy to zignorować i odpowiedzieć
+czy chcemy kontynuować bez weryfikacji <code class="code-inline">yes</code>.
+</p>
+<pre class="code-block">
+Directory does not contain SHA256.sig. Continue without verification? [no] yes
+</pre>
+<p>
+Po zakończonej instalacji, instalator znów zapyta nas o położenie plików instalacyjnych, teraz będzie sugerować <code class="code-inline">done</code>, warto posłuchać tej sugestii.
+</p>
+<pre class="code-block">
+Location of sets? (cd0 disk http or 'done') [done]
+</pre>
+<p>
+Ostatnimi komunikatami są miedzy innymi pytanie o ustawienie poprawnej daty oraz czasu.
+</p>
+<pre class="code-block">
+Time appears wrong. Set to 'Fri Apr 24 22:04:05 CEST 2020'? [yes]
+</pre>
+<p>
+Na sam koniec otrzymamy gratulacje odnośnie poprawnie zainstalowanego systemu oraz pytanie czy chcemy system zatrzymać (tak jak kiedyś na startych Windowsach, po zatrzymaniu systemu należy nacisnąć lub przytrzymać wyłącznik komputera tak samo jest z OpenBSD, kiedy wybierzemy polecenie <code class="code-inline">halt</code>), przejść do powłoki albo z resetować komputer wybieramy sugerowany restart.
+<code class="code-inline">reboot</code>.
+</p>
+<code class="code-block">
+Exit to (S)hell, (H)alt or (R)eboot? [reboot]
+</code>
+<p>
+Usuwamy nośnik i możemy cieszyć się nowym system OpenBSD.
+</p>
+<p>
+Odnośnie instalacji OpenBSD, to nie zawsze wszystko wygląda tak różowo. Instalacja na starych firmowych systemach takich jak Dell Optiplex GX620 przynosi rezultaty. Ale np. instalacja na komputerze PC, ktory był budowany przeze mnie od podstaw już nie. Na płycie Gigabyte z podstawką 1156, to włożnie pendrive-a do gniazda USB potrafi zawiesić cały komputer już na procedurze POST. Przy np. płycie MSI z podstawką 1150 system może się zainstalować ale po zainstalowaniu komputer zawiesza się na procedurze POST, odpięcie dysku SSD powodowało że komputer uruchamiał się poprawnie, jednak jeśli chciałem coś zrobić z tym komputerem musiałem wymontować dysk oraz podłączyć go na USB do innego systemu wyzerować początek i podłączyć z powrotem, bardzo irytujące. Nie wiem czy to jest wina tylko tej wersji bo próbowałem z wersją 6.8 na dzień dziejszy (23.02.2021) najnowszą. Jednak na laptopach nie ma takich problemów, dlatego laptop wydaje się najlepszym rozwiązaniem. Jednak te słowa pisze na Laptopie z OpenBSD wykorzystującym środowisko graficzne Fluxbox, chciałem mieć tu XFCE jednak podczas działania XFCE grafika (ATI Radeon) strasznie "glitch'owała", to nie wina sprzetu (bo xenodm, czy wymieniony wcześniej Fluxbox działają wyśmienicie) ale wydaje mi się że jest to wina wadliwego sterownika a te środowiska wykorzystują grafikę w znikomy sposób. Wnioskując dla OpenBSD nalepszy jest poleasingowy laptop z procesorem drugiej lub trzeciej genereacji oraz grafiką Intel HD Graphics.
+</p>
+<p>
+       ~xf0r3m
+</p>
+</div>
+<p class="footer">
+       2021; COPYLEFT; ALL RIGHTS REVERSED;
+</p>
+               </body>
+       </html>
diff --git a/articles/hardware/apple_macbook_a1181.html b/articles/hardware/apple_macbook_a1181.html
new file mode 100755 (executable)
index 0000000..710c042
--- /dev/null
@@ -0,0 +1,236 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+    __  __               __                       
+   / / / /___ __________/ /      ______ _________ 
+  / /_/ / __ `/ ___/ __  / | /| / / __ `/ ___/ _ \
+ / __  / /_/ / /  / /_/ /| |/ |/ / /_/ / /  /  __/
+/_/ /_/\__,_/_/   \__,_/ |__/|__/\__,_/_/   \___/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Apple Macbook A1181</h1>
+      <p>
+        Poliwęglanowy Macbook A1181 zadebiutował w 2006 roku i był to
+        pierwszy komputer przenośny firmy Apple z procesorem Intela. Swój
+        egzemplarz nabyłem podkoniec 2018 roku od kolegi za małe pieniądze.
+        Czy jednak używanie komputera z 2007 (moj MacBook, to Mid 2007) ma
+        sens? Wszystko zależy od oprogramowania. Na początku jednak kilka
+        informacji o sprzęcie.
+      </p>
+      <h2>Sprzęt</h2>
+      <p>
+        Komputer gdy go dostałem wyposarzony był w Core2Duo T7400 o taktowaniu
+        2.16GHz, 2GB DDR2 oraz 120GB dysk twardy. Łączność bezprzewodową 
+        zapewnia Apple Airport Extreme 802.11a/b/g/n z odblokowanym domyślnie
+        standardem <em>n</em>, we wcześniejszych wersjach ten standard był
+        wyłączony. Ekran to błyszcząca matryca LCD o przekątnej 13,3" i
+        rozdzielczości 1280x800. Potrzymaniu tego laptopa, postanowiłem że
+        rozszerze mu ilości RAM zamieniając te 1GB kości na 2GB. Niestety mimo
+        iż komputer sprzętowo przyjął te kości, to w systemie widoczne było
+        tylko 3GB. Inną wadą tego sprzętu było mocowanie dysku twardego. Dysk
+        miał swoją ramkę, do niej mocowany był za pomocą dwóch zestawów śrubek
+        na <em>torx</em>. Nigdy nie wiedziałem, które śrubki idą gdzie czy 
+        z przodu czy z tyłu. Dysk wjeżdzał w ramce do obudowy w takie gumki. Te
+        gumki były przyklejone do obudowy i przy pewnej zmianie dysku jedna z tych
+        gumek się odkleiła i trzeba było go całego rozebrać, żeby ją wyciągnąć.
+        Plusem, tego komputera jego rozbieranie. Aby dostać się do płyty
+        głównej, trzeba okręcić 25 śrubek (11 na zewnątrz, 10 wewnątrz
+        [pod baterią] + maskownica pamięci RAM i dysku) na koniec lekko
+        wypchnąć od spodu palmrest i już. Komputer otwarty. Nie wspomniałem 
+        tutaj o napędzie. Jest to napęd szczelinowy, nie posiada tacki. Płyty
+        wysuwa się w szczelinę i wysuwa przyciskiem na klawiaturze, w moim
+        egzemplarzu napęd chyba niechce coś współpracować. Nie czyta płyt
+        ale to chyba normalne dla tych sprzętów kupionych jako używane. Dlatego
+        o nim wspomniałem wscześniej. Klawiatura wygodna, w moim przypadku
+        prawdopodobnie szwedzka. Nie dawno ją przekleiłem. Jakiś czas temu
+        kupiłem drugi egzemplarz, na części i jedyne co wymieniłem to
+        taśma palmrestu. Oryginalna źle się złożyła podczas zamykania obudowy
+        i zmieniając RAM uszkodziłem jedną ścieżkę, a jej wymiana nie była
+        trudna, ponieważ pod szarą maskownicą elektroniki gładzika znajdowało
+        się złącze taśm znane z innych laptopów, wystarczyło wyciągnąć 
+        uszkodzoną taśmę, wsunąć nową i zamknąć złącze.  
+      </p>
+      <h2>Wygląd</h2>
+      <p>
+        Kształt komputera jest bardzo elegancji jak firmę z jabłkiem w logo 
+        przystało. Komputery te wychodziły w dwóch wariantach kolorystycznych
+        czarnym oraz białym. Komputery na klapie matrycy były opatrzone
+        podświetlanym logo. Logo akurat w tym modelu nie świeciło, aż tak
+        mocno aby prześwietlać się przez matrycę podczas wyświetlania 
+        ciemniejszego obrazu.
+        Do okołą matrycy znajduje się prawie centymetrowa ramka na której
+        znajdują się stopki dystansujące matrycę od klawiatury. Niestety
+        praktyka pozkazała, że są one z niskie klawiatura może się po poprostu 
+        odbić na matrycy. Na środku górnej części ramki znajduje się kamera
+        <em>iSight</em>. Na palmreście znajduje się przycisk włącznika,
+        klawiatura oraz wyposażony w jeden przycisk gładzik znajdujący się 
+        mniej więcej na środku
+        palmrestu. Na froncie kadłubka znajduje się dioda sygnalizująca
+        uruchomienie systemu lub jego przejście w stan wstrzymania, po lewej 
+        stronie znajdują się dostępne w MacBook-u złącza takie jak:
+      </p>
+      <ul>
+        <li>Złącze zasilania MagSafe</li>
+        <li>Gigabitowy Ethernet</li>
+        <li>Mini DVI</li>
+        <li>FireWire o przepustowowści do 400 Mb/s</li>
+        <li>Dwa USB 2.0</li>
+        <li>Złącze mikrofonu/wejście audio</li>
+        <li>Złącze słuchawkowe/wyjście audio</li>
+        <li>Kensington Lock</li>
+      </ul>
+      <p>
+        Po prawej stronie znajduje się szczelina do odtwarzacza płyt, a z tyłu
+        głośniki oraz wylot powietrza z CPU. Pod spodem znajdziemy baterię oraz jej 
+        blokadę. Baterie w tych wersjach sprzętu Apple posiadają wskaźnik
+        naładowania. Teraz trochę o bublach projektowych. Te MacBooki mają w 
+        palmrestach za krótki
+        punkt styku z kadłubkiem co powoduje charakterystyczne dla tego modelu
+        dziury, szczeliny w miejscah gdzie spoczywają nasze nadgarstki. Wygląda
+        to co najmniej jest nie estetyczne. W białej 
+        wersji mocno widać zużycie błyszczącego poliwęglanu: zdrapania, otarcia
+        zabrudzenia, złacza znajdują się w zagłebieniach, których przez lata
+        korzystania gromadzić się będzie brud. Pozostawienie tego laptopa na
+        słoneczku może spowodować jego zżółknięcie. Mój egzemplarz posiada
+        kilka naklejek na klapie (a ja z chęcią przykleił bym jeszcze jedną 
+        przy wylocie powietrza "Uwaga! Gorące. Nie dotykać.") oraz błekitny 
+        nieco już zużyty 
+        <em>hardcase</em>. Nie dokupowałem go i dostałem go wraz z laptopem.
+        Obcenie coś takiego dla tego modelu, można dostać jedynie w Chinach 
+        przez internet.
+      </p>
+      <h2>Firmware</h2>
+      <p>
+        Sprzęt Apple jak wiemy lub nie, nie posiada tradycjnego BIOS-u, a
+        firmware, do którego się raczej nie dostaniemy. Cechą charakterystyczną
+        tego rozwiązania jest użycie 32-bitowego UEFI. Jest to cenna wskazówka
+        jeśli chcemy zainstalować inny system operacyjny niż MacOS 10.6 Snow
+        Leopard.
+      </p>
+      <h2>System operacyjny</h2>
+      <p>
+        Chcąc skorzystać z tego komputera należy zastanowić się nad tym z
+        jakiego systemu operacyjnego możemy tutaj użyć. W grę może wchodzić 
+        kilka rozwiązań, większość jednak to rozwiązania oparte na Linuksie. 
+        Niestety
+        ze względu na wymienione powyżej UEFI 32-bitowe przed przegraniem 
+        obrazu na pendrive, dysk należy na początku przygotować. Na początku
+        chcę zobaczyć jak ten komputer poradzi sobie z <em>immudex</em>
+        (moją wersją Debiana 11 - 
+        <a href="https://github.com/xf0r3m/immudex">https://github.com/xf0r3m/immudex</a>).
+        Jeśli coś będzie nie tak, wtedy będę szukać alternatyw (oczywiście 
+        rozsądnych coś na opartego na Debianie lub Arch-u)
+        Na oficjalnej stronie Debiana znajduje się poradnik w jaki sposób 
+        należy przygotować dysk:
+        <a href="https://wiki.debian.org/InstallingDebianOn/Apple/MacBook/2-1">https://wiki.debian.org/InstallingDebianOn/Apple/MacBook/2-1</a>.
+        Jak możemy się domyślić przedstawione na stronie metody, dotyczą
+        obrazu <em>mini.iso</em> Debiana. Ja chcąc uruchomić <em>immudex</em>
+        muszę dostosować te konfigurację. Dużym plusem jest fakt iż moja 
+        dystrybucja korzysta rownież korzysta z GRUB dla zapewnienia
+        kompatybilności z systemami opartymi wyłącznie na UEFI. Więc co muszę 
+        zmienić w konfiguracji dla Debiana aby uruchomić <em>immudex</em>. 
+        Pierwszą rzeczą jest utworzenie dodatkowego katalogu na pendrivie,
+        który musi nazywać się <em>live</em>, wówczas moduł załadowany do 
+        <em>initrd</em> będzie wstanie odnaleźć archiwum <em>squashfs</em> i 
+        użyć go 
+        jako katalogu głównego. Po utworzeniu tego katalogu kopiuje do niego 
+        archiwum <em>squashfs</em>. Następnie dopisuje kilka opcji jądra, te
+        same, które występują w pliku konfiguracyjnym GRUB dla 64-bitowego 
+        UEFI (<a href="https://github.com/xf0r3m/immudex/blob/main/grub/amd64/grub.cfg">https://github.com/xf0r3m/immudex/blob/main/grub/amd64/grub.cfg</a>)
+        linia nr. 19 opcja o nazwie <code class="code-inline">linux</code> w
+        celach testowych pominąłem opcję <code class="code-inline">quiet</code>,
+        aby widzieć czy i jak ładuje się system. Po załadowaniu systemu działa
+        <em>ethernet</em>, działa dźwiek czy Wi-Fi. Pasek nie mieści się na
+        na ekranie, ale tym zajął bym się dopiero jeśli chciałbym (albo raczej 
+        musiał) korzystać z tego komputera. Po załadowaniu systemu przyszedł
+        czas na jego instalację. Instalując swoją dystrybucję na tym komputerze
+        zasugerowałem się skryptem instalacji <em>immudex_install</em>
+        dołączonym do obrazu. Istotne są tutaj dwie czynności. Pierwsza z nich
+        to ręczna instalacja binariów GRUB dla 32-bitowego UEFI 
+        (pakietu: <em>grub-efi-ia32-bin</em>) ze względu na to, wymagana będzie
+        również zmiana <em>targetu</em> w poleceniu instalującym GRUB z 
+        <code class="code-inline">x86_64-efi</code> na
+        <code class="code-inline">i386-efi</code>. Drugą istotną rzeczą jest
+        pobranie pliku konfiguracjnego GRUB, dokładnie tego, który został
+        użyty do konfiguracji zmiany konfiguracji GRUB podczas tworzenia dysku
+        USB, z którego ładowany był system. Możemy przpisywać ten długi adres,
+        jednak lepszym sposobem jest zaciągnięcie całego repozytorium z 
+        GitHub i skopiowanie pliku odpowiedniego pliku (w zależności od 
+        architektury, jednak różnią się one wyłącznie opisem opcji) do
+        katalogu <em>/media/boot/grub</em>. Po tej czynności możemy odmontować
+        wszystkie dyski i uruchomić komputer ponownie. W ten sposób uzyskamy 
+        zainstalowany <em>immudex</em> jak na każdym innym sprzęcie. A
+        instalacja na 32-bitowym EFI pojawi się w <em>immudex_install</em> 
+        w kolejnej wersji mojej dystrybucji.
+      </p>
+      <h2>Podsumowanie</h2>
+      <p>
+        Kiedy otrzymałem swój egzemplarz MacBook-a na początku korzystałem
+        z tego nieszczęsnego MacOS 10.6. Zainstalowałem tam Firefox 46, bo to 
+        był jedyny kompatybilny z tym systemem. Później stwierdziłem, że chcę
+        wgrać na niego jakąś dystrybucje Linuksa. Wybór mój padł na używaną
+        przeze mnie wówczas dystrybucję jaką był MX Linux. Odziwo MX Linux
+        załadował się z obrazu utworzonego na Windowsie więc musiał natywnie
+        wspierać 32-bitowe EFI, poźniej z racji tego, że uwielbiam Debiana 
+        próbowałem klasycznie za pomocą <em>dd</em> wgrać obraz na pendrive i 
+        go z niego
+        uruchomić po stracie całego popołudnia trafiłem na artykuł na 
+        <em>wiki.debian.org</em>. Potem kolejno instalacja <em>greenOS</em> teraz 
+        <em>immudex</em> już szła z górki. W między czasię pojawił się
+        <em>Arch Linux</em> oraz <em>Parabola GNU/Linux-libre</em> one również
+        udało się na nim zainstalować. Wracając jednak do pytania zadanego na
+        wstępie tego materiału, czy warto korzystać z komputera z 2007 roku 
+        obecnie. Komputer ten może być dobrym wyborem dla hakera dbającego o
+        swoją prywatność, ten komputem nie posiada bowiem Intel ME, posiada z
+        za to gigabitowy <em>ethernet</em> oraz bardzo wydajną kartę sieci
+        bezprzewodowej, gdzie przy pełnym zasięgu można było wyciągnąć 25MB/s
+        pobierając jeden plik z serwera w sieci lokalnej. Mój egzemplarz
+        posiada oryginalną baterię, nie znam jej przeszłości czy była
+        wymienia czy nie ale nadal potrafi trzymać 3-4h. Dodam iż komputer ma 
+        15 lat. Mi osobiście podoba się wyświetlany przez matrycę obraz, jest 
+        naprawdę bardzo ładny. Dużym minusem jest jego nagrzewanie się. 
+        Tem komputer
+        nie jest tylko ciepły (wręcz gorący) przy wylocie powietrza z
+        chłodzenia CPU, ale także z lewej strony palmrestu nad portami również
+        jest bardzo ciepły, a jeśli korzystam z sieci bezprzewodowej to będzie
+        on gorący również pod WSAD-em. Jednak na to ciepło może zaradzić 
+        najtańsza podstawka chłodząca (sam byłem w szoku gdy podstawce z sieci
+        marketów z uśmiechniętym owadem w logo za całe 20zł udało się go 
+        schodzić. Udało się schodzić plastik i to zrobiło robotę ponieważ nie 
+        ma tam żadnej wentylacji). Dla kogoś równie istotny może być jego 
+        ciężar, bo komputer jest dość cięzki. A tak poza tym to można na nim 
+        śmiało oglądać filmiki z 
+        YT poza YT w maksymalnie 360p. Przejrzeć proste stronki, choć tu warto
+        mieć adbloka. Powiem tak jeśli mamy zamiar korzystać z niego na biurku
+        na podstawce wykorzystać do programowania lub podstaw nauki Linuksa i
+        posiadamy dużą ilość cierpliwości to odpowiedź, brzmi: Tak, jak
+        najbardziej tylko trzeba mieć wszystkie rzeczy na uwadze. Przeglądarka
+        to wyłącznie Firefox z adblokiem i noscriptem z włączoną ścisłą 
+        ochroną lub GNU IceCat. Maile to tylko jakiś lekki klient, jak 
+        np. ClawsMail lub terminalowy mutt. Jeśli DE (środowisko graficzne) to 
+        najlepiej fluxbox lub openbox. Jeśli chcecie mieć coś "hakerskiego" i 
+        akurat wpadło wam to w ręce za naprawdę śmieszne pieniądze to moim 
+        zdaniem wystarczy. Jeśli macie zamiar to kupić to lepiej, już
+        zainwestować w Della Latitude z serii E z C2D lub IBM/Lenovo Thinkpad.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/hardware/index.html b/articles/hardware/index.html
new file mode 100755 (executable)
index 0000000..6167b0a
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+    __  __               __                       
+   / / / /___ __________/ /      ______ _________ 
+  / /_/ / __ `/ ___/ __  / | /| / / __ `/ ___/ _ \
+ / __  / /_/ / /  / /_/ /| |/ |/ / /_/ / /  /  __/
+/_/ /_/\__,_/_/   \__,_/ |__/|__/\__,_/_/   \___/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <ul class="special_list">
+        <a href="apple_macbook_a1181.html">Apple Macbook A1181</a>
+                       </ul>
+               </div>
+
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/immudex/aktualizacja_immudex.html b/articles/immudex/aktualizacja_immudex.html
new file mode 100755 (executable)
index 0000000..69bcf07
--- /dev/null
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Aktualizacja immudex</h1>
+                 <p>
+        <em>Immudex</em> ze względu na to, że jest system wydawanym na zasadzie
+        LiveCD, jego najważniejsze elementy jak: jądro, <em>initrd</em> oraz
+        archiwum <em>squashfs</em> pozostają stałe. Aktualizacji dokonuje
+        się poprzez ich wymianę na miejscu docelowym. W zależności 
+        od rodzaju instalacji można wgrać nowy obraz na dysk lub zmienić te 
+        pliki na partycji utworzonej podczas instalacji.
+      </p>
+      <p>
+        <em>Immudex</em> w wersji stablinej nie jest wydawany regularnie.
+        Posiada on trzy powody do wydania nowej wersji: Aktualizacja jądra,
+        poważna zmiana (potrzeba dołączenia jakiegoś narzędzia/programu,
+        wykrycie/naprawa błędu w jednym z narzędzi) lub
+        duża ilość pakietów do aktualizacji. Inaczej jest w przypadku wersji
+        testowej, gdzie wydania publikowane są regularnie co tydzień w sobotę.
+      </p>
+      <p>
+        Aktualizacji możemy dokonać dwa sposób albo ręcznie, albo automatycznie
+        wykorzystując do tego narzędzie <strong>immudex_upgrade</strong>.
+        Warto jednak zaznaczyć, że wybierając opcją automatyczą to może ona
+        się nie powieźć, jeśli używaliśmy autorskiego archiwum 
+        <em>squashfs</em> i jego wielkość przekracza 2GB. Wówczas należy
+        dokonać ręcznie poprzez uruchomienie komputera z pamięci USB.
+      </p>
+      <p>
+        Po zalogowaniu się użytkownika do systemu zostanie wyświetlone mu
+        powiadomienie o tym czy jest dostępna nowa wersja <em>immudex</em>.
+        Dostępność nowej sprawdzana jest na zasadzie wersji zapisanej w
+        aktualizacji na serwerze dystrybującym system. Porównywane są
+        wartości z pliku lokalnego (na dysku) i pliku zadalnego (na serwerze).
+      </p>
+      <h2>Aktualizacja ręczna</h2>
+      <p>
+        W przypadku ręcznej aktualizacji należy pobrać obraz z jednego z
+        serwerów:
+      </p>
+      <ul>
+        <li><a href="https://ftp.morketsmerke.org/immudex">https://ftp.morketsmerke.org/immudex</a></li>
+        <li><a href="https://sourceforge.net/project/immudex">https://sourceforge.net/project/immudex</a></li>
+      </ul>
+      <p>
+        Załadować go na pamięć USB lub wypalić na płycie.
+      </p>
+<pre class="code-block">
+$ sudo dd if=immudex64.iso bs=1M of=/dev/sdX status=progress
+</pre>
+      <p>
+        Po załadowaniu obrazu na nośnik, uruchamiamy z niego komputer. Po
+        uruchomieniu systemu musimy podmontować partycję z systemem. Przeważnie
+        jest pierwsza partycja lub druga partycja na dysku (w trybie UEFI)
+      </p>
+<pre class="code-block">
+$ sudo mount /dev/sdX1 /mnt
+</pre>
+      <p>
+        Następnie usuwamy zawartość katalogu <em>live</em>.
+      </p>
+<pre class="code-block">
+sudo rm -rf /mnt/live/*
+</pre>
+      <p>
+        Teraz należy skopiować zawartość katalogu <em>live</em> na obrazie.
+        Katalog ten jest montowany w dwóch miejscach: <em>/run/live/medium/live</em>
+        lub <em>/usr/lib/live/mount/medium/live</em>.
+      </p>
+<pre class="code-block">
+sudo cp /run/live/medium/live/* /mnt/live;
+</pre>
+      <p>
+        Po wykonaniu tych czynności możemy odmontować partycję z system a
+        następnie zrestartować komputer. System uruchomi się ponownie, ale już
+        za pomocą <em>immudex</em> w najnowszej wersji.
+      </p>
+      <h2>Aktualizacja automatyczna</h2>
+      <p>
+        Aktualizacja automatyczna sprowadza się w zasadzie do jednego
+        polecenia. Bowiem narzędzie <strong>immudex_upgrade</strong> posiada
+        opcję <em>--upgrade</em>, która sprawdzi dostępność nowej wersji, a
+        następnie po potwierdzeniu przez użytkownika rozpocznie proces
+        aktualizacji.
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ immudex_upgrade --upgrade
+New version (0.1.9) of immudex is available.
+Warning, reboot maybe necessary to continue work on this machine
+Do you want upgrade this system? (y/n): y
+Upgrading immudex to the newest version...[ OK ]
+</pre>
+      <p>
+        Po wykonaniu tej czynności najlepiej jest wykonać ponowny rozruch
+        komputera.
+      </p>
+      <p>
+        <span class="warn-sign warning">&#9888;</span>
+        Uwaga! Próba automatycznej aktualizacji może się zakończyć
+        niepowodzeniem jeśli korzystamy z niestandardowego obrazu, którego
+        rozmiar przekaracza 2GB.
+      </p> 
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/immudex.html b/articles/immudex/immudex.html
new file mode 100755 (executable)
index 0000000..fcbf37c
--- /dev/null
@@ -0,0 +1,240 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">IMMutable DEbian with Xfce</h1>
+      <p>
+        <strong>Aktualności:</strong>
+      </p>
+      <ul>
+        <li>
+          25.07.2023 - Uwaga! Od poniedziałku (31.07) godziny 18:00 do wtorku
+          (01.08) godziny 07:00 dostęp do searx.morketsmerke.org (silnik 
+          wyszukiwania, strona startowa firefox-a) może być ograniczony ze 
+          kwzględu na prowadzone w tym czasie prace konserwatorskie.
+        </li>
+        <li>
+          11.06.2023 - Uwaga! Od wersji 1.0.0, immudex będzie wymagać min. 6GB
+          wolnego miejsca na dysku.
+        </li>
+      </ul>
+      <p>
+        <strong>O dystrybucji:</strong>
+      <p>
+      <p>
+        Immudex to wersja debian zawierająca niezmienne środowisko pracy.
+        Wykorzystuje ona bowiem archiwum .squashfs znane z LiveCD. Przyczym 
+        pozwala ona na pełen dostęp do partycji zawierające archiwum, w razie
+        aktualizacji. Tak przygotowana wersja popularnego systemu operacyjnego
+        pozwoli bezpieczniejsze korzystanie z komputera oraz zasobów internetu.
+        Jeśli coś się stanie, wystarczy uruchomić komputer ponownie.
+      </p>
+      <p>
+        Immudex nastawiowny jest na wykorzystanie do przechowywania danych 
+        szyfrowanych partycji za pomocą mechanizmu LUKS. Domyślnie
+        przeglądarka WWW (<em>firefox-esr</em>) uruchamiany jest przez
+        sandboxer FireJail z własną emulacją stosu TCP/IP. Tak uruchomiana
+        przeglądarka nia posiada dostępu do otwartych szyfrowanych partycji.
+        Immudex tworzony jest również z myślą o nie narzucaniu rozwiązań
+        dlatego też wiele z nich można w łatwy sposób pominąć, oczywiście na
+        własną odpowiedzialność. W więcej informacji na temat rozwiązań w
+        Immudex znajduje się w artykule "Koncepcje immudex" na stronie z
+        dokumentacją systemu. Wszelkie połączenia przychodzące do są 
+        zablokowane poprzez firewall <em>ufw</em>.
+      </p>
+      <p>
+        <strong>Oprogramowanie:</strong>
+      </p>
+      <p>
+        Immudex domyślnie korzysta z wolnego oprogramowania, nie zainstalowano
+        na nim niewolnych pakietów w konfiguracji nie ma również niewolnych 
+        repozytoriów.
+      </p>
+      <p>
+        Oficjalnie immudex wspiera instalację
+        niewolnego oprogamowania wyłącznie w postacji <em>addonsów</em>
+        dostępnych w postacji samodzielnych skryptów na repozytorium projektu
+        lub poprzez narzędzie <em>immudex_addons</em>. Do dyspozycji mamy:
+      </p>
+      <table>
+        <thead>
+          <tr>
+            <th rowspan="2">Oprogramowanie</th>
+            <th colspan="3" class="centered-text">Wersja immudex</th>
+          </tr>
+          <tr>
+            <th class="centered-text">Stable</th>
+            <th class="centered-text">Testing</th>
+            <th class="centered-text">LHE*</th>
+          </tr>
+        </thead>
+        <tbody>
+        <tr>
+          <td>Środowisko XFCE</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2716;</td>
+        </tr>
+        <tr>
+          <td>Menadżer okien Ratpoison</td>
+          <td class="centered-text">&#x2716;</td>
+          <td class="centered-text">&#x2716;</td>
+          <td class="centered-text">&#x2714;</td>
+        </tr>
+        <tr>
+          <td>Odtwarzacz multimedialny VLC</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2716;</td>
+        </tr>
+        <tr>
+          <td>Odtwarzacz multimedialny mpv</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+        </tr>
+        <tr>
+          <td>Skrypt yt-dlp</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+        </tr>
+        <tr>
+          <td>Przeglądarka Mozilla Firefox ESR</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2716;</td>
+        </tr>
+        <tr>
+          <td>Przeglądarka GNU IceCat</td>
+          <td class="centered-text">&#x2716;</td>
+          <td class="centered-text">&#x2716;</td>
+          <td class="centered-text">&#x2714;</td>
+        </tr>
+        <tr>
+          <td>Wirtualizacja KVM (libvirtd + virt-manager):</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2716;</td>
+        </tr>
+        <tr>
+          <td>Narzędzia autorskie immudex:</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+          <td class="centered-text">&#x2714;</td>
+        </tr>
+        </tbody>
+      </table>
+      <p>
+        <em>* - Low Hardware Edition, Debian 10 Buster, 32-bit</em>
+      </p>
+      <p>
+        Pełna lista oprogramowania wraz z listą pakietów z znajduje się w 
+        pod tym linkiem: 
+        <a href="lista_oprogramowania_immudex.html">Lista oprogramowania immudex</a>
+      </p>
+      <p>
+        <strong>Obrazy płyt:</strong>
+      </p>
+      <table border="1" style="border-collapse: collapse;">
+        <tr>
+          <th colspan="3">&bull;&nbsp;immudex (stable, Debian 12 Bookworm)&nbsp;&bull;</th>
+        </tr>
+        <tr>
+          <td rowspan="2">64-bit:</td>
+          <td colspan="3"><a href="https://ftp.morketsmerke.org/immudex/stable/iso/1.0.1/immudex64.iso">https://ftp.morketsmerke.org/immudex/stable/iso/1.0.1/immudex64.iso</a></td>
+        </tr>
+        <tr>
+          <td>CRC: 820814467</td>
+          <td>SHA1: 458a7faf88608cdce99f44c39af94233d8c6e478</td>
+        </tr>
+        <tr>
+          <td rowspan="2">32-bit:</td>
+          <td colspan="3"><a href="https://ftp.morketsmerke.org/immudex/stable/iso/1.0.1/immudex32.iso">https://ftp.morketsmerke.org/immudex/stable/iso/1.0.1/immudex32.iso</a></td>
+        </tr>
+        <tr>
+          <td>CRC: 3072989609</td>
+          <td>SHA1: e59a08ff192f0ca092a30f6ecf69c7f8af5a9612</td>
+        </tr>
+        <tr>
+          <td colspan="3">&bull;&nbsp;<a href="https://github.com/xf0r3m/immudex/blob/main/changelogs/1.0.1.txt">Lista zmian dla wydania</a></td>
+        </tr>
+        <tr>
+          <th colspan="3">&bull;&nbsp;immudex-testing (Debian testing, 13 Trixie)&nbsp;&bull;</th>
+        </tr>
+        <tr>
+          <td rowspan="2">64-bit:</td>
+          <td colspan="3"><a href="https://ftp.morketsmerke.org/immudex/testing/iso/1.0.5/immudex-testing64.iso">https://ftp.morketsmerke.org/immudex/testing/iso/1.0.5/immudex-testing64.iso</a></td>
+        </tr>
+        <tr>
+          <td>CRC: 820814467</td>
+          <td>SHA1: 458a7faf88608cdce99f44c39af94233d8c6e478</td>
+        </tr>
+        <tr>
+          <td rowspan="2">32-bit:</td>
+          <td colspan="3"><a href="https://ftp.morketsmerke.org/immudex/testing/iso/1.0.5/immudex-testing32.iso">https://ftp.morketsmerke.org/immudex/testing/iso/1.0.5/immudex-testing32.iso</a></td>
+        </tr>
+        <tr>
+          <td>CRC: 3072989609</td>
+          <td>SHA1: e59a08ff192f0ca092a30f6ecf69c7f8af5a9612</td>
+        </tr>
+        <tr>
+          <td colspan="3">&bull;&nbsp;<a href="https://github.com/xf0r3m/immudex-testing/blob/main/changelogs/1.0.5.txt">Lista zmian dla wydania</a></td>
+        </tr>
+        <tr>
+          <th colspan="3">&bull;&nbsp;immudex-lhe (oldoldstable, Debian 10 Buster)&nbsp;&bull;</th>
+        </tr>
+        <tr>
+          <td rowspan="2">32-bit:</td>
+          <td colspan="3"><a href="https://ftp.morketsmerke.org/immudex/lhe/iso/0.0.0/immudex-lhe32.iso">https://ftp.morketsmerke.org/immudex/lhe/iso/0.0.0/immudex-lhe32.iso</a></td>
+        </tr>
+        <tr>
+          <td>CRC: 3072989609</td>
+          <td>SHA1: e59a08ff192f0ca092a30f6ecf69c7f8af5a9612</td>
+        </tr>
+        <tr>
+          <td colspan="3">&bull;&nbsp;<a href="https://github.com/xf0r3m/immudex-testing/blob/main/changelogs/1.0.5.txt">Lista zmian dla wydania</a></td>
+        </tr>
+      </table>
+      <p>
+        Domyślnym użytkownikiem jest <strong>user</strong>, dostęp to niego 
+        uzyskujemy za pomocą hasła <em>user1</em>. Możemy również skorzystać z
+        konta superużytkownika <em>root</em> z hasłem <em>toor</em>.
+      </p>
+      <p>
+        <strong>Dokumentacja projektu:</strong>
+      </p>
+      <p>
+        Dokumentacja systemu znajduje się pod tym linkiem: <a href="https://morketsmerke.github.io/articles/immudex/index.html">Dokumentacja immudex</a>.
+      </p>
+      <p>
+        <strong>Zastrzeżenia i uznanie autorstwa:</strong>
+      </p>
+      <p>
+        immudex is not affiliated with Debian. Debian is a registered trademark
+        owned by Software in the Public Interest, Inc.
+      </p>
+      <p>
+        <a href="https://www.flaticon.com/free-icons/rss">Rss icons created by Freepik - Flaticon</a> 
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/index.html b/articles/immudex/index.html
new file mode 100755 (executable)
index 0000000..ce9c601
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <ul class="special_list">
+      <li><a href="koncepcje_immudex.html">Koncepcje immudex</a></li>
+      <li><a href="instalacja_systemu.html">Instalacja immudex</a></li>
+      <li><a href="aktualizacja_immudex.html">Aktualizacja immudex</a></li>
+      <li><a href="plik_wersji.html">Skrypt aktualizacji - plik wersji</a></li>
+      <li><a href="ingerencja_w_obraz_immudex_-_przewiniecie.html">
+        Ingerencja w obraz immudex - przewinięcie</a></li>
+      <li><a href="instalacja_sterownika_dla_Nvidia_GF_920M.html">
+        Instalacja sterownika dla Nvidia GeForce 920M</a></li>
+      <li><a href="odtworzenie_srodowiska_budowania_immudex_z_LiveCD.html">
+        Odtworzenie środowiska budowania immudex z LiveCD</a></li>
+      <li><a href="transformacja_gnu_linux_debian_w_immudex.html">
+        Transformacja GNU/Linux Debian w immudex - budowanie</a></li>
+    </ul>
+       </div>
+
+       <p class="footer">
+               2023; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/immudex/ingerencja_w_obraz_immudex_-_przewiniecie.html b/articles/immudex/ingerencja_w_obraz_immudex_-_przewiniecie.html
new file mode 100755 (executable)
index 0000000..3b58c06
--- /dev/null
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Ingerencja w obraz immudex - przewinięcie</h1>
+                 <p>
+        Ze względu na specyfikę systemu immudex, może zajść potrzeba ingerencji
+        w jego obraz. Możemy dodać swoje ulubione oprogramowanie lub sterowniki
+        niezbędne do wygodnego korzystania z tej dystrybucji na naszym
+        komputerze. Przewinięcie głownie skupia się na ingerencji w archiwum
+        <strong>squashfs</strong>, które zawiera <em>rootfs</em> dystrybucji.
+      </p>
+      <p>
+        <span class="warn-sign notice">&#9888;</span>
+        Pro tip! Przewinięcia najlepiej dokonywać na systemie uruchomionym z 
+        pamięci USB lub płyty. Ponieważ zamontowane archiwum <em>squashfs</em>
+        nadal będzie zajmować miejsce na partycji mimo jego usunięcia, i nowe
+        archiwum może się nie skopiować ze względu na mała ilość miejsca na
+        dysku. Głównie będzie to mieć miejsce jeśli dotychczasowe archiwum
+        waży ponad 2GB.
+      </p>
+      <p>
+        Obsługa tego formatu plików, wymaga zainstalowanego w systemie
+        oprogramowania. Wersje <em>immudex</em> są w nie domyślnie wyposażone.
+        Więc czynności sprowadzają się głównie do wybrania dogodnego miejsca
+        (może być potrzebna większa ilość wolnego miejsca na dysku) i operacja
+        kilkoma poleceniami. Aby rozpocząć wprowadzanie zmian do obrazu musimy
+        go najpoczątku wypakować. Do wypakowania posłużymy się poleceniem
+        <strong>unsquashfs</strong>. 
+      </p>
+<pre class="code-block">
+$ sudo unsquashfs -d chroot /run/live/medium/live/filesystem.squashfs
+</pre>
+      <p>
+        Opcja <code class="code-inline">-d</code> służy wskazaniu katalogu, do
+        którego należy wypakować <em>rootfs</em>, jeśli folder nie istnieje to
+        zostanie utworzony. Następnie wskazujemy ścieżkę do archiwum
+        <em>squashfs</em>. Jeśli z jakiegoś powodu musimy nadpisać zawartość
+        istniejącego już katalogu, należy dodać opcję <strong>-f</strong>.
+      </p>
+      <p>
+        Aby rozpocząć wprowadzanie zmian do <em>rootfs</em>, należy zmienić
+        katalog główny obecnie uruchomionej powłoki. Tutaj warto się zatrzymać
+        i zastanować na tym jakie zmiany chcemy wprowadzić. Jesli jest to
+        dodanie jakiś pliku, instalacja dodatkowych pakietów. To zwykłe
+        przełączenie katalogu głównego powinno wystarczyć. Jednak jeśli w grę
+        wchodzi instalacja sterownika lub kompilacja nie których pakietów to
+        może być wymagana obecność interfejsów systemowych takich jak
+        <em>/dev</em>, <em>/proc</em> i tak dalej. Dlatego trzeba je
+        podmotować przed przełączeniem katalogu głównego.
+      </p>
+<pre class="code-block">
+/* w niektórych specyficznych przypadkach
+$ for i in /dev /dev/pts /proc /sys /run; do sudo mount -B chroot${i}; done
+*/
+$ sudo chroot chroot/ bash
+</pre>
+      <p>
+        Po zmianie katalogu głównego możemy dokonywać dowolnych zmian. Gdy
+        zakończymy już ich wprowadzanie, warto pamiętać o kilku czynnościach:
+      </p>
+      <ol>
+        <li>Utrzymaniu porządku w pakietach, za pomocą podpoleceń narzędzia
+          <strong>apt-get</strong>: <em>clean</em>, <em>autoremove</em> oraz
+          <em>autoclean</em> (głownie chodzi o pozbycie się pobranych pakietów
+          oraz tych już nie potrzebnych).</li>
+        <li>Usunięciu wszystkich plików roboczych (tych, które nie są już
+          potrzebne).</li>
+        <li>Usunięcie historii wprowadzanych poleceń. Jeśli przewaliśmy
+          działanie powłoki, to historia trafiła już do pliku, więc pomoć nam
+          może polecenie <code class="code-inline">echo &gt; ~/.bash_history</code>.
+          Gdy sesja powłoki jeszcze działa możemy wydać polecenie
+          <code class="code-inline">history -c</code>.</li>
+      </ol>
+      <p>
+        Oczywiście to tylko rady. Jeśli nie chcemy się do nich stosować nie
+        musimy. Ja stosuje je podczas wydawania nowych wersji <em>immudex</em>
+        (a przynajmnie staram się stosować).
+      </p>
+      <p>
+        Jeśli skończyliśmy wprowadzanie zmian, możemy spakować <em>rootfs</em>
+        do nowego pliku archiwum. Do tej czynności wykorzystamy polecenie
+        <strong>mksquashfs</strong>.
+      </p>
+<pre class="code-block">
+$ sudo mksquashfs chroot filesystem.squashfs -e boot
+</pre>
+      <p>
+        <span class="warn-sign warning">&#9888;</span>
+        Tutaj istotne jest aby archwium <em>squashfs</em> nazwywało się tak
+        jak podano na przykładzie <code class="code-inline">filesystem.squashfs</code>.
+        Program odpowiedzialny za obsługę sesji LiveCD <strong>live-boot</strong>
+        domyślnie szuka archiwym <em>squashfs</em> o takiej nazwie. Inne nazwy
+        <strong>nie będą</strong> działać.
+      </p>
+      <p>
+        Pierwszym argumentem jest wskazanie katalogu zawierającego 
+        <em>rootfs</em>, następnie podajemy nazwę archiwum. Podczas budowania
+        <em>immudex</em> wykorzystuje opcję <code class="code-inline">-e</code>,
+        aby program nie pakował plików jądra (one są potrzebne na zewnątrz).
+      </p>
+      <p>
+        Tak przygotowane archiwum może skopiować na dysk. Pamiętajmy jednak
+        o tym, że jeśli instalowane były dodatkowe modułu jądra 
+        (np. sterowniki), aktualizowane było jądro lub instalacje pakietów
+        mogły wpłynąć na obraz ram dysku (<em>initrd.img</em>) to należy
+        również skopiować pliki jądra. Jeśli nie mamy pewności czy nasze
+        czynności miały wpływ na te składniki systemu to najbezpieczniej jest
+        je wydobyć z <em>rootfs</em> i skopiować pod odpowiednimi nazwami
+        (<em>vmlinuz</em> - dla jądra oraz <em>initrd</em> - dla ram dysku).
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/instalacja_sterownika_dla_Nvidia_GF_920M.html b/articles/immudex/instalacja_sterownika_dla_Nvidia_GF_920M.html
new file mode 100644 (file)
index 0000000..d991a03
--- /dev/null
@@ -0,0 +1,214 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Instalacja sterownika dla Nvidia GeForce 920M</h1>
+                 <p>
+        Jakiś czas temu musiałem zoptymalizować mój "zestaw", wymieniłem
+        komputer gamingowy, na dwa latopy. Jeden z nich posiada grafikę Nvidia
+        GeForce 920M, chciałem aby na tym sprzęcie rezydował <em>immudex</em>
+        w wersji <em>testing</em>. I tutaj zaczęły się schody, bowiem
+        obecny (dostępny w repozytorium Debian Bookworm) sterownik Nvidii w 
+        wersji 528, nie posiada wsparcia dla tej karty. Więc wpadłem na
+        pomysł zainstalowania wersji 470 z Debian Bullseye. Poniżej znajduje
+        się opis oraz to co udało mi się uzyskać.
+      </p>
+      <p>
+        <span class="warn-sign warning">&#9888;</span>
+        Uwaga! Wykonywane tutaj czynności wykorzystują 
+        <strong>oprogramowanie własnościowe</strong>, jeśli jest to sprzeczne z
+        Twoim zasadami etycznymi zrezyguj z dalszego wykonywania poniższych
+        czynności.
+      </p>
+      <p>
+        <span class="warn-sign notice">&#9888;</span>
+        Pro Tip! Najlepiej te czynności wykonywać na komputerze uruchomionym
+        z pamięci USB.
+      </p> 
+      <p>
+        Sterowniki do obrazu <em>immudex</em>, możemy dodać na zasadzie
+        "<a href="przewiniecie_ingerencja_w_obraz_immudex.html">przewinięcia</a>".
+        Więc czynności rozpoczniemy od sprawdzenia dostępności takich poleceń
+        jak <strong>unsquashfs</strong> oraz <strong>mksquashfs</strong>. W 
+        najnowszych wersjach <em>immudex</em>
+        lub <em>immudex-testing</em> powinny byś one zainstalowane. W celach
+        porządkowych, utworzymy sobie katalog.
+      </p>
+<pre class="code-block">
+$ mkdir 0.1.7
+</pre>
+      <p>
+        Następnie na wypadek niepowodzenia naszych zmian, pobierzemy z partycji
+        obecnie używane archiwum <em>.squashfs</em>.
+      </p> 
+<pre class="code-block">
+$ cp /run/live/medium/live/filesystem.squashfs filesystem.squashfs_original
+</pre>
+      <p>
+        Teraz możemy przejść do katalogu i rozpakować nasze archiwum.
+      </p>
+<pre class="code-block">
+$ cd 0.1.7
+$ sudo unsquashfs -f -d tmp /run/live/medium/live/filesystem.squashfs
+</pre>
+      <p>
+        Po rozpakowaniu archiwum, katalog <em>tmp</em> będzie zawierać
+        <em>rootfs</em> najnowszego obrazu <em>immudex</em>. Aby był on
+        pełnoprawnym obrazem systemu brakuje mu plików jądra, które
+        nie wchodzi w skład archiwum (bo i po co, pliki jądra muszą znajdować
+        się na zewnatrz archiwum, aby system mógł się uruchomić, archiwum
+        zawierające <em>initrd</em> oraz jądro, marnuje po prostu miejsce).
+        Z tego względu, że brakuje w ogóle kilku plików, nie możemy sobie od
+        tak ich skopiować. Musimy posłużyć się narzędziem
+        <strong>apt</strong> oraz trochę je oszukać, aby przywrócić te pliki.
+        Wszystkie czynności przedstawione na poniższym przykładzie wykonywane
+        są w środowisku zmienionego katalogu głównego (<em>chroot</em>).
+        Aby moduły jądra zostały poprawnie zbudowane do środowiska zmienionego
+        katalogu głównego potrzebne jest przekazanie kilku systemowych
+        interfejsów: <em>/dev /dev/pts /proc /run /sys</em>.
+      </p>
+      <p>
+        <span class="warn-sign warning">&#9888;</span>
+        Polecenie <em>apt install</em> może zawieści się. Wówczas należy
+        przerwać operację i odświerzyć połączenie sieciowe poprzez komunikację
+        z serwerem DHCP (polecenie <em>dhclient</em>). 
+      </p>
+<pre class="code-block">
+0.1.7$ for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i tmp${i}; done
+0.1.7$ sudo chroot tmp/ bash
+(chroot)/$ mkdir boot
+(chroot)/$ apt purge linux-image* -y
+(chroot)/$ apt install linux-image-amd64
+</pre>
+      <p>
+        Jeśli nie ma katalogu /boot w katalogu głównym, polecenie
+        <code class="code-inline">apt</code>, zwróci błąd i zakończy działanie.
+        Aby jednak wykonał on zażądane przez nas czynności wystarczy mu sama
+        obecność tego katalogu (katalog może być pusty). Polecenie usuwania 
+        pakietu, może zwrócić monit o tym, że usuwamy działające obecnie jądro
+        i czy chcemy przerwać tę czynność. Z pewnością 99% możemy kliknąć 
+        <code class="code-inline">Nie</code>,
+        osobiście kiedyś udało mi się zawieści działanie jednego z serwerów
+        przeprowadzając tę czynność, mimo wykonania jej środowisku zmienionego
+        katalogu głównego. Jeśli naszym system jest <em>immudex</em>, to mamy 
+        100%.
+      </p>
+      <p>
+        Po odzyskaniu plików jądra, wypadałoby zainstalować pakiety
+        wspomagające budowanie jego modułów (chociaż, pakiet 
+        <em>build-essential</em>, jest zainstalowany w <em>immudex</em>).
+      </p>
+<pre class="code-block">
+(chroot)/$ apt install build-essential dkms linux-headers-$(uname -r)
+</pre>
+      <p>
+        Po zainstalowaniu tych pakietów, możemy przejść do instalacji
+        właściwego sterownika. W tym celu utworzymy sobie plik zawierający
+        lokalizację źródeł repozytorium dla wersji Debian Bullseye, ale tylko
+        do repozytoriów <em>contrib</em> oraz <em>non-free</em> (oczywiście,
+        można użyć bardziej odpowiedniej nazyw niż <em>nvidia.list</em>, jednak
+        dla mnie te repozytoria będą służyć jedynie do tego).
+      </p>
+<pre class="code-block">
+(chroot)/$ cp /etc/apt/sources.list /etc/apt/sources.list.d/nvidia.list
+(chroot)/$ sed -e 's/bookworm/bullseye/g' -e 's/main/contrib non-free/g' -i /etc/apt/sources.list.d/nvidia.list
+(chroot)/$ apt update
+(chroot)/$ apt install nvidia-detect
+(chroot)/$ nvidia-detect
+(chroot)/$ apt install nvidia-driver
+</pre>
+      <p>
+        Polecenie <code class="code-inline">nvidia-detect</code> zwróci
+        informacje o tym że pasującym sterownikiem jest sterownik w wersji 470.
+        A nie jak w przypadku Debian 12, pakiet sterowników dla układów Nvidia
+        Tesla, który nie działa z tym układem.
+        Powykonaniu tych <em>rootfs</em> jest gotowy do pakowania. Jest jeden
+        mały szczegół. Otóż w tej instalacji zabrakło instalacji pakietu
+        <em>nvidia-settings</em>. Nie został on zainstalowany przez niespełnione
+        zależności. Ważna dla tego pakietu jest biblioteka 
+        <strong>libxnvctrl0</strong>, powinna być ona zgodna z wersją
+        instalowanego sterownika Nvidii, jednak ze względu na to, że
+        zostawiliśmy repozytorium <em>main</em> dla Debian Bookworm, nie będzie
+        między nimi zgodności. Zatem, co trzeba zrobić? Otóż należy usunąć
+        obecnie zainstalowany wersję tej biblioteki wraz z pakietami, które jej
+        wymagają, są to dwa pakiety XFCE. Nie należy usuwać pakietów, już
+        niepotrzebnych, ponieważ za chwilę będą one znów potrzebne. Zapisujemy
+        sobie te pakiety (prawdopodbnie będą to: 
+        <em>xfce4-goodies</em> oraz <em>xfce4-sensors-plugin</em>), ponieważ
+        będziemy je instalować ponownie, kiedy uzyskamy odpowiednią wersję
+        wspomnianej biblioteki. Po usunięciu pakietów, tymczasowo zmieniamy
+        wersję dystrybucji, z Bookworm na Bullseye (dla repozytorium 
+        <em>main</em>). Instalujemy naszą
+        bibiotekę, następnie wracamy z powrotem do wersji Bookworm dla
+        repozytrium głównego. Teraz możemy zainstalować ponownie te dwa pakiety
+        oraz pakiet <em>nvidia-settings</em>. Poniżej przedstawiłem wyżej
+        wymieniony opis w postaci poleceń.
+      </p>
+<pre class="code-block">
+(chroot)/$ sed -i 's/Bookworm/Bullseye/g' /etc/apt/sources.list;
+(chroot)/$ apt remove libxnvctrl0 -y
+(chroot)/$ apt update
+(chroot)/$ apt install libxnvctrl0 -y
+(chroot)/$ sed -i 's/Bullseye/Bookworm/g' /etc/apt/sources.list;
+(chroot)/$ apt install xfce4-goodies xfce4-sensors-plugin nvidia-settings
+</pre>
+      <p>
+        Teraz <em>rootfs</em> jest gotowy do pakowania. Zanim jednak do tego
+        przystąpimy, warto posprzątać po sobie, aby nie zaśmiecać niepotrzebnie
+        obrazu. Następnie musimy odmontować zamontowane interfejsy systemowe. 
+        Do pakowania wykorzystamy polecenie <strong>mksquashfs</strong>.
+      </p>
+<pre class="code-block">
+(chroot)/$ apt-get clean
+(chroot)/$ apt-get autoclean
+(chroot)/$ apt-get autoremove
+(chroot)/$ history -c
+(chroot)/$ Ctrl+d
+0.1.7$ for i in /dev/pts /dev /proc /run /sys; do sudo umount tmp${i}; done
+0.1.7$ sudo mksquashfs tmp/ filesystem.squashfs -e boot
+</pre>
+      <p>
+        Ze względu na to iż sterowniki do moduły jądra, które mogą ładowane
+        w niekoniecznie znanym nam momencie, warto było by przenieść na dysk
+        docelowy także obraz jądra oraz obraz <em>initrd</em>.
+      </p>
+<pre class="code-block">
+0.1.7$ sudo cp tmp/boot/vmlinuz-6.1.0-7-amd64 vmlinuz
+0.1.7$ sduo cp tmp/boot/initrd.img-6.1.0-7-amd64 initrd
+</pre>
+      <p>
+        Te trzy pliki kopiujemy na dysk. Po skopiowaniu możemy uruchomić
+        system i sprawdzić czy wszytko jest działa. Zainstalowany sterownik
+        z Debian 11, działa prawidłowo na Debian 12. Po wykonaniu dodatkowych
+        czynności w systemie obecny jest również program <em>nvidia-settings</em>,
+        jednak dla tej karty nie posiada on zbyt wielu opcji lub
+        najzwyczajniej nie działa. Mimo to jeśli posiadamy komputer z tym
+        układem, to warto wykonać te czynności, aby nie doświadczać wielu 
+        irytujących błędów substytutu sterownika, takich jak <em>screen tearing</em>
+        czy jeszcze bardziej denerwującego restartu serwera X11 podczas
+        odblokowywania sesji po wyłączeniu ekranu ze względu na brak aktywności.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/instalacja_systemu.html b/articles/immudex/instalacja_systemu.html
new file mode 100755 (executable)
index 0000000..2bc5c1c
--- /dev/null
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Instalacja immudex</h1>
+                 <p>
+        Mimo tego, iż <em>immudex</em> jest wydawany jako <em>Live CD</em>, to
+        można go z powodzeniem zainstalować na dysku. Nawet jest to zalecane
+        dla tych, którzy chcą korzystać z niego w codziennym użytku. Obecnie
+        dostępne są dwa rodzaje instalacji:  
+      </p>
+      <h2>Instalacja obrazu LiveCD</h2>
+      <p>
+        Ten rodzaj instalacji świetnie sprawdzi się w przypadku cienkich
+        klientów oraz uruchamiania komputerów z sieci. Polega on na załadowaniu
+        na dysk obrazu płyty tak jak byśmy wgrywali go na pamięć USB.
+      </p>
+<pre class="code-block">
+$ curl https://ftp.morketsmerke.org/immudex/testing/iso/0.1.9/immudex-testing64.iso | sudo dd bs=1M of=/dev/sdX
+</pre>
+      <p>
+        Warto pamiętać o tym, że przy tego typu instalacjach reszta dysku
+        staje się bezużytczna.
+      </p>
+      <h2>Instalacja immudex na dysku</h2>
+      <p>
+        Jeśli chcemy na przykład wykorzystać <em>immudex</em> na laptopie,
+        gdzie potrzebujemy miejsca na dane. To dobry rozwiązaniem jest
+        instalacja systemu na dysku. <em>Immudex</em> póki co alokuje na pliki
+        systemowe 4 GB miejsca na dysku. Reszta pozostaje do naszej
+        dyspozycji.
+      </p>
+      <p>
+        Instalacji na dysku należy dokonać poprzez skrypt
+        <strong>immudex_install</strong>, skrypt zapyta nas o docelowy
+        dysk, jeśli będą więcej niż dwa. Przy uruchomieniu komputera z pamięci
+        USB jest to niemal pewne. Wybieramy konkretny dysk z listy i już,
+        system instaluje się.
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ immudex_install 
+This script will install immudex on first disk on your machine.
+It could be destructive for data placed on this disk
+Are you sure that you want contiune? (y/n): y
+Installation immudex in BIOS mode ... 1) vda
+2) vdb
+#? 1
+</pre>
+      <p>
+        Instalator sam na podstawie dostępności zmiennych oprogramowania
+        układowego UEFI ustali czy komputer działa w trybie BIOS czy UEFI
+        (w przypadku uruchomienia komputera w trybie BIOS, zmienne UEFI,
+        mimo że ten tryb jest dostępny, są niedostępne), następnie dobierze
+        odpowiedni zestaw poleceń. Nie będę przytaczać całego procesu
+        instalacji, ponieważ jest on rozpisany w narzędziu 
+        <em>immudex_install</em>, które można sobie przeanalizować pod tym
+        adresem: <a href="https://github.com/xf0r3m/immudex/blob/main/tools/010/immudex_install">https://github.com/xf0r3m/immudex/blob/main/tools/010/immudex_install</a>.
+      </p>
+      <p>
+        Inną kwestią pozostaje odmienność wersji UEFI. Obecnie mamy doczynienia
+        z 32-bitowym oraz 64-bitowym oprogramowanie układowym tego typu.
+        Skrypt <em>immudex-install</em> wspiera instalację na maszynach z
+        32-bitowym UEFI, jednak wymaga to specjalnego dysku USB. Na szczeście
+        istnieje narzędzie <strong>create_media</strong>, który posiada
+        specjalnego wgrania obrazu z <em>immudex</em> na pamięć USB, aby była
+        możliwość uruchomienia go na tych specyficznych komputerach.
+      </p>
+<pre class="code-block">
+$ create_media --i386-efi /dev/sdb ~/Pobrane/immudex-testing64.iso
+</pre>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/koncepcje_immudex.html b/articles/immudex/koncepcje_immudex.html
new file mode 100755 (executable)
index 0000000..f7048e5
--- /dev/null
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Koncepcje immudex</h1>
+                 <p>
+        Wiekszość dystrybucji Linuksa powstało, aby służyć ludziom. Dać im
+        możliwość panowania na posiadanym sprzętem. Wiele specyficznych 
+        dystrybucji posiada kilka zasad jakimi kieruje się podczas jej
+        tworzenia i rozwoju, <em>immudex</em> nie jest wyjątkiem. W tym
+        materiale zostało zebranych 7 zasad, które definiują tę dystrybucję.
+      </p>
+      <h3>1. Niezmienność</h3>
+      <p>
+        Podstawową cechą tej dystrybucji jest <strong>niezmienność</strong>
+        w najprostrzej, najczystszej postacji. Wiem, że uruchamianie systemu
+        jako <em>Live CD</em> może nie być postrzegne jako niezmienne. Dla
+        mnie <em>niezmienne</em> oznacza tyle, że jeśli uruchomisz system
+        ponownie to powróci on do swojej pierwotnej postaci. Nabrudzisz, 
+        nagrzebiesz, nie ważne. <em>Reboot</em> i masz już czysty system z
+        powrotem.
+      </p>
+      <h3>2. Separacja</h3>
+      <p>
+        Jeśli chcielibyśmy zainfektować jakąś dystrybucję szkodliwym
+        oprogramowniem (nie, oprogramowanie własnościowe się nie liczy), to
+        trzeba było by tego naprawdę chcieć. Nie mmiej jednak tworząc
+        <em>immudex</em> mam świadomość, że największym zagrożeniem dlatego
+        systemu pozostaje przeglądarka internetowa. Obecnie przeglądarki
+        stały się podsystemami dla systemów operacyjnych, więc warto było
+        by im ukrócić trochę uprawnienia. Dlatego też domyślnie przeglądarka
+        w <em>immudex</em> uruchamiana jest przez <em>sandboxer</em>
+        <strong>firejail</strong> wraz z własną emulacją stosu TCP/IP.
+      </p>
+      <p>
+        Innym rodzajem speracji jest załączony <em>firewall</em>
+        <strong>ufw</strong> z domyślną polityką dla połączeń przychodzących
+        ustawioną na <em>deny</em>.
+      </p>
+      <h3>3. Szyfrowanie danych</h3>
+      <p>
+        <em>Immudex</em> zachęca poprzez wsparcie autorskimi rozwiązaniami
+        korzystanie z szyfrowanych partycji. Jeśli taka partycja pozostanie
+        zamknięta, to mimo uzyskania dostępu do komputera dane na nim
+        przechowywane pozostaną bezpieczne. Punkty montowania nie są osiągalne
+        również z przeglądarki uruchomionej przez <em>firejail</em>.
+      </p>
+      <h3>4. Użyteczność</h3>
+      <p>
+        Mimo specyfiki systemu dalej pozostaje on użyteczny jak każda inna
+        dystrybuja skierowana na komputery biurkowe. Posiada ona intuicyjne
+        środowisko graficzne XFCE, oprgramowanie do odtwarzania multimediów,
+        pakiet biurowy, <u>normalną</u> przeglądarkę internetową z
+        zainstalowanym blokerem reklam oraz innych nachalnych elementów
+        stron internetowych. Dystrybucja się również zapewnić rozwiązania
+        związane z ochroną prywatności takie jak dedykowana dla niej instancja
+        meta-silnika wyszukiwarek internetowych <em>searxng</em> z dodanym
+        silnikiem również do przeglądarki (dodatek idx-search) oraz
+        oprogramowanie <em>openvpn</em>.
+      </p>
+      <h3>5. Elastyczność</h3>
+      <p>
+        Dystrybucja stara się być jak najbardziej elastyczna i nie narzucać
+        nikomu niczego. Nie musimy stoswać się do żadnej z wienionych tutaj
+        zasad, możemy wprowadzać własne rozwiązania. Również wiele wyżej
+        wymienionych koncepcji zostało zaimplementowanych w taki sposób, że
+        są łatwe do ominięcia. Możemy <em>immudex</em> dowolnie
+        przebudowywać i zmieniać. W pewnym momencie dojdziemy do wniosku, że
+        ona tak naprawdę nie istnieje. Jest tylko Debian, odpowiednio
+        skonfigurowany.
+      </p>
+      <h3>6. Bezkosztowość</h3>
+      <p>
+        <em>Immudex</em> utrzymywany jest na publicznie dostępnych serwisach,
+        takich jak <em>sourceforge.net</em> czy <em>github.com</em>. Istnienie
+        oficjalnego mirroru <em>ftp.morketsmerke.org</em> jest tylko i
+        wyłącznie fanberią twórcy. Sam Debian jest o tyle ciekawą dystrybucją,
+        że jego obrazy mogą być tworzone na naprawdę niskobudżetowym sprzęcie,
+        pokroju <em>chrombooka</em> (tylko trzeba się w dysk zaopatrzyć).
+        Nie potrzeba wydajnych serwerów, wystarczy zwykły laptop, połączenie
+        z internetem, zainstalowany Debian oraz trochę cierpliwości.
+        <em>Immudex</em> również jest dystrybucją, która powinna zadziałać 
+        na każdym sprzęcie. 
+      </p>
+      <h3>7. Wolność</h3>
+      <p>
+        Wolne oprogramowanie (<em>free software</em>) nie daje pełni wolności.
+        Aby moć się nią cieszyć, należy dać użytkownikom prawo do wyboru.
+        <em>Immudex</em> nie neguje istoty wolności oprgramowania. Nie chce
+        skazywać użytkowników na dyskonfort związany z niemożnością
+        wykorzystania sprzętu, na który wydali ciężko zarobione pieniądze lub
+        na wykluczenie korzystania ze współczesnych technologi zachowując
+        przy tym równowagę i posiadając z tyłu głowy wszystkie zagrożenia jakie
+        może ze sobą nieść. Domyślnie i oficjalnie <em>immudex</em> zawsze 
+        będzie posiadał
+        tylko i wyłącznie wolne oprogramowania, jednak nigdy nie będzie czynnem
+        niemile widzianym uzupełnienie obrazu o brakujący firmware czy inne
+        oprogramowanie własnościowe. Na tym własnie polega prawdziwa wolność,
+        na daniu możliwości wyboru.
+      <p>
+      <p>
+        <em>Immudex</em> został i jest tworzony głównie z myślą o mnie, nie
+        każdemu moje rozwiązania mogą pasować. Nie musi z niej korzystać,
+        dostępnych jest tyle wspaniałych dystrybucji, że napewno wybierze coś
+        dla siebie. Zajmowanie się tą dystrybucją, traktuję jako dobrą zabawę
+        więc wiele rzeczy oficjalnie może nie działać jak powino. Nie ma
+        tutaj gwarancji przydatności ani poprawności działania.
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/lista_oprogramowania_immudex.html b/articles/immudex/lista_oprogramowania_immudex.html
new file mode 100644 (file)
index 0000000..1e6ea0b
--- /dev/null
@@ -0,0 +1,520 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+
+<h2>List pakietów oprogramowania</h2>
+<p>Stan pakietów i aktualizacji na: <strong>pią, 28 lip 2023, 11:03:51 CEST</strong></p>
+<table border="1" style="border-collapse: collapse">
+<tr><th>Nazwa pakietu</th><th>stable</th><th>testing</th><th>LHE*</th></tr>
+<tr>
+<td>alsa-utils</td>
+<td><span style="color: #15ed15">1.2.8-1</span></td>
+<td><span style="color: #15ed15">1.2.9-1</span></td>
+<td><span style="color: #15ed15">1.1.8-2</span></td>
+</tr>
+<tr>
+<td>base-files</td>
+<td><span style="color: #ff0000">12.4+deb12u1</span></td>
+<td><span style="color: #15ed15">13</span></td>
+<td><span style="color: #15ed15">10.3+deb10u13</span></td>
+</tr>
+<tr>
+<td>bash-completion</td>
+<td><span style="color: #15ed15">1:2.11-6</span></td>
+<td><span style="color: #15ed15">1:2.11-7</span></td>
+<td><span style="color: #15ed15">1:2.8-6</span></td>
+</tr>
+<tr>
+<td>bridge-utils</td>
+<td><span style="color: #15ed15">1.7.1-1</span></td>
+<td><span style="color: #15ed15">1.7.1-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>chrony</td>
+<td><span style="color: #15ed15">4.3-2+deb12u1</span></td>
+<td><span style="color: #15ed15">4.3-4</span></td>
+<td><span style="color: #15ed15">3.4-4+deb10u2</span></td>
+</tr>
+<tr>
+<td>cifs-utils</td>
+<td><span style="color: #15ed15">2:7.0-2</span></td>
+<td><span style="color: #15ed15">2:7.0-2</span></td>
+<td><span style="color: #15ed15">2:6.8-2+deb10u1</span></td>
+</tr>
+<tr>
+<td>cmus</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">2.7.1+git20160225-2+b2</span></td>
+</tr>
+<tr>
+<td>conky</td>
+<td><span style="color: #15ed15">1.18.3-1</span></td>
+<td><span style="color: #15ed15">1.19.2-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>cryptsetup</td>
+<td><span style="color: #15ed15">2:2.6.1-4~deb12u1</span></td>
+<td><span style="color: #15ed15">2:2.6.1-4</span></td>
+<td><span style="color: #15ed15">2:2.1.0-5+deb10u2</span></td>
+</tr>
+<tr>
+<td>curl</td>
+<td><span style="color: #ff0000">7.88.1-10+deb12u1</span></td>
+<td><span style="color: #15ed15">7.88.1-10</span></td>
+<td><span style="color: #15ed15">7.64.0-4+deb10u6</span></td>
+</tr>
+<tr>
+<td>debootstrap</td>
+<td><span style="color: #15ed15">1.0.128+nmu2</span></td>
+<td><span style="color: #15ed15">1.0.128+nmu5</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>desktop-base</td>
+<td><span style="color: #ff0000">12.0.6+nmu1~deb12u1</span></td>
+<td><span style="color: #15ed15">12.0.6+nmu1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>dnsutils</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">1:9.18.16-1</span></td>
+<td><span style="color: #15ed15">1:9.11.5.P4+dfsg-5.1+deb10u9</span></td>
+</tr>
+<tr>
+<td>dosfstools</td>
+<td><span style="color: #15ed15">4.2-1</span></td>
+<td><span style="color: #15ed15">4.2-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>efibootmgr</td>
+<td><span style="color: #15ed15">17-2</span></td>
+<td><span style="color: #15ed15">17-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>etherwake</td>
+<td><span style="color: #15ed15">1.09-4+b1</span></td>
+<td><span style="color: #15ed15">1.09-4+b1</span></td>
+<td><span style="color: #15ed15">1.09-4+b1</span></td>
+</tr>
+<tr>
+<td>extlinux</td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3+b1</span></td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3+b1</span></td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-1</span></td>
+</tr>
+<tr>
+<td>feh</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">3.1.3-1</span></td>
+</tr>
+<tr>
+<td>ffmpeg</td>
+<td><span style="color: #15ed15">7:5.1.3-1</span></td>
+<td><span style="color: #ff0000">7:5.1.3-2</span></td>
+<td><span style="color: #15ed15">7:4.1.11-0+deb10u1</span></td>
+</tr>
+<tr>
+<td>figlet</td>
+<td><span style="color: #15ed15">2.2.5-3+b1</span></td>
+<td><span style="color: #15ed15">2.2.5-3+b1</span></td>
+<td><span style="color: #15ed15">2.2.5-3</span></td>
+</tr>
+<tr>
+<td>firejail</td>
+<td><span style="color: #15ed15">0.9.72-2</span></td>
+<td><span style="color: #15ed15">0.9.72-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>gimp</td>
+<td><span style="color: #15ed15">2.10.34-1</span></td>
+<td><span style="color: #15ed15">2.10.34-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>git</td>
+<td><span style="color: #15ed15">1:2.39.2-1.1</span></td>
+<td><span style="color: #15ed15">1:2.40.1-1</span></td>
+<td><span style="color: #15ed15">1:2.20.1-2+deb10u8</span></td>
+</tr>
+<tr>
+<td>grub-efi-amd64</td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>grub-efi-amd64-bin</td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>grub-pc-bin</td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: #15ed15">2.06-13</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>gvfs-backends</td>
+<td><span style="color: #15ed15">1.50.3-1</span></td>
+<td><span style="color: #15ed15">1.50.4-3</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>irssi</td>
+<td><span style="color: #15ed15">1.4.3-2</span></td>
+<td><span style="color: #15ed15">1.4.4-1</span></td>
+<td><span style="color: #15ed15">1.2.0-2+deb10u1</span></td>
+</tr>
+<tr>
+<td>isolinux</td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3</span></td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>iwd</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">0.14-2</span></td>
+</tr>
+<tr>
+<td>libvirt-clients</td>
+<td><span style="color: #15ed15">9.0.0-4</span></td>
+<td><span style="color: #15ed15">9.5.0-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>libvirt-daemon</td>
+<td><span style="color: #15ed15">9.0.0-4</span></td>
+<td><span style="color: #15ed15">9.5.0-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>libvirt-daemon-system</td>
+<td><span style="color: #15ed15">9.0.0-4</span></td>
+<td><span style="color: #15ed15">9.5.0-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>linux-image-686-pae</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">4.19+105+deb10u19</span></td>
+</tr>
+<tr>
+<td>linux-image-amd64</td>
+<td><span style="color: #15ed15">6.1.38-1</span></td>
+<td><span style="color: #15ed15">6.3.7-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>live-boot</td>
+<td><span style="color: #15ed15">1:20230131</span></td>
+<td><span style="color: #15ed15">1:20230131</span></td>
+<td><span style="color: #15ed15">1:20190614</span></td>
+</tr>
+<tr>
+<td>lsof</td>
+<td><span style="color: #15ed15">4.95.0-1</span></td>
+<td><span style="color: #15ed15">4.95.0-1</span></td>
+<td><span style="color: #15ed15">4.91+dfsg-1</span></td>
+</tr>
+<tr>
+<td>lynx</td>
+<td><span style="color: #15ed15">2.9.0dev.12-1</span></td>
+<td><span style="color: #15ed15">2.9.0dev.12-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>mpv</td>
+<td><span style="color: #15ed15">0.35.1-4</span></td>
+<td><span style="color: #15ed15">0.35.1-4+b1</span></td>
+<td><span style="color: #15ed15">0.29.1-1+deb10u1</span></td>
+</tr>
+<tr>
+<td>mtools</td>
+<td><span style="color: #15ed15">4.0.33-1+really4.0.32-1</span></td>
+<td><span style="color: #15ed15">4.0.33-1+really4.0.32-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>mutt</td>
+<td><span style="color: #15ed15">2.2.9-1+b1</span></td>
+<td><span style="color: #15ed15">2.2.9-1+b1</span></td>
+<td><span style="color: #15ed15">1.10.1-2.1+deb10u6</span></td>
+</tr>
+<tr>
+<td>netselect-apt</td>
+<td><span style="color: #15ed15">0.3.ds1-30.1</span></td>
+<td><span style="color: #15ed15">0.3.ds1-30.1</span></td>
+<td><span style="color: #15ed15">0.3.ds1-28</span></td>
+</tr>
+<tr>
+<td>nfs-common</td>
+<td><span style="color: #15ed15">1:2.6.2-4</span></td>
+<td><span style="color: #15ed15">1:2.6.3-1</span></td>
+<td><span style="color: #15ed15">1:1.3.4-2.5+deb10u1</span></td>
+</tr>
+<tr>
+<td>nmap</td>
+<td><span style="color: #15ed15">7.93+dfsg1-1</span></td>
+<td><span style="color: #15ed15">7.93+dfsg1-1</span></td>
+<td><span style="color: #15ed15">7.70+dfsg1-6+deb10u2</span></td>
+</tr>
+<tr>
+<td>openvpn</td>
+<td><span style="color: #ff0000">2.6.3-1+deb12u1</span></td>
+<td><span style="color: #15ed15">2.6.3-2</span></td>
+<td><span style="color: #15ed15">2.4.7-1+deb10u1</span></td>
+</tr>
+<tr>
+<td>parted</td>
+<td><span style="color: #15ed15">3.5-3</span></td>
+<td><span style="color: #15ed15">3.6-3</span></td>
+<td><span style="color: #15ed15">3.2-25</span></td>
+</tr>
+<tr>
+<td>pass</td>
+<td><span style="color: #15ed15">1.7.4-6</span></td>
+<td><span style="color: #15ed15">1.7.4-6</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>picom</td>
+<td><span style="color: #15ed15">9.1-1</span></td>
+<td><span style="color: #15ed15">10.2-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>pulseaudio</td>
+<td><span style="color: #15ed15">16.1+dfsg1-2+b1</span></td>
+<td><span style="color: #15ed15">16.1+dfsg1-2+b1</span></td>
+<td><span style="color: #15ed15">12.2-4+deb10u1</span></td>
+</tr>
+<tr>
+<td>python3-pip</td>
+<td><span style="color: #15ed15">23.0.1+dfsg-1</span></td>
+<td><span style="color: #15ed15">23.2+dfsg-1</span></td>
+<td><span style="color: #15ed15">18.1-5</span></td>
+</tr>
+<tr>
+<td>python3-venv</td>
+<td><span style="color: #15ed15">3.11.2-1+b1</span></td>
+<td><span style="color: #15ed15">3.11.4-5</span></td>
+<td><span style="color: #15ed15">3.7.3-1</span></td>
+</tr>
+<tr>
+<td>qemu-system-x86</td>
+<td><span style="color: #ff0000">1:7.2+dfsg-7+deb12u1</span></td>
+<td><span style="color: #15ed15">1:8.0.2+dfsg-3</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>qmmp</td>
+<td><span style="color: #15ed15">1.6.2-1+b1</span></td>
+<td><span style="color: #15ed15">1.6.2-1+b1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>ranger</td>
+<td><span style="color: #15ed15">1.9.3-5</span></td>
+<td><span style="color: #15ed15">1.9.3-5</span></td>
+<td><span style="color: #15ed15">1.9.2-4</span></td>
+</tr>
+<tr>
+<td>ratpoison</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">1.4.9-1</span></td>
+</tr>
+<tr>
+<td>redshift</td>
+<td><span style="color: #15ed15">1.12-4.2</span></td>
+<td><span style="color: #15ed15">1.12-4.2</span></td>
+<td><span style="color: #15ed15">1.12-2</span></td>
+</tr>
+<tr>
+<td>remmina</td>
+<td><span style="color: #15ed15">1.4.29+dfsg-1</span></td>
+<td><span style="color: #15ed15">1.4.31+dfsg-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>rsync</td>
+<td><span style="color: #15ed15">3.2.7-1</span></td>
+<td><span style="color: #15ed15">3.2.7-1</span></td>
+<td><span style="color: #15ed15">3.1.3-6</span></td>
+</tr>
+<tr>
+<td>squashfs-tools</td>
+<td><span style="color: #15ed15">1:4.5.1-1</span></td>
+<td><span style="color: #15ed15">1:4.6.1-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>sudo</td>
+<td><span style="color: #ff0000">1.9.13p3-1+deb12u1</span></td>
+<td><span style="color: #15ed15">1.9.14p2-1</span></td>
+<td><span style="color: #15ed15">1.8.27-1+deb10u5</span></td>
+</tr>
+<tr>
+<td>syslinux-efi</td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3</span></td>
+<td><span style="color: #15ed15">3:6.04~git20190206.bf6db5b4+dfsg1-3</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>systemd-sysv</td>
+<td><span style="color: #ff0000">252.12-1~deb12u1</span></td>
+<td><span style="color: #15ed15">253.5-1</span></td>
+<td><span style="color: #15ed15">241-7~deb10u10</span></td>
+</tr>
+<tr>
+<td>tmux</td>
+<td><span style="color: #15ed15">3.3a-3</span></td>
+<td><span style="color: #15ed15">3.3a-4</span></td>
+<td><span style="color: #15ed15">2.8-3+deb10u1</span></td>
+</tr>
+<tr>
+<td>ufw</td>
+<td><span style="color: #15ed15">0.36.2-1</span></td>
+<td><span style="color: #15ed15">0.36.2-1</span></td>
+<td><span style="color: #15ed15">0.36-1</span></td>
+</tr>
+<tr>
+<td>vim</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">2:8.1.0875-5+deb10u5</span></td>
+</tr>
+<tr>
+<td>vim-gtk3</td>
+<td><span style="color: #15ed15">2:9.0.1378-2</span></td>
+<td><span style="color: #15ed15">2:9.0.1672-1</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>virtinst</td>
+<td><span style="color: #15ed15">1:4.1.0-2</span></td>
+<td><span style="color: #15ed15">1:4.1.0-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>virt-manager</td>
+<td><span style="color: #15ed15">1:4.1.0-2</span></td>
+<td><span style="color: #15ed15">1:4.1.0-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>vlc</td>
+<td><span style="color: #15ed15">3.0.18-2</span></td>
+<td><span style="color: #15ed15">3.0.18-3</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>wakeonlan</td>
+<td><span style="color: #15ed15">0.41-12.1</span></td>
+<td><span style="color: #15ed15">0.41-12.1</span></td>
+<td><span style="color: #15ed15">0.41-12</span></td>
+</tr>
+<tr>
+<td>wget</td>
+<td><span style="color: #15ed15">1.21.3-1+b2</span></td>
+<td><span style="color: #15ed15">1.21.3-1+b2</span></td>
+<td><span style="color: #15ed15">1.20.1-1.1</span></td>
+</tr>
+<tr>
+<td>wireless-tools</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">30~pre9-13</span></td>
+</tr>
+<tr>
+<td>xdm</td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">1:1.1.11-3</span></td>
+</tr>
+<tr>
+<td>xfce4</td>
+<td><span style="color: #15ed15">4.18</span></td>
+<td><span style="color: #15ed15">4.18</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>xinit</td>
+<td><span style="color: #15ed15">1.4.0-1</span></td>
+<td><span style="color: #15ed15">1.4.0-1</span></td>
+<td><span style="color: #15ed15">1.4.0-1</span></td>
+</tr>
+<tr>
+<td>xorriso</td>
+<td><span style="color: #15ed15">1.5.4-4</span></td>
+<td><span style="color: #15ed15">1.5.4-4</span></td>
+<td><span style="color: inherit">N/I</span></td>
+</tr>
+<tr>
+<td>xserver-xorg</td>
+<td><span style="color: #15ed15">1:7.7+23</span></td>
+<td><span style="color: #15ed15">1:7.7+23</span></td>
+<td><span style="color: #15ed15">1:7.7+19</span></td>
+</tr>
+<tr>
+<td>xserver-xorg-core</td>
+<td><span style="color: #15ed15">2:21.1.7-3</span></td>
+<td><span style="color: #15ed15">2:21.1.7-3</span></td>
+<td><span style="color: #15ed15">2:1.20.4-1+deb10u9</span></td>
+</tr>
+<tr>
+<td>xterm</td>
+<td><span style="color: #15ed15">379-1</span></td>
+<td><span style="color: #15ed15">384-1</span></td>
+<td><span style="color: #15ed15">344-1+deb10u2</span></td>
+</tr>
+<tr>
+<td>youtube-dl</td>
+<td><span style="color: #15ed15">2021.12.17-2</span></td>
+<td><span style="color: inherit">N/I</span></td>
+<td><span style="color: #15ed15">2019.01.17-1.1</span></td>
+</tr>
+</table>
+<p>
+<em>* - Low Hardware Edition, Debian 10 Buster, 32-bit</em><br />
+<strong>N/I</strong> - (ang. <em>Not installed</em>) - nie zainstalowano<br />
+<span style="display: block; width: 15px; height: 15px; background-color: #15ed15; float: left;"></span>&nbsp;- zainstalowana wersja<br />
+<span style="display: block; width: 15px; height: 15px; background-color: #ff0000; float: left;"></span>&nbsp;- wersja gotowa do instalacji (aktualizacja)<br />
+</p>
+
+       </div>
+       <p class="footer">
+               2023; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/immudex/odtworzenie_srodowiska_budowania_immudex_z_LiveCD.html b/articles/immudex/odtworzenie_srodowiska_budowania_immudex_z_LiveCD.html
new file mode 100755 (executable)
index 0000000..970cc36
--- /dev/null
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Odtworzenie środowiska budowania immudex z LiveCD</h1>
+                 <p>
+        Przygotowując przez ten czas kolejne wersje <em>immudex</em> natrafiłem
+        na dość spory problem logistyczny. Otóż środowiska budowania (katalog
+        z <em>rootfs</em>, plikami <em>LiveCD</em> itp.) potrafił ważyć ok. 10
+        GB. Co powodowało problemy z archiwizacją oraz z ewentualnym
+        przenoszeniem tych danych. Zastanawiając się nad tym chwilę doszedłem do
+        wniosku, iż obrazy <em>.iso</em> muszą zawierać większość plików
+        zawartych w środowisku. Zatem wydaje mi się, że można je skopiować i
+        ustrukturyzować, aby obecność środowiska budowania przestała mieć
+        znaczenie.
+      </p>
+      <p>
+        <span class="warn-sign notice">&#9888;</span>
+        Ten materiał jest opisem czynności wykonywanych w skrypcie
+        opublikowanym na repozytorium projektu: <em>immudex-testing</em>,
+        pod tym adresem: <a href="https://github.com/xf0r3m/immudex-testing/blob/main/immudex_rebuildenv">https://github.com/xf0r3m/immudex-testing/blob/main/immudex_rebuildenv</a>,
+        więc przykłady nie będą poleceniami, ale przeredagowanym fragmentami
+        ze skryptu.
+      </p>
+      <p>
+        <em>Immudex</em> posiada dwie wersje oficjalne, jedną nieoficjalną,
+        która nie jest publicznie dostępna. Dodatkowo obsługuje on dwie
+        architektury: <em>amd64</em> oraz <em>i386</em>. Dlatego też
+        najważnie jeszcze jest aby wydobyć jak najwięcej informacji z jej jak
+        najmniejszej ilości. W tym przypadku do dyspozycji posiadamy plik
+        z obrazem lub link do lokalizacji sieciowej, gdzie możemy go pobrać.
+        Na podstawie samej nazwy obrazu płyty, możemy dowiedzieć się kilku
+        rzeczy. Czy mamy doczynienia z wersją stabliną, testową czy nieoficjalną
+        oraz dla jakiej architektury przygotowany został system. Na podstawie
+        tych informacji oraz informacji z instrukcji budowania <em>immudex</em>
+        możemy utworzyć strukturę katalogową, która pomoże nam utrzymać porządek
+        oraz umożliwi automatyzację procesu tworzenia nowego obrazu.
+      </p>
+<pre class="code-block">
+isoPath=$1;
+if echo $isoPath | grep -q 'http'; then wget $isoPath; fi
+
+filename=$(basename $isoPath);
+if echo $filename | grep -q 'immudex-testing'; then
+  branch="immudex-testing";
+  branchAltName="testing";
+elif echo $filename | grep -q 'immudex-niko'; then
+  branch="immudex";
+  branchAltName="niko"
+else
+  branch="immudex";
+  branchAltName="stable";
+fi
+
+if echo $filename | grep -q '64'; then
+  arch="64";
+else
+  arch="32";
+fi
+
+mkdir -pv build/${branchAltName}/${branch}/${arch}/{chroot,staging,tmp};
+</pre>
+      <p>
+        Posiadając już strukturę katalogów możemy określić "katalog główny" dla
+        naszych czynności. Wykonywane przez nas czynności nie będą
+        opuszczać obszaru tego katalogu.
+      </p>
+<pre class="code-block">
+rootPath="build/${branchAltName}";
+</pre>
+      <p>
+        Następną czynnością, jaką możemy wykonąć jest pobranie dla odpowiedniej
+        wersji <em>immudex</em>, skryptu odpowiedzialnego za budowanie obrazu 
+        płyty oraz nadanie mu odpowiednich uprawnień.
+      </p>
+<pre class="code-block">
+wget https://github.com/xf0r3m/${branch}/raw/main/immudex_build -O ${rootPath}/immudex_build
+chmod +x ${rootPath}/immudex_build;
+</pre>
+      <p>
+        Teraz możemy przjść już to skopiowania danych z płyty.
+      </p>
+<pre class="code-block">
+mkdir -v /tmp/iso;
+sudo mount -v $isoPath /tmp/iso;
+sudo cp -rvv /tmp/iso/* ${rootPath}/${branch}/${arch}/staging;
+sudo chown -Rv ${USER}:${USER} ${rootPath}/${branch}/${arch}/staging;
+sudo umount -v /tmp/iso;
+sudo rmdir -v /tmp/iso;
+</pre>
+      <p>
+        Dla utrzymania porządku w systemie, wypadało by utworzyć punkt
+        montowania dla obrazu płyty, z którego będziemy kopiować dane. Następnie
+        płytę należy zamontować. Jeśli nie przyglądaliśmy się za bardzo
+        poleceniu tworzenia struktury katalogowej dla środowiska, to każde 
+        środowisko budowania, dla konkretnej architektury
+        składa się z trzech katalogów. W katalogu
+        <code class="code-inline">staging</code> znajduje się cała zawartość
+        obrazu płyty i do tego katalogu będzie ona kopiowana. Następnie
+        nadawane są odpowiednie prawa własnosci dla skopiowanych danych.
+        Na koniec obraz płyty jest odłączany od systemu a punkt montowania
+        usuwany.
+      </p>
+      <p>
+        W tym momencie na trafiamy na pierwszy problem, otóż nie wszystkie
+        pliki znajdują się na obrazie. Taki plikiem jest plik konfiguracji
+        GRUB-a, dla samodzielnego pliku wykonywalnego programu rozruchowego.
+        Może to brzmi skomplikowanie, ale ta czynność jest opcjonalna, ponieważ
+        ten plik pozostaje bez zmian (plik wykonywalny), dlatego nie potrzeba
+        tworzyć go na nowo, ale jeśli chcemy mieć pełne środowisko to można
+        wykonać te czynności.
+      </p>
+<pre class="code-block">
+cat &gt; ${rootPath}/${branch}/${arch}/tmp/grub-standalone.cfg &lt;&lt;EOF
+search --set=root --file /DEBIAN
+set prefix=($root)/boot/grub
+configfile /boot/grub/grub.cfg
+EOF
+cat ${rootPath}/${branch}/${arch}/tmp/grub-standalone.cfg;
+</pre>
+      <p>
+        Po wykonaniu czynności przygotowawczych, nadszedł czas aby zabrać się
+        za rozpakowywanie archiwum <em>squashfs</em>.
+      </p>
+<pre class="code-block">
+sudo unsquashfs -f -d ${rootPath}/${branch}/${arch}/chroot ${rootPath}/${branch}/${arch}/staging/live/filesystem.squashfs;
+</pre>
+      <p>
+        Zawartość skopiowanego archiwum wypakowujemy do przygotowanego
+        wcześniej katalogu <em>chroot</em>. Po wypakowaniu ustalamy jakie
+        jądro według architektury należy zainstalować. Tu pojawia się drugi
+        problem, otóż archiwa <em>squashfs</em> pozbawione są plików jądra.
+        Więc aby nie rozpoczynąć każdego pliku wersji (skryptu aktualizacji)
+        od uzupełnienia jądra. Robi się to teraz, a jest realizowane za pomocą
+        małego skryptu uruchamianego w zmienionym na zawartość archiwum
+        <em>squashfs</em> katalogu domowym. Z tego też powodu musimy ustalić
+        wersję jądra, którą na podstawie architektury uzupełnimy środowisko
+        budowania.
+      </p>
+<pre class="code-block">
+if [ "$arch" = "64" ]; then
+  linuxKernel="linux-image-amd64";
+else
+  linuxKernel="linux-image-686-pae";
+fi
+
+cat &gt; chrtcmd.sh &lt;&lt;EOF
+#!/bin/bash
+
+mkdir /boot;
+apt purge -y linux-image*;
+dhclient;
+apt update;
+apt install -y $linuxKernel;
+echo &gt; /root/.bash_history;
+history -c;
+EOF
+  
+cat chrtcmd.sh;
+sudo mv -v chrtcmd.sh ${rootPath}/${branch}/${arch}/chroot;
+sudo chroot ${rootPath}/${branch}/${arch}/chroot bash chrtcmd.sh;
+sudo rm -v ${rootPath}/${branch}/${arch}/chroot/chrtcmd.sh;
+</pre>
+      <p>
+        Po określeniu jądra oraz napisaniu skryptu możemy przenieść go do
+        katalogu <code class="code-inline">chroot</code> a następnie
+        uruchomić. Skrypt usunie pozostałości po jądrze i zainstaluje je na
+        nowo. Tutaj podczas usuwania pakietów jądra może pojawić się monit
+        o tym, że usuwamy aktualnie używane jądro. Wydaje mi się, że możemy
+        śmiało kontynuować i nie powinno się nic stać, ponieważ zmieniliśmy
+        katalog główny. Jeśli używamy <em>immudex</em> to na pewno się nic
+        się nie stanie, ponieważ katalog <em>/boot</em> nawet nie istnieje.
+        Po zakończeniu działania skryptu, możemy go usunąć.
+      </p>
+      <p>
+        W ten sposób udało sie nam odzyskać środowisko budowania
+        <em>immudex</em> z obrazu płyty.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/plik_wersji.html b/articles/immudex/plik_wersji.html
new file mode 100755 (executable)
index 0000000..ab89fed
--- /dev/null
@@ -0,0 +1,206 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Skrypt aktualizacji - plik wersji</h1>
+                 <p>
+        Zmiany wprowadzane do <em>immudex</em> są rozpisywane w postaci skryptu.
+        Program ten nazwany jest <strong>plikiem wersji</strong>, ze względu na
+        to, że jego nazwą jest numer kolejnej wersji dystrybucji. Pliki wersji
+        są tworzone od momentu pierwszych poprawek, aż do daty wydania tej
+        wersji systemu. Plik wersji składa się z definicji funkcji, które
+        poźniej są wkorzystywane do utworzenia listy instrukcji, która
+        wprowadzi wszystkie zmiany przeznaczone dla tej wersji <em>immudex</em>.
+        Poniżej znajduje się przykładowy plik wersji 
+        (<em>testing, wersja 0.1.9</em>).
+      </p>
+<pre class="code-block">
+#!/bin/bash
+
+function update_packages() {
+  dhclient; 
+  apt update;
+  apt upgrade -y;
+}
+
+function install_packages() {
+  apt install $@ -y;
+}
+
+function get_immudex_testing_project() {
+  if [ ! -d ~/immudex-testing ]; then
+    cd;
+    git clone https://github.com/xf0r3m/immudex-testing.git;
+  fi
+}
+
+function recreate_users() {
+  userdel -r user;
+  userdel -r xf0r3m;
+
+  useradd -m -s /bin/bash user;
+  if [ ! -f /home/user/.vimrc ]; then
+    cp -rvv /etc/skel/.??* /home/user;
+    cp -rvv /etc/skel/?* /home/user;
+    mkdir /home/user/.local;
+    tar -xvf ~/immudex-testing/files/017/local_user.tar -C /home/user/.local;
+    rm /home/user/.face;
+    cp /usr/share/images/desktop-base/immudex_xfce_greeter_logo.png /home/user/.face;
+    chown -R user:user /home/user;
+  fi
+  echo "user:user1" | chpasswd;
+
+  useradd -m -s /bin/bash xf0r3m;
+  if [ ! -f /home/xf0r3m/.vimrc ]; then
+    cp -rvv /etc/skel/.??* /home/xf0r3m;
+    cp -rvv /etc/skel/?* /home/xf0r3m;
+    mkdir /home/xf0r3m/.local;
+    tar -xvf ~/immudex-testing/files/017/local_xf0r3m.tar -C /home/xf0r3m/.local;
+    rm /home/xf0r3m/.face;
+    cp /usr/share/images/desktop-base/immudex_xfce_greeter_logo.png /home/xf0r3m/.face;
+    chown -R xf0r3m:xf0r3m /home/xf0r3m;
+  fi
+  echo "xf0r3m:xf0r3m1" | chpasswd;
+
+  usermod -aG libvirt,libvirt-qemu xf0r3m;
+  usermod -aG libvirt,libvirt-qemu user;
+}
+
+function tidy() {
+  apt-get clean;
+  apt-get clean;
+  apt-get autoremove -y;
+  apt-get autoclean;
+  rm -rf ~/immudex-testing;
+  echo &gt; ~/.bash_history;
+  history -c   
+}
+
+function set_default_wallpaper() {
+  rm /usr/share/images/desktop-base/default;
+  ln -s /usr/share/images/desktop-base/$1 /usr/share/images/desktop-base/default;
+}
+
+function set_notifier_packages() {
+  cp -vv ~/immudex-testing/files/011/Notifier\ -\ packages.desktop /home/xf0r3m/.config/autostart;
+  chown xf0r3m:xf0r3m /home/xf0r3m/.config/autostart/Notifier\ -\ packages.desktop;
+}
+
+VERSION=$(echo $0 | cut -d "." -f 1);
+if [ ! "$VERSION" ]; then echo -e "\e[31mUpdate failed!\e[0m"; exit 1; fi;
+
+update_packages;
+install_packages gimp isolinux;
+
+get_immudex_testing_project;
+
+cp -vv ~/immudex-testing/images/${VERSION}/abandoned_hospital_bower.png /usr/share/images/desktop-base;
+
+sed -i 's/no_trespass_abandon.jpeg/abandoned_hospital_bower.png/' /etc/lightdm/lightdm-gtk-greeter.conf;
+
+rm /etc/apt/source.list;
+
+tidy;
+
+</pre>
+      <p>
+        Niektóre pliki wersji mogą być bardzo ubogie. Zawierać dwie trzy
+        instrukcje i to dzięki użyciu funkcji, w których zawarto typowe i
+        powtarzalne czynności wykowane podczas każdej aktualizacji, takie jak
+        aktualizacja zainstalowanego oprogramowania czy posprzątanie po sobie.
+        Po warunku określającym, czy aktualizacj w ogóle powiedzie się 
+        <code class="code-inline">if [ ! "$VERSION ];...</code> rozpoczyna się
+        seria czynności definiujących tę wersję systemu.
+      </p>
+      <p>
+        Uruchomienia tego pliku dokonuje się w środowisku zmienionego katalogu
+        głónego, po przez wywołanie powłoki BASH, podając ten plik jako
+        argument. Na przykład:
+      </p>
+<pre class="code-block">
+$ sudo chroot immudex-testing/64/chroot bash 019.sh
+</pre>
+      <p>
+        Przyglądając się temu strukturze tego skryptu, od razu rzuca się w oczy
+        potencjał optymalizacyjny. Na początku musimy sobie jednak odpowiedzieć
+        na jedno pytanie. Skąd biorą się te definicje funkcji? Definicje
+        funkcji są składowane wraz plikami wersji w tym samym katalogu pod
+        postacią pliku szablonu (<em>template.sh</em>). To jeśli definicje
+        znajdują się w odrębnym pliku to zamiast je kopiować można je
+        przecież załadować do pliku za pomocą polecenia <strong>source</strong>
+        lub instrukcji kropki (<strong>.</strong>). Tu pojawia się problem,
+        którego wolelibyśmy uniknąć a mianowicie kopiowana kolejnych plików do
+        <em>rootfs</em>. I go unikniemy wykorzystując to co już mamy dostępne.
+      </p>
+      <p>
+        Zamiast zaczynać plik serii definicji funkcji, pobierzemy je z
+        repozytorium:
+      </p>
+<pre class="code-block">
+dhclient;
+cd;
+if [ -x /usr/bin/git ]; then git clone https://github.com/xf0r3m/immudex-testing.git;
+else apt install git &amp;&amp; git clone https://github.com/xf0r3m/immudex-testing.git;
+fi
+</pre>
+      <p>
+        Teraz plik szablonu (plik z definicjami) możemy załadować do pliku
+        wersji.
+      </p>
+<pre class="code-block">
+source ~/immudex-testing/versions/template.sh;
+</pre>
+      <p>
+        Teraz od tej linii rozpoczyna się plik wersji. Warto też dodać, że
+        funkcja odpowiedzialna za sklonowanie repozytorium przestaje być
+        potrzebna, ponieważ zrobi to teraz każdy plik wersji na początku
+        wykonania. Warto dopisać do początku polecenie <strong>dhclient</strong>
+        aby odświerzyć połączenie sieciowe. Przedstawiony na początku
+        materiału przykład po optymalizacji prezentuje się w taki o to sposób.
+      </p>
+<pre class="code-block">
+dhclient;
+cd;
+if [ -x /usr/bin/git ]; then git clone https://github.com/xf0r3m/immudex-testing.git;
+else apt install git &amp;&amp; git clone https://github.com/xf0r3m/immudex-testing.git;
+fi
+source ~/immudex-testing/versions/template.sh;
+update_packages;
+install_packages gimp isolinux;
+
+cp -vv ~/immudex-testing/images/${VERSION}/abandoned_hospital_bower.png /usr/share/images/desktop-base;
+
+sed -i 's/no_trespass_abandon.jpeg/abandoned_hospital_bower.png/' /etc/lightdm/lightdm-gtk-greeter.conf;
+
+rm /etc/apt/source.list;
+
+tidy;
+</pre>
+      <p>
+        Podsumowując pliki wersji to nic innego jak skrypty, które wdrażają
+        zmiany przeznaczone dla tej wersji systemu.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/immudex/transformacja_gnu_linux_debian_w_immudex.html b/articles/immudex/transformacja_gnu_linux_debian_w_immudex.html
new file mode 100755 (executable)
index 0000000..684de53
--- /dev/null
@@ -0,0 +1,288 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+ _                               _           
+(_)_ __ ___  _ __ ___  _   _  __| | _____  __
+| | '_ ` _ \| '_ ` _ \| | | |/ _` |/ _ \ \/ /
+| | | | | | | | | | | | |_| | (_| |  __/>  < 
+|_|_| |_| |_|_| |_| |_|\__,_|\__,_|\___/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+                 <h1 class="title">Transformacja GNU/Linux Debian w immudex - Budowanie</h1>
+                 <p>
+        Chcąc podnieść swój poziom bezpieczeństwa na nieco wyżej,
+        uznałem, że dobry pomysłem będzie użycie systemu, który jest niezmienny.
+        Za najprostszą formę niezmienności uznałem systemy uruchamiane z
+        poziomu <em>LiveCD</em>. Gdy taki system się uruchamia, zostaje
+        uruchomione jądro oraz <em>initrd</em>, montowane jest
+        archiwum <em>squashfs</em>, a dysk na którym są zapisane te elementy
+        pozostaje w trybie tylko do odczytu. Uruchamiając komputer ponownie
+        wszystko powróci do swojej pierwotnej formy. Tę dystrybucję oparłem 
+        o GNU/Linux Debian z dwóch powodów. Pierwszym z nich jest 
+        doświadczenie. Otóż
+        już wcześniej zajmowałem się dystrybucją pochodną od Debiana oraz
+        stabliność, GNU/Linux Debian to bardzo stablina dystrybucja. Ten
+        materiał ma za zadnie przedstawić w jaki sposób można utworzyć obraz
+        płyty z niezmiennym systemem operacyjnym.
+      </p>
+      <p>
+        Do budowy <em>immudex</em> potrzebujemy kilku pakietów do utworzenia
+        końcowego obrazu płyty oraz plików, które on będzie zawierać.
+      </p>
+<pre class="code-block">
+$ sudo apt install -y debootstrap squashfs-tools xorriso isolinux syslinux-efi\
+grub-pc-bin grub-efi-amd64-bin mtools dosfstools git vim
+</pre>
+      <p>
+        Teraz możemy utworzyć katalog przeznaczony na nasz system, jeśli
+        będziemy obsługiwać obie architektury komputerów klasy PC tj.
+        <em>amd64</em> lub <em>i386</em>, to wypadało by utworzyć podkatalogi
+        dla obu.
+      </p>
+<pre class="code-block">
+$ mkdir -p immudex/{64,32};
+</pre>
+      <p>
+        Po utworzeniu początkowych katalogów, możemy pobrać czysty obraz
+        katalogu głównego z jednego z dostępnych serwerów lustrzanych.
+      </p>
+<pre class="code-block">
+$ sudo /sbin/debootstrap --arch=amd64 bullseye ~/immudex/64/chroot http://ftp.icm.edu.pl/debian
+</pre>
+      <p>
+        Polecenie <code class="code-inline">debootstrap</code> służy do pobrania
+        oraz instalacji obrazu we wskazane miejsce
+        (<code class="code-inline">~/immudex/64/chroot</code>). Wersja stablina
+        <em>immudex</em> jest analogiczna do Debiana więc jako nazwę kodową
+        wersji podajemy <code class="code-inline">bullseye</code> (wersja
+        stablilna na czas pisania tego materiału). Tak samo jest z wersją 
+        testową. Ostatni argument to adres najszybszego dla nas serwera
+        lustrzanego z repozytorium Debiana. Dla mnie jest SunSITE ICM UW.
+      </p>
+      <p>
+        Na chwilę opuszczamy utworzony wcześniej katalog <em>~/immudex</em>,
+        aby pobrać pliku projektu z serwisu GitHub: <a href="https://github.com/xf0r3m/immudex">https://github.com/xf0r3m/immudex</a>.
+        Do tego celu najlepiej wybrać takie miejsce, w którym możemy pozostawić
+        po sobie bałagan. Katalog <em>~/Pobrane</em> świetnie się do tego
+        nadaje.
+      </p>
+<pre class="code-block">
+$ if [ ! -d ~/Pobrane ]; then mkdir ~/Pobrane; fi
+$ cd ~/Pobrane
+$ git clone https://github.com/xf0r3m/immudex.git;
+</pre>
+      <p>
+        Pośród pobranych plików projektu znajduje się 
+        <strong>bazowy plik wersji</strong> (<em>versions/base.sh</em>), który
+        wykorzystywany jest do budowania <em>immudex</em> od zera. Od czystej
+        wersji Debiana. Ten plik musimy skopiować do katalogu, w którym 
+        <em>debootstrap</em> wypakował obraz Debiana.
+      </p>
+<pre class="code-block">
+$ sudo cp -v ~/Pobrane/immudex/version/bash.sh ~/immudex/64/chroot;
+</pre>
+      <p>
+        Plik ten musi zostać uruchomiony przez powłokę w zmienionym katalogu
+        głównym. Skrypt aby mógł prawidłowo określić pakiety jakie trzeba
+        pobrać (na przykład jądro) oczekuje również na podanie architektury 
+        (w tym przypadku jest to 64 dla <em>amd64</em> lub 32 dla 
+        <em>i386</em>),
+      </p>
+<pre class="code-block">
+$ sudo chroot ~/immudex/64/chroot bash base.sh 64
+</pre>
+      <p>
+        Program zainstaluje wszystkie pakiety oferowane przez pierwszą wersję
+        <em>immudex</em>, uzupełni system o kilka autorskich narzędzi
+        ułatwiających pracę z dystrybucją zgodnie z jej koncepcją
+        (oczywiście wszystko zostało stworzone, w taki sposób aby niczego
+        nie narzucać. Wszystko można w łatwy sposób obejść) oraz skonfiguruje
+        środowisko graficzne. Wszystkie czynności można sprawdzić analizując
+        plik, który znajduje się w repozytorium: <a href="https://github.com/xf0r3m/immudex/blob/main/versions/base.sh">https://github.com/xf0r3m/immudex/blob/main/versions/base.sh</a>
+      </p>
+      <p>
+        Po zakończeniu wykonywania czynności przez skrypt, możemy go usunąć,
+        aby nie zaśmiecać obrazu.
+      </p>
+<pre class="code-block">
+$ sudo rm -f ~/immudex/64/chroot/base.sh;
+</pre>
+      <p>
+        Teraz kiedy <em>rootfs</em> jest gotowy. Możemy zająć się pozostałymi
+        plikami do okoła niego. Wrócimy jeszcze do niego, tworząc z katalogu
+        archiwum <em>squashfs</em>. Nasze czynności rozpoczniemy od utworzenia
+        struktury katalogowej, której część znajdzie się na obrazie płyty.
+      </p>
+<pre class="code-block">
+$ mkdir -p ~/immudex/64/{staging/{EFI/boot,boot/grub/x86_64-efi,isolinux,live},tmp}
+</pre>
+      <p>
+        Po tym jak utworzyliśmy odpowiednie miejsce w strukturze, możemy teraz
+        wygenerować z katalogu <em>chroot</em> archiwum <em>squashfs</em>. Ten
+        proces może trochę potrwać w zależności od mocy naszego komputera.
+        Istotnym faktem tutaj jest nazwa pliku archiwum <em>squashfs</em>.
+        Nie jest ona przypadkowa, pod tą nazwą program <em>live-boot</em>
+        odpowiedzialny za obsługę środowiska LiveCD będzie domyślnie szukać
+        pliku o nazwa <strong>filesystem.squashfs</strong> i będzie próbować
+        użyć go jako katalogu głównego. Wcześniej montując archiwum.
+      </p>
+<pre class="code-block">
+$ sudo mksquashfs ~/immudex/64/chroot ~/immudex/64/staging/live/filesystem.squashfs -e boot
+</pre>
+      <p>
+        Przygotowując <em>squashfs</em> nie możemy zapomnieć o jądrze oraz
+        <em>initrd</em>. Nazwy plików jądra oraz <em>initrd</em>, zostały 
+        dobrane pod istniejące już pliki konfiguracyjne programów rozruchowych.
+      </p>
+<pre class="code-block">
+$ cp -v $(ls -v ~/immudex/64/chroot/boot/vmlinuz-* | tail -1) ~/immudex/64/staging/live/vmlinuz
+$ cp -v $(ls -v ~/immudex/64/chroot/boot/initrd.img-* | tail -1) ~/immudex/64/staging/live/initrd
+</pre>
+      <p>
+        Już tłumaczę skąd wzięło się te podstawienia. Otóż, czasami może się
+        zdarzyć, że katalog <em>/boot</em> będzie zawierał dwa jądra. Ponieważ
+        przeważnie w dystrybucjach Linuksa tak jest. Jest "nowe" domyślne jądro
+        oraz "stare" zapasowe wrazie gdy to nowe okaże się wadliwe. Wyżej
+        wymienione podstawienia, uzupełnią polecenie nazwami plików nowszych
+        wersji.
+      </p>
+      <p>
+        Po skopiowaniu plików jądra. Możemy zająć teraz kwestią uruchomienia
+        systemu, a co za tym idzie - instalacja oraz konfiguracja programów
+        rozruchowych. <em>Immudex</em> wspiera dwa tryby rozruchu: rozruch w
+        trybie BIOS oraz w trybie UEFI (ale tylko UEFI 64-bitowe, domyślnie.
+        Gdyż można przystosować pamięc USB do uruchomienia na komputerach z
+        32-bitowym UEFI - narzędzie <em>create_media</em>). Konfiguracja
+        tych programów nie jest trudna, wystarczy kilka poleceń. Na początek
+        zaczniem od załadowania do struktury katalogowej plików
+        konfiguracyjnych. Za rozruch w trybie BIOS odpowiada program
+        <strong>isolinux</strong>, część projektu <em>syslinux</em>, który
+        będzie odpowiadać za rozruch już zainstalowanego <em>immudex</em> na
+        dysku (o tym w innym materiale). Natomiast za rozruch w trybie UEFI
+        odpowiada GRUB w wersji 2. Pliki konfiguracyjne znajdują się wśród
+        plików projektu <em>immudex</em>.
+      </p>
+<pre class="code-block">
+$ cp -v immudex/isolinux/amd64/* ~/immudex/64/staging/isolinux;
+$ cp -v immudex/grub/amd64/* ~/immudex/64/staging/boot/grub
+</pre>
+      <p>
+        Następną czynnością jest utworzenie pliku konfiguracyjnego dla
+        samodzielnego pliku GRUB-a. W tym pliku wskazane jest
+        katalog główny, ustalenie <em>prefiksu</em> dla ścieżek, oraz wskazanie
+        pliku konfigracyjnego dla GRUB-a.
+      </p>
+<pre class="code-block">
+$ cat &gt;&gt; ~/immudex/64/tmp/grub-standalone.cfg &lt;&lt;EOF
+search --set=root --file /DEBIAN
+set prefix=(\$root)/boot/grub
+configfile /boot/grub/grub.cfg
+EOF
+</pre>
+      <p>
+        Pierwsza linia na powyższym przykładzie powoduje ustawienie zmiennej
+        <code class="code-inline">root</code> scieżki dysku zawierającego plik
+        <code class="code-inline">DEBIAN</code>. Więc, aby GRUB ustawił katalog
+        główny obrazu jako swój główny katalog, musi się na nim znajdować
+        "luzem" plik o nazwie <code class="code-inline">DEBIAN</code>. 
+      </p>
+<pre class="code-block">
+$ touch ~/immudex/${arch}/staging/DEBIAN;
+</pre>
+      <p>
+        Aby programy rozruchowe mogły prawidło działać potrzebują plików
+        pomocniczych. Te pliki są instalowane wraz z pakietami, które 
+        dostarczają do naszych systemów te programy. Poniżej znajdują się
+        polecenia, których zadaniem jest skopiowanie plików pomocniczych
+        programów rozruchowych do struktury katalogowej obrazu płyty.
+      </p>
+<pre class="code-block">
+$ cp -v /usr/lib/ISOLINUX/isolinux.bin ~/immudex/64/staging/isolinux;
+$ cp -v /usr/lib/syslinux/modules/bios/* ~/immudex/64/staging/isolinux;
+$ cp -rv /usr/lib/grub/x86_64-efi/* ~/immudex/64/staging/boot/grub/x86_64-efi
+</pre>
+      <p>
+        Teraz możemy utworzyć plik wykonywalny GRUB, który następnie zostanie 
+        załadowany do partycji UEFI:
+      </p>
+<pre class="code-block">
+$ grub-mkstandalone --format=x86_64-efi\
+--output=${HOME}/immudex/64/staging/EFI/boot/bootx64.efi --locales=""\
+--fonts="" "boot/grub/grub.cfg=${HOME}/immudex/64/tmp/grub-standalone.cfg";
+</pre>
+      <p>
+        Ciekawym argumentem jest tutaj ostatni argument, gdyż zawiera on 
+        mapowania plików. W przypadku tego pliku konfiguracyjnego GRUB-a jego
+        plikiem jest plik <em>~/immudex/64/tmp/grub-standalone.cfg</em>, 
+        o którym już wspomniałem. Tamten zaś
+        wskazuje na właściwy już plik, w którym widnieją wpisy rozruchowe.
+      </p>
+      <p>
+        Tak utworzony plik możemy skopiować do partycji EFI, która w przypadku
+        obrazów płyt jest plkiem. Poniżej znajdują polecenia, które tworzą
+        plik partycji.
+      </p>
+<pre class="code-block">
+$ cd ~/immudex/64/staging/boot/grub
+$ dd if=/dev/zero bs=1M of=efiboot.img count=20
+$ sudo mkfs.vfat efiboot.img
+$ sudo mmd -i efiboot.img efi efi/boot
+</pre>
+      <p>
+        Po utworzeniu pliku partycji oraz utworzeniu na nim odpowiednich
+        folderów (ostatnie polecenie). Możemy skopiować nasz plik GRUB-a.
+      </p>
+<pre class="code-block">
+$ sudo mcopy -vi efiboot.img ~/immudex/64/staging/EFI/boot/bootx64.efi ::efi/boot 
+</pre>
+      <p>
+        Po wykonaniu tej czynności obraz w postacji struktury katalogów i
+        plików jest gotowy. Pozostała do wykonania jedna czynność. Zmiana tej
+        struktury w jeden plik, który będzie mógł być zapisany na płycie lub
+        nośniku USB, a następnie komputer będzie mógł być z niego uruchomiony.
+      </p>
+<pre class="code-block">
+cd ~/immudex/64;
+xorriso as mkisofs -iso-level 3 -o "immudex64.iso" -full-iso9660-filenames\
+-volid "immudex64" -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin\
+-eltorito-boot isolinux/isolinux.bin -no-emul-boot -boot-load-size 4\
+-boot-info-table --eltorito-catalog isolinux/isolinux.cat -eltorito-alt-boot\
+-e /boot/grub/efiboot.img -no-emul-boot -isohybrid-gpt-basdat\
+-append_partition 2 0xef ~/immudex/${arch}/staging/boot/grub/efiboot.img\
+~/immudex/64/staging
+</pre>
+      <p>
+        Poszczególne opcje polecenie <code class="code-inline">xorriso</code>
+        ustawiają odpowiednio programy rozruchowe, aby były one uruchamiane
+        podczas uruchamiana komputera z róznym rodzajem oprogramowania
+        układowego. Obraz jest również ustawiony tak, aby hybrydą obrazu płyty
+        oraz obrazu dysku, przez co może być załadowany bezpośrednio do pamięci
+        USB. Dzięki tej czynności jesteśmy w stanie uruchomić komputer z
+        pendrive-a.
+      </p>
+      <p>
+        Podsumowując dużą role w transformacji Debiana w <em>immudex</em>
+        odgrywa bazowy plik wersji. Po za kilkoma szczegółami, prowadzona
+        przeze mnie dystrybucja Linuksa dalej pozostaje Debianem. Nie chciałem
+        tworzyć nowego bytu, a raczej dostoswać obecny byt do swoich potrzeb.
+        Wiele z technik rekomendowanych to tworzenia obrazów z Debianem nie
+        zostało tutaj użytych.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+    </div>
+  </body>
+</html>
diff --git a/articles/linux/Alpine_Linux_jako_bramka_sieciowa.html b/articles/linux/Alpine_Linux_jako_bramka_sieciowa.html
new file mode 100644 (file)
index 0000000..302d75a
--- /dev/null
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+
+               <h1 class="title">Alpine Linux jako bramka sieciowa</h1>
+               <p>
+                       Ostatnio budowaliśmy bramkę w oparciu o system OpenBSD, nie było to jakoś trudne zdanie. Teraz zajemiemy się tym samym zagadniem co poprzednio,
+                       tylko że z systemem GNU/Linux. Do tego celu wybrałem kolejną dystrybucje, która jest nieco bardzie podrasowana jeśli chodzi o bezpieczeństwo,
+                       prosto z Norwegii, <strong>Alpine Linux</strong>. Ciekawą rzeczą w tej dystrybucji jest to że możemy zainstalać usługę, która umożliwi nam kontrolowanie
+                       naszego systemu z poziomu przeglądarki. Nie ma się co napalać, jak szczerbaty na suchary, ale to zawsze coś. Może pojawi się tutaj jakiś
+                       materiał odnośnie <em>ACF</em>, bo tak to się dokładnie nazywa. Pozwole sobie tutaj na nawiązania do materiału o robieniu bramki z OpenBSD, pozowoli
+                       to ograniczyć wypełniacz merytoryczny, przez co ten artykuł będzie znacznie krótszy.
+               </p>
+               <p><strong>
+                       Uwaga! Wszystkie znajdujące się tu polecenia wykonujemy z poziomu użytkownika <em>root</em>.
+               </strong></p>
+               <ol>
+                       <li>Instalacja systemu
+                               <p>
+                               Instalacja Alpine Linux została już tutaj przedstawiona jednym z umieszczonych tutaj materiałów. Podobnie jak na OpenBSD jeśli czytamy
+                                to jeszcze przed rozpoczęciem jakich kolwiek prac, to ustawienia interfejsów sieciowych możemy skonfigurować już na poziomie instalatora.
+                               </p>
+                       </li>
+                       <li>Instalacja niezbędnego oprogramowania
+                               <p>
+                                       Menedżerem pakietów w Alpine jest program <strong>APK</strong>, jak rozszerzenie paczek oprogramowania na Androidzie. Dystrybucja po instalacji pozostaje natywnie pusta, aby dać użytkownikowi jak największe pole do manewru. Do zainstalowania mamy aż trzy pakiety: ISC DHCPD - <em>dhcp</em>, <em>dnsmasq</em>, <em>iptables</em>. Aby użyć polecenia <code class="code-inline">apk</code> do instalacji pakietów należy użyć opcji <code class="code-inline">add</code> następnie po niej podać nazwę interesującego nas pakietu.
+                               </p>
+<pre class="code-block">
+# apk add dhcp dnsmasq iptables
+</pre>
+                               <p>
+                                       Po zainstalowaniu potrzebnych usług oraz programów, możemy przejść do ich konfiguracji. Na początek, tak samo jak przy OpenBSD skupimy się na DHCP.
+                               </p>
+                       </li>
+                       <li>Konfiguracja DHCP
+                               <p>
+                                       Aby daemon DHCP mógł odczytać nasz plik konfiguracji musimy nazwać <em>dhcpd.conf</em> i umieścić w katalogu <em>/etc/dhcpd</em>. Konfiguracja tutaj jest identyczna do tej jaką tworzliśmy na dla OpenBSD, ponieważ jest to ten sam program. Dla leniwych, którym nie chce się przejrzeć tamtego artykułu i dla samej zapachajdziury, opisze linia po linii konfiguracje DHCP.
+                               </p>
+<pre class="code-block">
+subnet 192.168.0.0 netmask 255.255.255.0 {
+       range 192.168.0.100 192.168.0.199;
+       option routers 192.168.0.1;
+       option domain-name "morketsmerke.net";
+       option domain-name-servers 192.168.0.1;
+}
+</pre>
+                               <p>
+                                       Pierwsza linia otwiera nam deklaracje pod sieci, po słowie <code class="code-inline">subnet</code> występuje adres sieci, z kolei po słowie <code class="code-inline">netmask</code> maska sieciowa. W następnej linii deklarowany jest zakres adresów przeznaczonych dla hostów w naszej sieci. <code class="code-inline">option routers</code> będzie przekazywać taki parametr adres bramy domyślnej, <code class="code-inline">option domain-name</code> zawiera sufiks DNS dla naszych hostów a ostatnia linia <code class="code-inline">option domain-name-servers</code> zawiera adresy serwerów DNS, może być ich wiele, jednak nie wszystkie systemu obsługują więcej niż dwa adresy. W przykłdzie znajduje się tylko jedna sieć jeśli nasza bramka ma obsługiwać więcej sieci to deklaracje można powtórzyć oczywiście dostosowując ją do adresacji zastosowanej w owej sieci.
+                               </p>
+                               <p>
+                                       Jako ciekawostkę albo nieco bardzie zaawansowaną konfiguracje podam że rezerwacje adresów, które wyglądają o tak:
+                               </p>
+<pre class="code-block">
+host admin-komputer {
+       hardware ethernet 00:de:ad:be:ef:00;
+       fixed-address 192.168.0.10;
+       option host-name "admtop";
+}
+</pre>
+                               <p>
+                                       Rezerwacje mogą zupełnie wybiegać poza zakres, a daemon i tak nada zarezerwowane adresy tym komputerom.
+                               </p>
+                       </li>
+                       <li>Konfiguracja daemona DHCP<br />
+                               <p>
+                                       Do uruchomienia daemona w Alpine Linux wykorzystywany jest jeszcze jeden plik <em>/etc/conf.d/dhcpd</em>. W tym pliku musimy ustawić dwie zmienne <code class="code-inline">DHCPD_CONF</code> oraz <code class="code-inline">DHCPD_IFACE</code>, aby je ustawić nadajemy im wartość i usuwamy poprzedzający je znak komentarza. Jakie wartości należy im nadać? Otóż zmienna <code class="code-inline">DHCPD_CONF</code> przechowuje ścieżkę to pliku konfiguracyjnego. Wartość tej zmiennej może już wskazywać na nasz pliki, jeśli nie to należy to skorygować. Zmienna <code class="code-inline">DHCPD_IFACE</code>, przechowuje interfejsy na jakich nasłuchiwać ma nasze DHCPD.
+                               </p>
+<pre class="code-block">
+DHCPD_CONF="/etc/dhcpd/dhcpd.conf";
+DHCPD_IFACE="eth0 eth1";
+</pre>
+                               </p>
+                       </li>
+                       <li>Ustawienie interfejsu dla dnsmasq<br />
+                               <p>
+                                       Podobnie do konfiguracji zastosowanej w OpenBSD i w tym przypadku jeśli dnsmasq ma nam służyć tylko i wyłącznie jako maskarada DNS lub przekaźnik (bo taką rolę pełni) to nie potrzeba w zasadzie nic konfigurować, jedne co należy zrobić to wskazać odpowiednie interfejsy. W pliku konfiguracyjnym odnajdujemy opcje <code class="code-inline">#interface</code> jest ujęta w komentarz aby ją włączyć musimy usunąć znak komentarza, a po znaku równości (<strong>=</strong>) wpisać nazwę interfejsu.
+                               </p>
+<pre class=="code-block">
+interface=eth1
+</pre>
+                               <p>
+                                       Następnie zapisujemy oraz restartujemy usługę, tutaj warto wspomnieć, że Alpine Linux jest dystrybucją opartą na <strong>OpenRC</strong>, a więc restart usługi odbywa się jak w starych systemach GNU/Linux.
+                               </p>
+<pre class="code-block">
+# /etc/init.d/dnsmasq restart
+</pre>
+                               <p>
+                                       Identycznie jak przy OpenBSD, jeśli chcemy wymusić nasłuchiwanie na konkretnym interfejsie, musimy odblokować opcję <code class="code-inline">bind-interfaces</code>.
+                               </p>
+<pre class="code-block">
+bind-interfaces
+</pre>
+                       </li>
+                       <li>Ewentualne wpisy do <em>/etc/hosts</em>*<br />
+                               <p>
+                                       Wykorzystując plik <em>/etc/hosts</em> na naszej bramce możemy zdefiniować nazwy domenowe dla naszych serwerów w sieci lokalnej. Przeważnie w konfiguracji odpytywania UNIX-y skonstrułowane są w taki sposób że na początku sprawdzają zawartość tego pliku, i jeśli nie znajdą odpowiedniego dla zapytania rekordu, kierują zapytanie do swoich adresów DNS. Format wpisu jest taki sam dla wszystkich UNIX-ów, składa się on z trzech części: adresu IP, FQDN (pełnej nazwy domenowej), hostname (nazwy hosta). Nazw hosta możemy używać tylko jeśli na naszym komputerze został został zdefiniowany sufiks DNS. Przykładowy wpis znajduje się poniżej:
+                               </p>
+<pre class="code-blocks">
+192.168.0.10 serwer.morketsmerke.net serwer
+</pre>
+                       </li>
+                       <li>NAT<br />
+                               <p>
+                                       Podbnie jak w przypadku <em>PF</em> (pakiet firewalla na OpenBSD) <strong>NAT</strong> to jedna reguła. Reguła, która do poprawnego działania wymaga przestawienia opcji jądra, opcji przekazywania pakietów z jednego interfejsu na drugi wewnątrz systemu. Poniżej znajdują się polecenia jakie należy wykonać aby uruchomić NAT.
+                               </p>
+<pre class="code-block">
+# iptables -t NAT -A POSTROUTING -o eth0 -j MASQUERADE
+# echo 1 &gt; /proc/sys/net/ipv4/ip_forward
+</pre>
+                               <p>
+                                       Pierwsze polecenie jest ustawieniem reguły pakietu zapory sieciowej na GNU/Linux, którą jest <strong>iptables</strong>. Przy iptables reguły dodawane są na bieżąco, a co za tym idzie będą tak długo załadowane jak długo uruchomiony jest system. To jest jedna z różnic pomiędzy PF a iptables. Do trwałego zapisania reguł będzie potrzebny nam zewnętrzny pakiet. Tym zajmiemy się na koniec. Teraz przejdźmy samej reguły. Przełącznik <code class="code-inline">-t</code> wskazuje nam tablice - zbióry reguł stosowane na podstawie przeznaczenia pakietów. Na przykład reguły podejmujące działania pakietach wygenerowanych przez bramkę lub do niej zaadresowane zostaną zdefiniowane w innej tablicy niż te które mają działać na pakietach, które przez tą bramkę przechodzą. Nas będą interesować tylko tablice <code class="code-inline">filter</code> (tablica domyślna), która zajmuje się pakietami z i do bramki oraz tablica <code class="code-inline">nat</code>, zajmująca się pakietami przecodzącymi przez bramkę.
+                                       W iptables są jeszcze dwie tablice, jednak na nie są nam one potrzebne także ich opis pominę. Opcja <code class="code-inline">-A</code> spowoduje dopisanie naszej reguły na końcu łańcucha. Łańcuchy są to podzbiory reguł, których cechą charkterystyczną jest konkretny moment podróży pakietu za nim dotrze do aplikacji, której dane przenosi lub zostanie przesłany dalej w głąb innych sieci. Najproście zobrazować to sobie w ten sposób, że do kiedy pakiet dociera do systemu zawsze na początku trafia do łańcucha <code class="code-inline">PREROUTING</code> tablicy <code class="code-inline">nat</code> w tym łańcuchu dokonywane są wszelkie zmiany (akcje) dla pakietu, kiedy tylko się pojawi, może zostać przekierowany albo do łańcucha <code class="code-inline">INPUT</code> albo do łańcucha <code class="code-inline">FORWARD</code> tablicy <code class="code-inline">filter</code> łańcuch <code class="code-inline">INPUT</code> przeznaczony jest dla pakietów kierowanych dla tego komputera,
+                                       z kolei łańcuch <code class="code-inline">FORWARD</code> dla tych pakietów, które przechodzą przez ten komputer. Jeśli pakiet trafił do <code class="code-inline">INPUT</code>, wtedy trafia lokalnego procesu.
+                                       Proces może odpowiedzieć, wygerowany przez proces pakiet trafia najpierw do odpowiedniego łańcucha tj. <code class="code-inline">OUTPUT</code> tablicy <code class="code-inline">filter</code> następnie do łańcucha <code class="code-inline">OUTPUT</code> tablicy <code class="code-inline">nat</code>, gdzie mogą być dokonywane zmiany dla wygenerowaych pakietów.
+                                       Tutaj obydwie ścieżki łączą się ponieważ pakiety opuszaczające łańcuch <code class="code-inline">FORWARD</code> oraz łańcuch <code class="code-inline">OUTPUT</code> tablicy <code class="code-inline">nat</code> są przetwarzane ostatecznie w łańcuchu <code class="code-inline">POSTROUTING</code> tablicy <code class="code-inline">nat</code>, czyli momencie gdy mają opuścić ten komputer. Tutaj właśnie wykorzystywana jest akcja <code class="code-inline">MASQUERADE</code>, która zapisaliśmy w pierwszym poleceniu, po łańcuchu umieszczony jest przełącznik <code class="code-inline">-o</code> określający interfejs wyjściowy (nasz interfejs podłączony do internetu).
+                                       Ostatnią składową jest reguły jest cel/akcja (po przełączniku <code class="code-inline">-j</code>) podejmowana na pakiecie, kiedy zostaje dopasowany do reguły.
+                                       Podsumowując pakiety przechodzą z tablicy do tablicy z łańcucha do łańcucha w poszukiwaniu pasujących reguł, kiedy reguła zostanie dopasowana wtedy podejmowany jest dla pakietu cel/akcja, może być ona <code class="code-inline">ACCEPT</code> lub <code class="code-inline">DROP</code> lub specjalna jak <code class="code-inline">MASQUERADE</code>.
+                               </p>
+                               <p>
+                                       Odnośnie zamiany adresów czyli właśnie NAT-u to istnieją dwa sposoby. Jeśli nasz adres na interfejsie podłączonym do sieci rozległej/Internetu jest przydzielany dynamicznie powinniśmy użyć własnie <code class="code-inline">MASQUERADE</code> jeśli nasz adres jest stały, to wtenczas należało by użyć <code class="code-inline">SNAT</code> a następnie podać za pomocą dodatkowej opcji <code class="code-inline">--to-source</code> adres jakie należy użyć podczas NAT-u.
+                               </p>
+<pre class="code-block">
+# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 10.20.40.34
+</pre>
+                               <p>
+                                       Drugie polecnie nie jest już tak skomplikowane, uruchamia ono przekazywanie pakietów wewnątrz systemu.
+                               </p>
+                       </li>
+                       <li>Zapisanie reguł do pliku<br />
+                               <p>
+                                       Niestety reguły iptables są przechowywane w łańcuchach do momentu kolejnego uruchomienia komputera. W Alpine Linux wraz z iptables otrzymujemy polecenie <code class="code-inline">iptables-save</code>, którego uruchomienie spowoduje wyświetlenie nam tablic z łańcuchami w formacie, który poźniej pozwoli na ich automatyczne przywrócenie, aby całość zadziałała po ustawieniu NAT-u należy przekierować wyjście tego właśnie polecenia do pliku <em>/etc/iptables/rules-save</em>. Przy zapisie reguł warto pamiętać o tym że włączenie przekazywania pakietów w systemie też powinno się odbywać automatycznie. Możemy zrobić to na dwa sposoby. Pierwszy z nich to dopisanie opcji <code class="code-inline">net.ipv4.ip_forward = 1</code> do pliku <em>/etc/sysctl.d/00-alpine.conf</em> lub skorzystać z konfiguracji iptables w <em>/etc/conf.d/iptables</em>, gdzie powinniśmy znaleźć opcje <code class="code-inline">IPFORWARD</code>, która należy przestawić na <code class="code-inline">yes</code>.
+                               </p>
+                       </li>
+                       <li>Ustawienie autostartu usług
+                               <p>
+                                       Alpine Linux jest dystrybucją, która została nieco inaczej zbudowana niż te powszechnie nam znane, w których programem typu init jest moloch systemd, który automatycznie załącza znane usługi do startu wraz z systemem, najwyżej usługa nie wystartuje z powodu braku konfiguracji. Tutaj programem typu init jest OpenRC, gdzie sytuacja nie jest już tak kolorowa. Nie ma jednak tragedii - "Not great, not terrible". Aby włączyć uruchamie konkretnych usług przy użyciu OpenRC jako programu init, wystarczy wydać konkretne polecenie jak te przedstawione poniżej:
+                               </p>
+<pre class="code-block">
+# rc-update add dnsmasq default
+# rc-update add dhcpd default
+# rc-update add iptables default
+</pre>
+<br />
+                               </p>
+                       </li>
+               </ol>
+               <p>
+               Jak widać na powyższej liście stworzenie prostej bramki opartej dobry system GNU/Linux, nie jest jakoś bardzo skomplikowane, wymaga wydania kilku poleceń oraz wyedytowania kilku plików. Dla mnie, gdzie mam trochę wprawy dużo rzeczy wydaje się banalnych, ale jeśli spojrzał bym kilka lat wstecz to już samo zagadnienie budowania bramki na GNU/Linux było by sporą abstrakcją, co dopiero na systemie, który trochę odbiega nurtu głównych dystrybucji takich jak GNU/Linux Debian czy CentOS. Serio, dla mnie łatwiejsze było nauczenie się zupełnie innego systemu operacyjnego oraz zupełnie innego pakietu zapory niż zabranie się za iptables, i mimochodem znając nieco bardziej iptables niż wtedy to pozostał bym wierny OpenBSD oraz PF.
+               </p>
+               <p>
+               ~xf0r3m
+               </p>
+
+                       </div>
+                       <p class="footer">
+                               2021; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+
+                       </body>
+               </html>
diff --git a/articles/linux/NFS_-_udostepnianie_i_montowanie_udziałów.html b/articles/linux/NFS_-_udostepnianie_i_montowanie_udziałów.html
new file mode 100644 (file)
index 0000000..548e6db
--- /dev/null
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">NFS - Udostępnianie i montowanie udziałów</h1>
+        <p>
+            Wykorzystanie <strong>NFS</strong> (ang. <em>Network File System</em>), czyli sieciowego systemu plików, jest chyba najbardziej zbliżonym plikowym zasobem sieciowym do katalogów wstępujących klasycznie w systemie, mowa oczywiście o systemach UNIX. Nie chce wdawać się w szczegóły samego protokołu, ponieważ tutaj chciałybm skupić się na samej praktyce, niezbędną teorie przytoczę podczas omawania konkretnych przykładów.
+        </p>
+        <p>
+            Na początek zajmiemy się serwerem, kiedy będzie gotów przejdziemy wówczas do konfiugracji klienta. Przed przystąpieniem do instalacji oprogramowania NFS, upewnijmy się czy nasz system posiada aktualne źródła repozytorium oraz oprogramowanie. Przytoczę tutaj polecenia dystrybucji opartych na Debianie.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+        <p>
+            Po zainstalowaniu aktualizacji możemy przejść do instalacji właściwego oprogramowania.
+        </p>
+<pre class="code-block">
+$ sudo apt install nfs-kernel-server
+</pre>
+        <p>
+            Teraz przejdziemy do utworzenia katalogu udziału oraz nadamy mu odpowiednie uprawnienia.
+        </p>
+<pre class="code-block">
+$ sudo mkdir /example
+$ sudo chmod nobody:nogroup /example
+</pre>
+        <p>
+            <code class="code-inline">/example</code> jest tutaj katalogiem udziału. Kiedy wykonaliśmy powyższe czynności mozemy przejść do udostępnienia katalogu z pomocą protokołu NFS. Otwieramy plik <em>/etc/exports</em>, plik może nie istnieć. Wewnątrz pliku deklarujemy nasz udział.
+        </p>
+<pre class="code-block">
+$ sudo vi /etc/exports
+# w /etc/export:
+/example        192.168.1.2(rw,sync,no_subtree_check,no_root_squash)
+</pre>
+        <p>
+            Tutaj:
+            <ul>
+                <li><code class="code-inline">/example</code> - jest nazwa katalogu udostępnianego za pomocą NFS,</li>
+                <li><code class="code-inline">192.168.1.2</code> - jest adresem klienta, który będzie montował ten udział w swoim systemie, nie koniecznie musi byc to adres IP, więcej informacji na stronie podręcznika <code class="code-inline">man 5 exports</code></li>
+            </ul>
+            Pozostała część linii są to opcje udziału, które określają następujące rzeczy:
+            <ul>
+                <li><code class="code-inline">rw</code> - umożliwienie zapisu plików na tym udziale,</li>
+                <li><code class="code-inline">sync</code> - wymusza zapis zmian na udziale, zapewnia stabliność działania i spójność danych</li>
+                <li><code class="code-inline">no_subtree_check</code> - wyłącznie sprawdzania plików na udziale</li>
+                <li><code class="code-inline">no_root_squash</code> - wyłącznie zmiany uprawnień z uzytkownika <em>root</em>(na kliencie) na zwykłego (na serwerze) - Stosowane w przypadku udostepnienia podkatalogów katalogu głównego.</li>
+            </ul>
+            Po zapisaniu zmian w pliku możemy zrestartować naszą usługe NFS.
+        </p>
+<pre class="code-block">
+$ sudo systemctl restart nfs-kernel-server
+</pre>
+        <p>
+            Konfiguracja na serwerze została juz zakończona, w przypadku NFS widać że nie ma z dużo pracy. Teraz przejdziemy do konfiguracji klienta. Rozpoczynamy ją klasycznie od zainstalowania aktualizacji w systemie.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+        <p>
+            Kiedy aktualizacje są zainstalowane, możemy przejść do zainstalowania niezbędnego oprogramowania.
+        </p>
+<pre class="code-block">
+$ sudo apt install nfs-common
+</pre>
+        <p>
+            Po instalacji pakietu możemy sobie przetestować nasz udział NFS, za pomocą poniższego polecenia.
+        </p>
+<pre class="code-block">
+$ sudo mount 192.168.1.3:example /nfs_example
+</pre>
+        <p>
+            Gdzie:
+            <ul>
+                <li><code class="code-inline">192.168.1.3</code> - adres serwera</li>
+                <li><code class="code-inline">example</code> - nazwa udziału udostępnionego dla klienta</li>
+                <li><code class="code-inline">/nfs_example</code> - punkt monotowania</li>
+            </ul>
+            Montowanie nie jest jakieś trudne, co widać na załączonym wyżej przykładzie. Teraz tak naprawdę możemy korzystać z naszego udziału. Jeśli chcemy sprawdzić czy udział został rzeczywiście zamontowany możemy wydać polecenie <code class="code-inline">mount</code> lub <code class="code-inline">df -h</code>, w wynikach działania tych poleceń powinniśmy odnaleźć adres IP serwera, nazwę udziału oraz punkt montowania. Teraz kiedy już możemy korzysać z naszego udziału to warto wprowadzić do systemu klienta jedną zmianę, ustawić system tak aby sam montował udział podczas startu.
+        </p>
+        <p>
+            W plik <em>/etc/fstab</em> dopisujemy poniższą linie.
+        </p>
+<pre class="code-block">
+192.168.1.3:example     /nfs_example    nfs     auto,nofail,noatime,nolock,intr,tcp,actimeo=1800    0   0
+</pre>
+        <p>
+            W przypadku tej linii to:
+            <ul>
+                <li><code class="code-inline">192.168.1.3:example</code> - jest wskazaniem adresu serwera wraz z nazwą udziału,</li>
+                <li><code class="code-inline">/nfs_example</code> - punkt montowania,</li>
+                <li><code class="code-inline">nfs</code> - montowany system plików.</li>
+            </ul>
+            po montowanym systemie plików występują opcje montowania. Opcje montowania można ze sobą mieszać, dlatego występują tu zarówno opcje ogólne, sterujące pracą samego systemu montowania oraz opcje specyficzne dla konkretnego systemu plików. Poniżej znajduje się objaśnienie opcji wykorzystanych podczas
+            tworzenia powyższego wpisu.
+            <ul>
+                <li><code class="code-inline">auto</code> - (opcja globalna), spowoduje montowanie udziału kiedy zostanie wydane polecenie <code class="code-inline">mount</code> wraz z przełącznikiem <code class="code-inline">-a</code>, czyli montowanie wszystkich urządzeń, których wpisy znajdują się pliku <em>/etc/fstab</em>,</li>
+                <li><code class="code-inline">nofail</code> - (opcja globalna), nie informuj o błedach podczas montowania tego urządzenia jeśli dane urządenie nie istnieje (lub jest nieosiągalne),</li>
+                <li><code class="code-inline">noatime</code> - (opcja globalna), nie aktualizuj czasu dostępu do pliku kiedy plik jest odczytywany,</li>
+                <li><code class="code-inline">nolock</code> - (opcja systemu plików), plik odczytywane przez aplikacje mogą zostać przez nie zablokowane aby inne procesy nie mogły ich użyć. Opcja <code class="code-inline">nolock</code>, powoduje że działa to tylko w obrębie komputera klienta i nie wpływu na procesy wykonywane chociażby na serwerze gdzie udostępniony jest ten udział,</li>
+                <li><code class="code-inline">intr</code> - (opcja systemu plików), umożliwia przerwanie operacji na plikach za pomocą sygnałów systemowych,</li>
+                <li><code class="code-inline">tcp</code> - (opcja systemu plików), metoda połączenia i przekazywania danych protokołu NFS. TCP zapewnia najstabilniejsze rozwiązanie,</li>
+                <li><code class="code-inline">actimeo=1800</code> - (opcja systemu plików), wskazuje na jak długo (ilość czasu wyrażona w sekundach) klient ma przechowywać w pamięci podręcznej atrybuty wykorzystywanych przez NFS plików. Tutaj ustawiono 30 minut,</li>
+                                                               <li><code class="code-inline">0</code> - (opcja globalna), pierwsze zero (<strong>0</strong>), oznacza ustawienie kopii zapasowej partycji wykonywanej przez program <em>dump</em>. Jeśli nigdy nie używaliśmy programu dump, to lepiej tą opcje pozostwić w wartości <code class="code-inline">0</code>,</li>
+                                                               <li><code class="code-inline">0</code> - (opcja globalna), drugie zero (<strong>0</strong>), kwalifikuje partycję do sprawdzania przez narzędzie <em>fsck</em>, kolejno: <code class="code-inline">0</code> - nie sprawdzaj partycji; <code class="code-inline">1</code> - ta wartość powinna być stosowana przy partycji głównej (<em>/ root</em>), włącza sprawdzanie oraz wymusza pierwszeństwo; <code class="code-inline">2</code> - opcja dla pozostałych partycji, które mają zostać sprawdzone. Wszystkie partycje z wartością <code class="code-inline">2</code> są sprawdzane po kolei.</li>
+            </ul>
+            Po zapisaniu zmian w pliku możemy zrestartować komputer klienta, aby sprawdzić czy rzeczywiście wpis w pliku <em>/etc/fstab</em> działa. Poprawność monotowania możemy sprawdzić za pomocą tych samych poleceń jakie wykorzystywaliśmy podczas testowania udziału.
+        </p>
+        <p>
+            NFS jak widać jest natywnym systemem udostępniania plików w UNIX-ach a jego instalacja i konfiguracja nie należy do najtrudniejszych.
+        </p>
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+</body>
+</html>
diff --git a/articles/linux/OTP/index.html b/articles/linux/OTP/index.html
new file mode 100644 (file)
index 0000000..a04d3be
--- /dev/null
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+   ____  __    __   ______                    _             __
+  / __ \/ /___/ /  /_  __/__  _________ ___  (_)___  ____ _/ /
+ / / / / / __  /    / / / _ \/ ___/ __ `__ \/ / __ \/ __ `/ / 
+/ /_/ / / /_/ /    / / /  __/ /  / / / / / / / / / / /_/ / /  
+\____/_/\__,_/    /_/  \___/_/  /_/ /_/ /_/_/_/ /_/\__,_/_/   
+                                                              
+    ____               _           __ 
+   / __ \_________    (_)__  _____/ /_
+  / /_/ / ___/ __ \  / / _ \/ ___/ __/
+ / ____/ /  / /_/ / / /  __/ /__/ /_  
+/_/   /_/   \____/_/ /\___/\___/\__/  
+                /___/                
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Old Terminal Project GNU/Linux (Wise choice)</h1>
+               <p>
+                       OTP a właśc. <strong>Old Terminal Project GNU/Linux</strong> jest to lekka
+                       dystrybucja oparta na dCore (port TinyCore-a) w wersji bazującej na
+                       Ubuntu 18.04. Jej zadaniem jest przywrócenie świetności starym
+                       terminalom, czy cienkim klientom produkowanym do 2010. System jest 
+                       32-bitowy i nie wspiera UEFI, dlatego nie jest ondedykowany dla
+                       wszystkich terminali. Dołączone do dystrybucji oprogramowanie
+                       pozwala wykorzystać te urządzenia do celu w jakim zostały stworzone 
+                       zarazem odnajdując się wśród współczesnych maszyn.
+               </p>
+               <p>
+                       Zrzut ekranu przestawiający pulpit dystrybucji:
+                       <a target="_blank" href="https://i.ibb.co/JBdSPC6/OTP-1-0-4-ss.png">
+                               <figure>
+                                       <img src="https://i.ibb.co/1KmgPd4/OTP-1-0-4-ss-thumbnail.png">
+                                       <figcaption>Kilknij obrazek, aby otworzyć w pełnym rozmiarze.</figcaption>
+                               </figure>
+                       </a> 
+    </p>
+    <p>
+                       Oprogramowanie dołączone do OTP:
+               </p>
+               <ul>
+                       <li><strong>Środowisko graficzne icedesk</strong>
+                               <em>(on boot)</em> (Xorg-all, icewm, xterm,
+                               adwaita-icon-theme, hicolor-icon-theme),</li>
+                       <li><strong>Przeglądarka internetowa Arora</strong>
+                               (<a href="https://github.com/Arora/arora">https://github.com/Arora/arora</a>)
+        <em>(on demand)</em>,</li>
+                       <li><strong>Klient OpenSSH</strong><em>(on demand)</em></li>
+                       <li><strong>Remmina</strong> + RDP plugin + VNC plugin + SPICE plugin
+        <em>(on boot)</em></li>
+                       <li><strong>virt-manager</strong><em>(on demand)</em></li>
+               </ul>
+    <p>
+      <strong>Aktualna wersja: <span style="font-size: 20pt;">1.0.5</span></strong>
+    </p>
+               <p>
+                       Dystrybucja została oparta o jeden z portów TinyCore, przy czym port <strong>dCore</strong>
+                       wykorzystuje pakiety <em>.deb</em> do konwersji ich na własne paczki zachowując
+                       przy tym rozwiązania z TinyCore. W przypadku dCore pakiety mają rozszerzenie
+                       <em>.sce</em> i działaja na dokładnie takiej samej zasadzie co pakiety <em>TCZ</em>. Są
+                       to małe odwzorowania <em>rootfs</em> zamknięte w formacie <em>squashfs</em>. Pakiety mogą
+                       być ładowane na żądanie (<em>on demand</em>) lub pod czas uruchamiania systemu
+                       (<em>on boot</em>), ze względu na małą wydajność tych starszych cienkich klientów
+                       podczas rozruchu systemu ładowane są najczęściej używane rozszerzenia.
+                       Rozszerzenia ładowane są za pomocą polecenia:
+               </p>
+<pre class="code-block">
+$ sce-load
+</pre>
+               <p>
+                       Polecenie to musi zostać wydane przez zwykłego użytkownika bez uprawnień
+                       administratora. Wyświetli ono menu z którego należy wybrać pakiet do 
+                       załadowania.
+               </p>
+               <p>
+                       Użytkownik może sam pobierać i ładować pakiety z Ubuntu 18.04. Do tej
+                       czynności wymagana jest nazwa pakietu z Ubuntu. Pakiet pobierany i 
+                       konwertowany jest za pomocą polecenia:
+               </p>
+<pre class="code-block">
+$ sce-import nazwa_pakietu
+</pre>
+               <p>
+                       Ładowanie może następować tak jak we wcześniej wyjaśniony sposób lub 
+                       "mniej interaktywny" podajac poleceniu nazwę pakietu:
+               </p>
+<pre class="code-block">
+$ sce-load nazwa_pakietu
+</pre>
+               <p>
+                       Po instalacji pakietów, warto oczyścić katalog na dysku z pobranych
+                       paczek <em>.deb</em>. Dokonuje się tego za pomocą rozszerzeia 
+                       <em>sce-debpurge</em>. Jest
+                       ono dostarczane wraz z dystrybucją, trzeba je tylko załadować.
+               </p>
+<pre class="code-block">
+$ sce-load sce-debpurge
+</pre>
+               <p>
+                       Usunięcie wszystkich pakietów <em>.deb</em>:
+               </p>
+<pre class="code-block">
+$ sce-debpurge -a
+</pre>
+               <p>
+                       Jeśli nie będziemy już potrzebować jakiegoś rozszerzenia możemy je usunąć
+                       za pomocą polecenia <em>sce-remove</em>, które również jest dołączane do pakietów
+                       dystrybucji, wymaga jedynie załadowania.
+               </p>
+<pre class="code-block">
+$ sce-load sce-remove
+$ sce-remove nazwa_pakietu
+</pre>
+               <p>
+                       Pakiet zostanie usunięty przy zamykaniu systemu.
+               </p>
+               <p>
+                       Jeśli chodzi o działanie samej dystrybucji to jest ono takie trochę
+                       thin-klienckie. Ponieważ położono nacisk na to aby użytkownik logował
+                       się do zdalnego systemu i to na nim pracował i nie pozostawiał po sobie
+                       śladu na terminalu. System automatycznie loguje się na użytkownika po czym
+                       uruchamiane jest środowisko graficzne. Wszelkie zamiany w systemie oraz
+                       dane zapisane przez użytkownika nie zostaną zachowane po restarcie systemu.
+               </p>
+               <p>
+                       System zainstalować można na dwa sposoby:
+               </p>
+               <ul>
+                       <li>tylko do odczytu</li>
+                       <li>instalacja typu frugal</li>
+               </ul>
+               <p>
+                       Pierwszy z nich polega na wgraniu obrazu płyty do pamięci flash terminala.
+                       Drugi przypomina normalną instalację jednak różni się od typowego procesu
+                       instalacji znanego z innych dystrybucji. Polega on na skopiowaniu na dysk
+                       zawartości płyty. Obie metody są opisane w 
+                       <a href="instalacja.html">poradniku instalacji</a> 
+                       A link do obrazu LiveCD znajduje się poniżej:
+               </p>
+               <ul>
+                       <li>
+                               <a href="https://sourceforge.net/projects/oldterminalproject/files/iso/OTP-hybrid-1.0.5.iso/download">
+                                       sourceforge.net
+                               </a>
+                       </li>
+               </ul>
+    <p>
+      Poprzednie wersje OTP znajdują się pod tym adresem: <a href="https://sourceforge.net/projects/oldterminalproject/files/iso/">https://sourceforge.net/projects/oldterminalproject/files/iso/</a>.
+    </p>
+               <p>
+                       Dostęp do przygotowanych pakietów z poziomu LiveCD wymaga 
+                       specjalnego montowania:
+               </p>
+<pre class="code-block">
+$ sudo mount -B /mnt/sr0/cde/sce /tmp/tce/sce
+</pre>
+    <p><strike>
+      Od wersji 1.0.3 nie ma możliwości instalowania dodatkowych pakietów
+      w wersji LiveCD.</strike>
+    </p> 
+    <p>
+      Wszelkie szczegóły odnośnie zmian w kolejnych wydaniach dystrybucji 
+      znajdują się na stronie git projektu, pod poniższy adresem:
+        <a href="https://github.com/xf0r3m/OTP">https://github.com/xf0r3m/OTP</a>
+    </p>
+               <p>
+                       Należy pamiętać, że Old Terminal Project GNU/Linux jest dystrybuowany
+                       bez gwarancji przydatność. Oznacza to że system może w ogóle się nie
+                       uruchomić Twoim sprzęcie. Autor nie ponosi odpowiedzialności za szkody
+                       wyrządzone instalacją OTP. Miłej zabawy.
+               </p>
+               <p>
+                       -- Changelog --
+               </p>
+               <p>
+                       -- 06.12.2021 - Rozpoczęcie prac nad OTP.<br />
+                       -- 12.12.2021 - Wydanie pierwszej wersji OTP o nazwie kodowej "Wise choice".<br />
+      -- 22.12.2021 - Wydanie wersji 1.0.1.<br />
+      -- 13.02.2022 - Wydanie wersji 1.0.2.<br /> 
+      -- 16.04.2022 - Wydanie wersji 1.0.3.<br />
+      -- 17.04.2022 - Wydanie wersji 1.0.4.<br />
+      -- 27.04.2022 - Wydanie wersji 1.0.5.<br />
+               </p>
+       </div>
+       <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+</body>
+</html>
diff --git a/articles/linux/OTP/instalacja.html b/articles/linux/OTP/instalacja.html
new file mode 100644 (file)
index 0000000..c5ea87c
--- /dev/null
@@ -0,0 +1,299 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+   ____  __    __   ______                    _             __
+  / __ \/ /___/ /  /_  __/__  _________ ___  (_)___  ____ _/ /
+ / / / / / __  /    / / / _ \/ ___/ __ `__ \/ / __ \/ __ `/ / 
+/ /_/ / / /_/ /    / / /  __/ /  / / / / / / / / / / /_/ / /  
+\____/_/\__,_/    /_/  \___/_/  /_/ /_/ /_/_/_/ /_/\__,_/_/   
+                                                              
+    ____               _           __ 
+   / __ \_________    (_)__  _____/ /_
+  / /_/ / ___/ __ \  / / _ \/ ___/ __/
+ / ____/ /  / /_/ / / /  __/ /__/ /_  
+/_/   /_/   \____/_/ /\___/\___/\__/  
+                /___/                
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Instalacja OTP</h1>
+               <ol>
+                       <li><strong>Tylko do odczytu:</strong>
+                               <p>
+                                       Z racji tego iż OTP ma służyć terminalom, które mają łaczyć się 
+                                       z odległmi systemami, system ten nie powinien być postrzegany jako
+                                       każdy inny Linux do codziennej pracy, system ten ma za zadanie
+                                       tylko i wyłącznie umożliwić Ci podłączenie sie do innego komputera.
+                                       Dlatego też można postrzegać go jako firmware, który cały
+                                       czas znajduje się w tym stanie, jakby by był świerzo zainstalowany.
+                                       Użytkownik nie pozostawia nic po sobie, cały system działa do momentu
+                                       działania terminala, uruchomienie urządzenia ponownie ładuje ten sam
+                                       nie zmieniony system. Oczywiście to są tylko założenia.
+                               </p>
+                               <p>
+                                       Instalacje systemu w tym trybie rozpoczynamy od przygotowania
+                                       pendrive-a z obrazem systemu. Każdy obecnie operuje co najmniej 4GB
+                                       kością pamięci USB. System zajmuje niecałe 740MB. Aby nie sciągać pliku
+                                       obrazu na uruchomionym z LiveCD terminalu, po załadowaniu ISO na 
+                                       pendrive utworzymy dodatkową partycję
+                                       sformatowaną na FAT, która będzie przechowywać pliku obrazu płyty.
+                               </p>
+                               <ul>
+                                       <li><strong>Wgrywanie ISO na pendrive:</strong>
+<pre class="code-block">
+$ sudo dd if=OTP-hybrid.iso bs=1M of=/dev/sdb status=progress  
+</pre>
+                                       </li>
+                                       <li><strong>Za pomocą fdisk, tworzymy dodatkową partycję:</strong>
+<pre class="code-block">
+$ sudo fdisk /dev/sdb
+&gt; n
+&gt; p
+&gt; 2
+&gt; [domyślnie]
+&gt; [domyślnie]
+&gt; t
+&gt; 2
+&gt; b
+&gt; w
+</pre>
+                                       </li>
+                                       <li><strong>Formatujemy nowo utworzoną partycję na FAT32:</strong>
+<pre class="code-block">
+$ sudo mkfs.fat -F32 /dev/sdb2
+</pre>
+                                       </li>
+                                       <li><strong>Montujemy partycję i kopiujemy na nią obraz płyty:</strong>
+<pre class="code-block">
+$ sudo mount /dev/sdb2 /mnt
+$ cp ~/Downloads/OTP-hybrid.iso /mnt
+</pre>
+                                       </li>
+                               </ul>
+                               <p>
+                                       Po skopiowaniu obrazu na partycję, możemy odmontować
+                                       pendrive-a, podłaczyć
+                                       do terminala i rozpocząć właściwą instalacja, która sprowadza się do
+                                       trzech czynności:
+                               </p>
+                               <ul>
+                                       <li><strong>Uruchomienia terminala z pamięci USB,</strong></li>
+                                       <li><strong>Zamontowania dodatkowej partycji,</strong>
+<pre class="code-block">
+$ sudo mount /dev/sdb2 /mnt
+</pre>
+                                       </li>
+                                       <li><strong>Wgraniu obrazu płyty do pamięci flash terminala tak jak na pendrive.</strong>
+<pre class="code-block">
+$ sudo dd if=/mnt/OTP-hybrid bs=1M of=/dev/sda status=progress
+</pre>
+                                       </li>
+                               </ul>
+                               <p>
+                                       Minusem instalacji tego typu, jest ograniczona ilość pamięci RAM 
+                                       w cienkich klientach. To w nim będzie rezydować <em>rootfs</em>, w nim również
+                                       będą przechowywane rozszerzenia więc jej zasób może się szybko
+                                       wyczerpać.
+                               </p>
+                       </li>
+                       <li><strong>Instalacja frugal</strong>
+                               <p>
+                                       Instalacja w tym trybie spowoduje, że system będzie przypominać nieco
+                                       dotyczasowe Linux-y, ale względu na rozwiązania bazowe dalej system
+                                       będzie na nowo ładował ten sam stan przy każdym restarcie. Dane
+                                       będziemy mogli zachować na dwa sposoby:
+                               </p>
+                               <ul>
+                                       <li><strong>używając polecenia backup przed każdym zamknięciem systemu</strong>,
+                                               spowoduje to utworzenie archiwum w jednym z katalogów na dysku
+                                               i wypakowaywanie jego zawartości przy każdym kolejnym ładowaniu systemu.
+                                       </li>
+                                       <li><strong>Tworząc swój katalog bezpośrednio dysku, i zapisując w nim wszelkie informacje,</strong>
+                                               warto dodać, że jako jedyny aktywny użytkownik w tym systemie mamy uprawnienia 
+                                               administratora. Wariacją tego pomysłu może być oddzielna partycja czy oddzielna
+                                               szyfrowana partycja, sam system nie zajmnie więcej niż 1GB.
+                                       </li>
+                               </ul>
+                               <p>
+                                       Poniżej znajduje się lista kroków, którą należy wykonać aby 
+                                       zainstalować system w ten sposób. Odnośnie tego sposóbu na moim 
+                                       osobistym koncie na github znajduje się skrypt, pozwalający
+                                       zaoszczędzić trochę czasu na przepisywaniu tych czynności do
+                                       terminala.
+                               </p>
+                               <ul>
+                                       <li><strong>dC-install.sh</strong>
+                                               <a href="https://github.com/xf0r3m/dC-install.git">https://github.com/xf0r3m/dC-install.git</a>
+                                       </li>
+                               </ul>
+        <p>
+          <strong>Poniższy opis instalacji nie jest zgodny z wersją 
+          1.0.2.</strong>
+          Prawdobodobnie zostanie zaktualizowany. Jednak zalecaną metodą przy
+          sposobie <em>frugal</em> jest wykorzystanie skryptu. Skrypt jest
+          bardzo prosty, i jeśli ktoś naprawdę sobie tego życzy może wykonać
+          je ręcznie przy okazji dostosowując instalacje do własnych potrzeb.
+        </p>
+                               <strike><p>
+                                       W zależności od tego czy używamy pendrive'a czy płyty punkt montowania
+                                       obrazu instalacyjnego może być inny.
+                               </p>
+                               <ul>
+                                       <li><strong>/mnt/sr0</strong> - dla płyt</li>
+                                       <li><strong>/mnt/sdX</strong> - dla dysków USB</li>
+                               </ul>
+                               <ol>
+                                       <li>
+                                               <strong>Wybranie odpowiedniego dysku przeznaczonego do instalacji systemu.</strong>
+<pre class="code-block">
+$ sudo fdisk -l
+</pre>
+                                       </li>
+                                       <li>
+                                               <strong>Partycjonowanie dysku</strong>,w przypadku OTP możemy zrobić jedną partycję
+                                               obejmującą cały obszar dysku.
+<pre class="code-block">
+$ sudo fdisk /dev/sdX
+&gt; n
+&gt; p
+&gt; [domyślnie]
+&gt; [domyślnie]
+&gt; [domyślnie]
+&gt; a         #Ustawienie flagi rozruchowej
+&gt; w
+</pre>
+                                               <p>
+                                                       gdzie <code class="code-inline">X</code> - to litera oznaczająca dysk.
+                                               </p>
+                                       </li>
+                                       <li><strong>Formatowanie dysku</strong>, domyślnie OTP instaluje się na partycji z system
+                                               plików EXT4, wybór innego systemu plików może wymagać użycia innego
+                                               programu rozruchowego (w tym materiale jest extlinux).
+<pre class="code-block">
+$ sudo mkfs.ext4 /dev/sdX1
+</pre>
+                                       </li>
+                                       <li><strong>Utworzenie nowej zawartości pliku /etc/fstab</strong>
+                                               systemu tymczasowego w celu łatwiejszego montowania dysku.
+<pre class="code-block">
+$ sudo rebuildfstab
+</pre>
+                                       </li>
+                                       <li><strong>Montowanie dysku przeznaczonego na system</strong>.
+<pre class="code-block">
+$ mount /mnt/sdX1 
+</pre>
+                                               <p>
+                                                       Podany tutaj punkt montowania można znaleźć w pliku <em>/etc/fstab.</em>
+                                               </p>
+                                       </li>
+                                       <li><strong>Tworzenie katalogów dla plików systemowych oraz programu rozruchowego</strong>.
+<pre class="code-block">
+$ sudo mkdir -p /mnt/sdX1/boot/extlinux
+</pre>
+                                       </li>
+                                       <li><strong>Skopiowanie plików jądra oraz początkowego systemu plików w pamięci RAM na dysk</strong>.
+<pre class="code-block">
+$ sudo cp -p /mnt/sdb/boot/* /mnt/sdX1/boot
+</pre>
+                                               <p>
+                                                       Ignorujemy komunikat o tym, że katalog <em>isolinux</em> został pominięty, tak
+                                                       właśnie miało być.
+                                               </p>
+                                       </li>
+                                       <li><strong>Importujemy pakiet e2fsprogs</strong>.
+<pre class="code-block">
+$ sce-import e2fsprogs
+</pre>
+                                               <p>
+                                                       Pakiet ten zawiera program <em>e2label</em>, pozwalający na ustawienie etykiet
+                                                       system plików rodziny EXT, dzięki ustawieniu etykiety nie będziemy
+                                                       musieli posługiwać się UUID w pliku konfiguracyjnym programu rozruchowego.
+                                               </p>
+                                       </li>
+                                       <li><strong>Załadowanie pakietu e2fsprogs</strong>.
+<pre class="code-block">
+$ sce-load e2fsprogs
+</pre>
+                                               <p>
+                                                       Pakiety na <strong>dCore</strong> (dystrybucja bazowa OTP) wymagają importowania (pobrania
+                                                       z serwerów, [w tym przypadku Ubuntu] paczki <em>.deb</em> i konwersji jej do pliku
+                                                       zgodnego z tym portem TinyCore - <em>.sce</em>, A następnie załadowania w systemie
+                                                       (instalacji). Więcej o tym na stronie głównej projektu.
+                                               </p>
+                                       </li>
+                                       <li><strong>Ustawienie etykiety dla systemu plików</strong>.
+<pre class="code-block">
+$ sudo e2label /dev/sdX1 "OTP"
+</pre>                                         
+                                       </li>
+                                       <li><strong>Importowanie pakietu programu rozruchowego</strong>.
+<pre class="code-block">
+$ sce-import extlinux
+</pre>
+                                       </li>
+                                       <li><strong>Załadowanie pakietu z programem rozruchowym</strong>.
+<pre class="code-block">
+$ sce-load extlinux
+</pre>                                 
+                                       </li>
+                                       <li><strong>Instalacja plików niezbędnych do startu systemu przy użyciu
+                                               programu rozruchowego tego typu.</strong>
+<pre class="code-block">
+$ sudo extlinux --install /mnt/sdX1/boot/extlinux
+</pre>
+                                       </li>
+                                       <li><strong>Instalacja rekordu rozruchowego (MBR) na dysku.</strong>
+<pre class="code-block">
+$ sudo dd if=/usr/lib/EXTLINUX/mbr.bin of=/dev/sdX
+</pre>                                 
+                                       </li>
+                                       <li><strong>Utworzenie pliku konfiguracyjnego programu rozruchowego.</strong>
+<pre class="code-block">
+$ sudo vi /mnt/sdX1/boot/extlinux/extlinux.conf
+
+default OTP
+label OTP
+kernel /boot/vmlinuzbionic
+append initrd=/boot/OTP.gz tce=sdX1 quiet desktop=icewm host=otp
+</pre>
+                                       </li>
+                                       <li><strong>Wybranie dysku docelowego dla rozszerzeń dCore</strong>, wykonanie tej
+                                               czynności spowoduje utworzenie struktury katalogowej w systemie plików.
+                                               Tę czynność należy wykonać przed skopiowaniem rozszerzeń z obrazu
+                                               instalacyjnego.
+<pre class="code-block">
+$ tce-setdrive
+</pre>
+                                               <p>
+                                                       Z wyświetlonej listy należy wybrać docelowy punkt montowania.
+                                               </p>
+                                       </li>
+                                       <li><strong>Skopiowanie rozszerzeń z obrazu instalacyjnego</strong>
+<pre class="code-block">
+$ sudo cp -rvv /mnt/sdb/cde/* /mnt/sdX1/tce
+</pre>
+                                       </li>
+                               </ol>
+                       </li>
+               </ol>
+               <p>
+                       Po skopiowaniu rozszerzeń, instalacja jest zakończona można uruchomić
+                       komputer ponownie. Za pomocą powyższych sposobów, możemy zainstalować
+                       OTP w pamięci flash naszego terminala.
+               </p></strike>
+       </div>
+       <p class="footer">
+         2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+</body>
+</html>
diff --git a/articles/linux/Parabola_GNU_Linux-libre.html b/articles/linux/Parabola_GNU_Linux-libre.html
new file mode 100644 (file)
index 0000000..e538c10
--- /dev/null
@@ -0,0 +1,895 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  ____ _   _ _   _   ___     _                       _ _ _              
+ / ___| \ | | | | | / / |   (_)_ __  _   ___  __    | (_) |__  _ __ ___ 
+| |  _|  \| | | | |/ /| |   | | '_ \| | | \ \/ /____| | | '_ \| '__/ _ \
+| |_| | |\  | |_| / / | |___| | | | | |_| |>  <_____| | | |_) | | |  __/
+ \____|_| \_|\___/_/  |_____|_|_| |_|\__,_/_/\_\    |_|_|_.__/|_|  \___|
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">Parabola GNU/Linux-libre</h1>
+    <p>
+      <strong>Parabola GNU/Linux-libre</strong> lub poprostu 
+      <em>Parabola Linux</em>, jest to dystrybucja oparta na Arch Linux
+      stworzona przy użyciu kernela <strong>Linux-libre</strong> pozbawionego
+      wszelkiego zamkniętego oprogramowania (blobów binarnych) oraz 
+      zaciemnionego kodu. Uznana za całkowicie wolną przez Free Software
+      Fundation.
+    </p>
+    <p>
+      Skoro dystrybucja jest oparta na Arch-u to możemy spodziewać się
+      ręcznej instalacji. Na swoją instalację wybrałem starszy sprzęt bez
+      Intel ME, dość ciekawe urządzenie bo jest to stary poliwęglanowy
+      Apple Macbook A1181.
+    </p>
+    <p>
+      <img src="https://i.ibb.co/KWpcVkv/2021-11-11-192551-1280x800-scrot.png" alt="macbook_parabola_screenshot" style="width: 100%;"/>
+    </p>
+    <ol>
+      <li><strong>Utworzenie obrazu instalacyjnego</strong>
+          <p>
+            Instalacje systemu zaczniemy od utworzenia obrazu na jakimś pendrive
+            czy dysku USB. I tu już zaczynają się schody ponieważ ten komputer
+            nie posiada BIOS-u, lecz wbudowany firmware mianowicie 32-bitowe 
+            EFI.
+            Niestety metoda opisana na stronie Arch Linux nie działa z tym
+            sprzętem. Chcąc utworzyć obraz instalacjny dla tego sprzętu musimy
+            przygotwać nasz dysk wg. instrukcji: 
+            <a href="https://wiki.debian.org/InstallingDebianOn/Apple/MacBook/2-1">
+              https://wiki.debian.org/InstallingDebianOn/Apple/MacBook/2-1
+            </a>
+            Po rozpakowaniu pliku iso za pomocą 7-zip-a, kopiujemy cały folder
+            <em>parabola</em> na dysk USB, następnie należy użyć poniższej
+            konfiguracji dla GRUB-a.
+          </p>
+<pre class="code-block">
+if loadfont /boot/grub/fonts/unicode.pf2 ; then
+    set gfxmode=800x600
+    insmod efi_gop
+    insmod efi_uga
+    insmod video_bochs
+    insmod video_cirrus
+    insmod gfxterm
+    insmod png
+    terminal_output gfxterm
+fi
+linux (hd0,msdos1)/parabola/boot/x86_64/vmlinuz-linux-libre parabolabasedir=parabola parabolaisolabel=PARA_202108
+initrd (hd0,msdos1)/parabola/boot/x86_64/initramfs-linux-libre.img
+</pre>
+          <p>
+            Ostatnią rzeczą jaką należy zrobić przed uruchomieniem komputera
+            z tego dysku, to trzeba ustawić etykietę dysku na etykietę obrazu
+            płyty za pomocą polecenia <strong>fatlabel</strong>
+          </p> 
+<pre class="code-block">
+# fatlabel /dev/sda1 PARA_202108
+</pre>
+          <p>
+            Obraz płyty jest gotowy, do <em>boot menu</em> na Macu przechodzimy
+            przytrzymując klawisz <strong>alt/option</strong> podczas włączania
+            komputera pokaże się dysk usb z etykietą "EFI Boot".
+          </p>
+      </li>
+      <li><strong>Instalacja systemu</strong>
+          <p>
+            Parabola dystrybuowana jest w dwóch wersjach, 
+            <strong>OpenRC</strong>
+            lub <strong>systemd</strong>. Osobiście wybrałem <em>OpenRC</em>,
+            (i dla tego typu programu <em>init</em>, przedstawię instalację
+            jeśli wybierzemy <em>systemd</em>, to opis instalacji znajduje
+            się pod tym linkiem
+            <a href="https://wiki.parabola.nu/Installation_Guide">
+              http://wiki.parabola.nu/Installation_Guide
+            </a>, lub podczas instalacji za pomocą polecenia
+            <code class="code-inline">Installation_guide</code>) 
+            nie wiem czy to nie strzał w stopę, bo jest przyzwyczajony do
+            <em>systemd</em>, jednak dla takiego sprzetu wydajemi się że
+            <em>OpenRC</em> będzie lepszym wyborem. 
+          </p>
+          <p>
+            Odziwo Parabola posiada sterowniki do karty bezprzewodowej na
+            Macu. Połączyć się możemy za pomocą apletu NetworkManager
+            <em>nmtui-connect</em>. Strzałką wybieramy sieć, zatwierdzamy
+            enterem, podajemy hasło i następuje łączenie. Połączenie sieciowe
+            jest wymagane do zainstalowania systemu.
+          </p>
+          <p>
+            Instalacje systemu rozpocznamy od partycjonowania dysku. Swój
+            system skonfigurowałem w taki sposób, że mam 3 partycje podstawowe.
+            EFI, partycja z katalogiem głównym oraz partycję szyfrowaną z
+            katalogiem domowym. Dlaczego nie użyłem szyfrowania partycji z
+            z katalogiem głównym? Natknąłem się na błąd, który to uniemożliwiał
+            podczas ładowania się jądra po wpisaniu hasła do odblokowania 
+            partycji
+            nie działo się nic. System się zawieszał. Dlatego wybrałem taki
+            kompromis, ponieważ tak naprawdę zależy mi wyłącznie na ochronie 
+            moich danych.
+          </p>
+          <table>
+              <tr>
+                <th>Urządzenie</th>
+                <th>Rozmiar</th>
+                <th>Punkt montowania</th>
+              </tr>
+              <tr>
+                <td>/dev/sda1</td>
+                <td>600M</td>
+                <td>/boot (EFI)</td>
+              </tr>
+              <tr>
+                <td>/dev/sda2</td>
+                <td>-1G</td>
+                <td>/</td>
+              </tr>
+              <tr>
+                <td>/dev/sda5</td>
+                <td>1G</td>
+                <td>swap</td>
+              </tr>
+          </table>
+          <p>
+            Powyżej znajduje się tabela przedstawiająca partycjonowanie.
+            Pominąłem partycję dla szyfrowania pod <em>/home</em>, nią zajmiemy
+            po zainstalowaniu systemu. Po spartycjonowaniu dysku tworzymy
+            odpowiednie dla przeznaczenia partycji systemy plików.
+          </p>
+<pre class="code-block">
+#Partycja /boot:
+# mkfs.vfat -F32 /dev/sda1
+#Partycja /:
+# mkfs.ext4 /dev/sda2
+#Swap:
+# mkswap /dev/sda5
+</pre>
+          <p>
+            Montujemy główny system plików pod katalogiem <em>/mnt</em>,
+            po zamontowaniu tworzymy w nim nowy katalog <em>boot</em> pod ten
+            katalog montujemy partycje EFI, na sam koniec możemy włączyć
+            przestrzeń wymiany.
+          </p>
+<pre class="code-block">
+# mount /dev/sda2 /mnt
+# mkdir /mnt/boot
+# mount /dev/sda1 /mnt/boot
+# swapon /dev/sda5
+</pre>
+          <p>
+            Teraz przechodzimy do instalacji systemu. Instalacja systemu
+            polega na instalacji pakietów za pomocą odpowiedniego narzędzia.
+            Poradnik instalacji, rozmienia się z tą czynnością na kilka
+            podpunktów, ja złoże je w jedno duże polecenie.
+          </p>
+<pre class="code-block">
+$ pacstrap /mnt base libelogind udev-init-scripts linux-libre-lts networkmanager grub vim cryptsetup dhclient man-db man-pages texinfo 
+</pre>
+          <p>
+            Jest wielce prawdopodobne, że podczas instalacji wystąpi błąd 
+            związany z podpisami lub integralnością pakietów instalacja
+            zostanie przerwana i należy go naprawić aby pójść dalej.
+          </p>
+          <p>
+            W poradniku instalacji w podpunkcie poświęconym temu problemowi
+            są dwa polecenia. Należy je przepisać i uruchomić.
+          </p>
+<pre class="code-block">
+# pacman -Sy archlinux-keyring archlinuxarm-keyring parabola-keyring
+# pacman -U https://www.parabola.nu/packages/core/i686/archlinux32-keyring-transition/download/
+</pre>
+          <p>
+            Następnie musimy odswierzyć klucze dewelopera, które się 
+            niezgadzają.
+          </p>
+<pre class="code-block">
+# pacman-key --refresh-keys mail_dewelopera@example.com
+</pre>
+          <p>
+            Po wykonaniu tej czynności należy powtórzyć te dwa polecenia
+            wykonywane przed odświerzeniem kluczy. Teraz klucze powinny się
+            zgadzać i instalacja powinna ruszyć dalej.
+          </p>
+          <p>
+            Zakończenie działania polecenia 
+            <code class="code-inline">pacstrap</code> oznacza teoretycznie, że
+            system jest zainstalowany. Niestety tylko w teorii. Wymaga on
+            jeszcze konfiguracji. Zaczniemy od wygenerowania pliku
+            <em>/etc/fstab</em> na podstawie zamontowanych dysków.
+          </p>
+<pre class="code-block">
+# genfstab -U /mnt &gt;&gt; /mnt/etc/fstab
+</pre>
+          <p>
+            Zmieniamy nasz katalog główny na <em>/mnt</em>, wykorzystując do
+            tego specjalne narzędzie dostarczane wraz ze wszystkimi
+            dystrybucjami opartymi na Arch Linux.
+          </p>
+<pre class="code-block">
+# arch-chroot /mnt
+</pre>
+          <p>
+            Ustawienia właściwe adresy w pliku <em>/etc/hosts</em>.
+          </p>
+<pre class="code-block">
+127.0.0.1   localhost
+::1         localhost
+127.0.1.1   macbook.localdomain macbook
+</pre>
+          <p>
+            W pliku <em>/etc/conf.d/hostname</em> ustawiamy nazwę hosta. Nie 
+            działa to
+            jednak ponieważ nie w systemie brakuje polecenia, które miały by
+            tę nazwę ustawić. Nazwę ustalimy za pomocą polecenia
+            <em>nmtui-hostname</em>, kiedy już go uruchomimy.
+          </p>
+          <p>
+            Następną rzeczą do ustawienia są <strong>locale</strong>. W pliku
+            <em>/etc/locale.conf</em>, zapisujemy poniższe dane.
+          </p>
+<pre class="code-block">
+LANG="pl_PL.UTF-8"
+LC_COLLATE="C"
+LC_TIME="pl_PL.UTF-8"
+</pre>
+          <p>
+            Powyższy plik nie jest jedym plikiem, w którym należy zapisać
+            <em>locale</em>. Otwieramy plik <em>/etc/locale.gen</em>, w pliku
+            poszukujemy <em>pl_PL.UTF-8 UTF-8</em>. Usuwamy znak komentarza 
+            sprzed wyszukanej frazy i zapisujemy plik.
+          </p>
+<pre class="code-block">
+...
+#pap_AW UTF8
+pl_PL.UTF-8 UTF-8
+#pl_PL ISO-8859-2
+...
+</pre>
+        <p>
+          Nastepnie wydajemy polecenie:
+        </p>
+<pre class="code-block">
+(chroot)# locale-gen
+</pre>
+        <p>
+          W pliku <em>/etc/conf.d/keymaps</em> ustawimy układ klawiatury dla
+          konsoli, natomiast w pliku <em>/etc/conf.d/consolefont</em> ustawimy
+          czcionkę oraz mapę znaków aby zapewnić poprawne wyświetlanie
+          polskich znaków w konsoli.
+        </p>
+        <p>
+         W <em>/etc/conf.d/keymaps</em> ustawiamy opcję
+         <strong>keymap</strong>, resztę pozostawiamy bez zmian.
+        </p>
+<pre class="code-block">
+keymap="pl"
+</pre>
+        <p>
+          W <em>/etc/conf.d/consolefont</em> ustawiamy dwie opcje
+          <strong>consolefont</strong> oraz <strong>consoletranslation</strong>
+          zgodnie z poniższymi ustawieniami.
+        </p>
+<pre class="code-block">
+consolefont="lat2-16"
+consoletranslation="8859-2"
+</pre>
+        <p>
+          Po zapisaniu zmian w pliku możemy przejść do instalacji
+          programu rozruchowego <strong>GRUB</strong>. Instalacja wymaga
+          jedynie dwóch poleceń.
+        </p>
+<pre class="code-block">
+(chroot)# grub-install --target=i386-efi --efi-directory=/boot --bootloader-id=GRUB
+(chroot)# grub-config -o /boot/grub/grub.cfg
+</pre>
+        <p>
+           Teraz instalacja jest teorytcznie zakończona, jednak przed 
+           odmontowaniem partycji musimy:
+        </p>
+        <ul>
+          <li><strong>Ustawić hasło dla superużytkownika.</strong></li>
+          <li><strong>Skopiowiać plik /etc/init.d/NetworkManager z</strong>
+              <strong>uruchomionego z płyty, najlepiej do katalogu</strong>
+              <strong>użytkownika root.</strong></li>
+        </ul>
+        <p>
+          Ustawienie hasła dla <em>root</em>-a jest banalnie proste.
+        </p>
+<pre class="code-block">
+(chroot)# passwd
+</pre>
+        <p>
+          Podajemy nowe hasło dwa razy. Druga czynność wymaga już opuszczenia
+          środowiska zmienionego katalogu głównego. Katalog z dysku opuszczamy
+          wydając po prostu polecenie <code class="code-inline">exit</code>.
+          Następnie kopiujemy plik usługi NetworkManager do katalogu 
+          <em>/mnt/root</em>.
+        </p>
+<pre class="code-block">
+(chroot)# exit
+# cp /etc/init.d/NetworkManager /mnt/root
+</pre>
+        <p>
+          Po wykonaniu tej czynności możemy odmontować systemy plików dysku
+          za pomocą jednego polecenia następnie uruchomić komputer ponownie.
+          Instalacja została zakończona.
+        </p>
+<pre class="code-block">
+# umount -R /mnt
+# reboot
+</pre>
+      </li>
+      <li><strong>Pierwsze uruchomienie i konfiguracja katalogu /home</strong>
+          <p>
+            Po uruchomieniu komputeraz uslyszysmy charakterystyczny gong. Na 
+            ekranie pojawi się białe tlo. Zostaniemy przeniesieni odrazu do
+            menu GRUB-a. Wybieramy domyślną opcję. Komputer może się zawiesić
+            w trakcie ładowania jądra do pamięci, więc jeśli utkniemy z dwoma
+            napisami w lewym górnym rogu ekranu, to możemy wyłączyć twardo
+            komputer i uruchomić go ponownie. Teraz z GRUBa wybieramy tę drugą
+            opcję i z następnego podmenu wybieramy opcje nr. 1. Teraz system
+            powinien się uruchomić. Jeśli znów się zawiesił, to znów twardo go
+            wyłączamy i wybieramy domyślną opcję z menu GRUB-a. Czasami
+            potrzeba kilku takich uruchomień aby komputer się uruchomił.
+            Po załadowaniu dostaniemy wyłącznie dostęp do konsoli. 
+            Na początku musimy zalogować się jako <em>root</em>.
+          </p>
+          <p>
+            Na partycji, dla której przeznaczyliśmy większość miejsca na dysku.
+            Nie tworzymy zwykłego systemu plików, tylko system 
+            plików przeznaczony do szyfrowania <strong>LUKS</strong>.
+          </p>
+<pre class="code-block">
+# cryptsetup -y -v luksFormat /dev/sda3
+</pre>
+          <p>
+            Program podczas tworzenia plików zapyta o potwierdzenie, trzeba
+            wiekimi literami wpisać <strong>YES</strong>. Następnie polecenie
+            zapyta o hasło szyfrowania woluminu, dwukrotnie. Po utworzeniu
+            trzeba wolumin otworzyć.
+          </p>
+<pre class="code-block">
+# cryptsetup open /dev/sda3 crytphome
+</pre>
+          <p>
+            Polecenie zapyta o klucz do odszyfrowania (hasło), następnie
+            utworzy nowe urządzenie blokowe w katalogu <em>/dev/mapper</em> o
+            nazwie, podanej jako ostatni argument polecenia. To nazwą może być
+            cokolwiek. To utworzone urządzenie montujemy pod katalogiem
+            <em>/home</em>.
+          </p>
+<pre class="code-block">
+# mount /dev/mapper/crypthome /home
+</pre>
+          <p>
+            Przy tej konfiguracji będziemy wracać do tego punktu podczas
+            zamykania systemu. Dla bezpieczeństwa szyfrowanego woluminu lepiej
+            kulturalnie go odmontować i zamknąć.
+          </p>
+<pre class="code-block">
+# umount /home
+</pre>
+          <p>
+            Czasami na pewno zadarzy się sytuacja, że nie będziemy mogli 
+            odmontować tego katalogu, ponieważ <em>cel jest zajęty</em>.
+            Oznacza to mniej więcej tyle, że w systemie istnieje
+            jeszcze jakiś działający proces użytkownika, w celu zbadania
+            sytuacji, wydajemy polecenie:
+          </p>
+<pre class="code-block">
+# ps -aux
+</pre>
+          <p>
+            Jeśli proces jest nie istotny, dla wyników naszej pracy na
+            komputerze, możemy go na początku spróbować kulturalnie zamknąć
+            wydajac polecenie <em>kill</em> wraz z PID-em procesu, oczywiście
+            bez podawania żadnego symbolu sygnału.
+          </p>
+<pre class="code-block">
+# kill PID
+</pre>
+          <p>
+            Jeśli to nie pomoże, proces należy zabić dodając do powyższego
+            polecenia opcje <em>-9</em>, prosząc jądro o wysłanie do procesu
+            sygnału <em>KILL</em>.
+          </p>
+<pre class="code-block">
+# kill -9 PID
+</pre>
+          <p>
+            Innym powodem problemów z odmontowaniem katalogu <em>/home</em> 
+            są podmontowane w jego podkatalogach inne systemy plików jak
+            udziały SMB. Należy je ręczenie odmontować lub użyć polecenia:
+          </p>
+<pre class="code-block">
+# umount -R /home
+</pre>
+      </li>
+      <li>
+        <strong>
+          Nowy użytkownik oraz nadanie mu uprawnień superużytkownika
+        </strong>
+        <p>
+          Kiedy mamy już miejsce na nasze dane, możemy utworzyć nowego konto
+          na którym będziemy je przechowywać. Prawdopodobnie jesteśmy
+          jedymi realnymi użytkownikami tego systemu więc nadamy mu 
+          uprawnienia superużytkownika aby nie trzeba było się przelogowywać.
+          Wyższych uprawnień będziemy potrzebować do instalacji środowiska 
+          graficznego.
+        </p>
+        <p>
+          Użytkownika tworzymy za pomocą poleceania <strong>useradd</strong>,
+          wraz z opcją <em>-m</em>, która spowoduje utworzenie katalogu
+          domowego oraz skopiowanie zawartości katalogu <em>/etc/skel</em> 
+          zawierającego pliki konfiguracyjne powłoki oraz pliki domyślne
+          użytkowników systemu. Po utworzeniu użytkownika należy pamiętać o
+          zdefiniowaniu hasła dla użytkownika. Hasło należy podać dwukrotnie.
+        </p>
+<pre class="code-block">
+# useradd -m xf0r3m
+# passwd xf0r3m
+</pre>
+        <p>
+          W systemie prawdopodbnie nie będzie zainstalowanego programu
+          <strong>sudo</strong>. Więc możemy go doinstalować, jeśli czytasz
+          to przed rozpczęciem jakich kolwiek prac, możesz dopisać 
+          <em>sudo</em> do polecenia <code class="code-inline">pacstrap</code>
+          instalującego system.
+        </p>
+<pre class="code-block">
+# pacman -Syu sudo
+</pre>
+        <p>
+          Po zainstalowaniu pakietu, przechodzimy do pliku 
+          <em>/etc/sudoers</em>. Plik jest tylko do odczytu, nawet dla
+          <em>root</em>. Przejście w tryb edycji (jeśli używamy programu Vim)
+          czy zapisanie zmian będzie wymagać potwierdzenia. W pliku odszukujemy
+          lini <em>root ALL=(ALL) ALL</em>, pod nią możemy zapisać identyczną
+          frazę zmieniając tylko użytkownika lub poniższą dzięki, której nie
+          będzie potrzeby wpisywania hasła. 
+        </p>
+<pre class="code-block">
+xf0r3m ALL=(ALL) NOPASSWD:ALL
+</pre>
+        <p>
+          Po zapisaniu zmian możemy opuścić konto superużytkownika, wylogowując
+          się poleceniem <em>exit</em>. Następnie zalogować się na swoje konto.
+        </p>
+      </li>
+      <li>
+        <strong>Instalacja i konfiguracja środowiska graficznego</strong>.
+        <p>
+          Na tym Macbook-u, którego użyłem do instalacji, procesor 
+          Core2Duo poci się niemiłośernie. Osiągając 65 - 70 stopnii C
+          temperatury roboczej, co przekłada się na hałas generowany przez
+          wentylator, na tym sprzęcie mam ograniczenia również co do wiekości
+          zainstalowanej pamięci RAM, mimo włożenia dwóch kości po 2GB system
+          system obsługuje maksymalnie 3GB. Aby móc na nim bez przeszkód 
+          pracować
+          potrzebowałem lekkiego środowiska aby przeznaczyć więcej pamięci na
+          programy, do tej instalacji użyłem środowiska 
+          <strong>fluxbox</strong>. Teraz
+          pisząc ten tekst, z włączonym Vim-em oraz odtwarzaczem muzyki
+          <em>moc</em> oraz menedżerem zadań <em>htop</em> wykorzystane ma
+          122MB. Pozostawiając ponad 2,5 GB na pozostałe programy. Ta 
+          konfiguracja
+          jest rozwiązaniem dla osób, które nie boją się terminala. Jednak
+          wybierając dystrybucję z rodziny Arch Linux, trzeba mieć to
+          na uwadze. Instalacje rozpoczynamy od zainstalowania odpowiednich
+          pakietów.
+        </p>
+<pre class="code-block">
+$ pacman -Syu xorg xorg-xinit xorg-xauth fluxbox xf86-video-intel terminator
+</pre>
+        <p>
+          W dystrybucjach opartych na Arch-u zauważyłem, że duże pakiety
+          oprogramowania są podzielone na mniejsze częsci, jeśli nie 
+          zainstalujemy pakietu xorg-xinit to będzie brakować polecenia
+          <strong>startx</strong>. Pakiet 
+          <code class="code-block">xf86-video-intel</code> można by tak
+          rzec, że jest to podstawowy sterownik grafiki, bez niego środowisko 
+          nie ruszy
+          czego osobiście doświadczyłem. Jako emulator terminala wybrałem, 
+          <strong>terminator</strong>
+          ponieważ jest samodzielnym programem zapewniającym poprawne
+          wyświetlanie polskich znaków (O tym będzie w następnym punkcie).
+        </p>
+        <p>
+          Po zainstalowaniu pakietów uruchamiamy środowisko graficzne i
+          zaraz je zamykamy. Przez to <em>fluxbox</em> utworzy w katalogu
+          domowym użytkownika, katalog konfiguracyjny <em>.fluxbox</em> w
+          nim znajduje się plik pod nazwą <em>menu</em>. Aby uruchomić poraz
+          pierwszy środowisko graficzne, potrzebujemy pliku, który wskaże
+          serwerowi X11, który menedżer okien ma uruchomić, taki plik nazywa
+          <em>.xinitrc</em> i znajduje się w katalogu domowym użytkownika.
+          W pliku wystarczy zapisać jedno polecenie:
+        </p>
+<pre class="code-block">
+exec fluxbox
+</pre>
+        <p>
+          Ten plik może wydawać się nie pozorny, jednak będzie zawierać
+          istotne ustawienia, takie jak ustawienie tapety czy chyba
+          najważniejsze, ustawienia układu klawiatury w środowisku graficznym.
+        </p>
+        <p>
+          Przy pierwszym uruchomieniu <em>fluxbox</em> utworzy w katalogu
+          domowym użytkownika, katalog konfiguracyjny <em>.fluxbox</em> w
+          nim znajduje się plik <em>menu</em>. W pliku odnajdujemy
+          znacznik <em>[begin]</em> w nawiasie okrągłym obok możemy podać
+          tytuł menu np. "<em>Parabola GNU/Linux-libre on MacBook 2,1</em>".
+          Od znacznika <em>[begin]</em> po znacznik <em>[end]</em>
+          znajduje się definicja menu głównego, pierwszy
+          wpis oznaczony znacznikiem <em>[exec]</em> zawiera wpis w menu dla
+          programu <em>xterm</em>, takie programu w systemie nie ma (możemy
+          go doinstalować jednak na próżno szukać w nim poprawnego wyświetlania
+          polskich znaków). Ten wpis przystowujemy, aby uruchamiał program
+          <em>terminator</em>. Budowa wpisu elementu menu, wygląda następująco. 
+          Na początku mamy <strong>typ elementu</strong>, może być to program
+          co jest równoznaczne z typem <em>[exec]</em> lub np. submenu jeśli
+          chcemy podzielić wpisy. Wiele typów jest wypisanych w
+          domyślnej konfiguracji wewnątrz pliku. Na tym etapie interesować nas
+          będzie wyłącznie <em>[exec]</em>. Następnym elementem wpisu jest
+          etykieta elementu umieszczona wewnątrz nawiasów okrągłych
+          <strong>()</strong>. Możemy wpisać cokolwiek, oczywiście warto 
+          pamiętać o tym, że ta etykieta pozwoli nam odnaleźć ten konkretny 
+          program, gdy w menu nagromadzi się wiele wpisów w miarę 
+          korzystania z komputera. Ostatnim elementem jest polecenie zawarte
+          w tym przypadku w nawiasach klamrowych <strong>{}</strong>. Aby
+          dostosować wpis <em>xterm</em> dla <em>terminatora</em>, zamieniamy
+          <em>xterm</em> na <em>terminator</em>. Skoro wiemy jak dodawać
+          programy do menu, to nic nie stoi na przeszkodzie, aby doinstalować
+          swoje ulubione programy, o ile tylko znajdują się one w repozytorium.
+        </p>
+        <p>
+          Warto wspomnieć że wykorzystywaną przeglądarką w tej dystrybujcji
+          jest <strong>Iceweasel</strong>. Jest to z przerobiony Firefox, z
+          którego usunięto obsługę DRM oraz wszystkie rzeczy, które przez FSDG
+          (<em>Free Software Distribution Guidelines</em>) - wytyczne dla
+          wolnych dystrybucji uznawane są za nie wolne (<em>non-free</em>). 
+          Ta przeglądarka była zamiennikiem Firefoxa dla Debiana od 4 wersji 
+          oraz dla innych dystrybucji bazujących na nim do 2016 roku. 
+          Pamiętam, że jej zaletą była
+          świetna wydajność na każdym możliwym sprzęcie, i to się chyba nie
+          zmieniło. Deweloperzy Parabola GNU/Linux-libre są chyba jedynym
+          zespołem, który aktywnie rozwija ten porzucony projekt. Brak DRM
+          oznacza, że korzystając z tej przeglądarki możemy zapomnieć o
+          korzystaniu z większości serwisów streamingowych.
+        </p>
+        <p>
+          Jeśli chodzi o moją konfigurację, to używam <em>terminatora</em> jako
+          emulatora terminala, <em>Vim</em>-a jako domyślnego edytora tekstów
+          w nim pisze ten tekst, <em>moc (ang. Music on Console)</em> - jako
+          odtwarzacza muzyki, <em>mpv</em> jako odtwarzacza plików wideo.
+          <em>leafpada</em> jako podręcznego notatnika, <em>htop</em> jako
+          mendżera zadań (istotną jego rolą jest wskaźnik poziomu naładowania
+          baterii, dlatego działa non stop), graficzny menedżer plików zastępuje
+          mi konsolowy <em>ranger</em>. To wszystko. 
+        </p>
+        <p>
+          Wrócimy do menu. W podmenu <em>Fluxbox</em> możemy zmienić
+          domyślny motyw mendżera okien. Na swoim komputerze wybrałem
+          temat <em>BlueNight</em>, który komponuje się z tapetą Parabola
+          GNU/Linux-libre, ukradzoną z obrazu instalacyjnego wersji 
+          skierowanej na desktopy. Żeby nie musieć uruchamiać jeszcze raz
+          komputera z płyty umieściłem ją na w serwisie ImgBB, link znajduje 
+          się poniżej.
+        </p>
+        <p>
+          <a href="https://ibb.co/RPjpy4g">https://ibb.co/RPjpy4g</a>
+        </p>
+        <p>
+          Aby ustawić tapetę potrzebujemy zewnętrznego programu. Takim program
+          może być <strong>feh</strong>, w którym ustawienie tapety jest jedną
+          z dodatkowych funkcji, tak naprawdę to program do otwierania plików
+          graficznych czy też obrazów. Pobrany plik tapety należało by gdzieś
+          zabezpieczyć aby nie usunąć go przypadkiem podczas oczyszczania,
+          katalogu <em>Pobrane</em> czy <em>Downloads</em>. W pliku
+          <em>~/.xinitrc</em> nad poleceniem 
+          <code class="code-inline">exec</code> zapisujemy poniższe polecenie.
+        </p>
+<pre class="code-block">
+feh --bg-fill ~/sciezka/do/pliku/tapety
+</pre>
+        <p>
+          Zapisujemy zmiany. Jeśli uruchomimy teraz środowisko graficzne,
+          tapeta mignie nam na chwile i najprawdopodbniej zostanie zastąpiona
+          tłem wybranego przez nas tematu. Musimy wyłączyć tło z tego tematu.
+          Motywy dostarczane wraz z system dostępne są w katalogu 
+          <em>/usr/share/fluxbox/styles</em>, jeśli styl w tym katalogu jest
+          podkatalogiem, to w środku podkatalogu znajduje się plik
+          <em>theme.cfg</em>, w nim trzeba wyłączyć wszystkie linie dotyczące
+          tła (ang. <em>background</em>). Wyłączyć je możemy umieszczając
+          na ich początku symbol komentarza.
+        </p>
+<pre class="code-block">
+#background: flat
+#background.color: rgb:6A/9A/AF
+</pre>
+      </li>
+      <li>
+        <strong>Ustawienie polskich znaków w konsoli, polskiego układu
+        klawiatury w środowisku graficznym oraz problemy z NetworkManager po
+        aktualizacji oraz nazwa komputera.</strong>
+        <p>
+          Podczas instalacji ustawialiśmy w pliku opcje dotyczące czcionki oraz
+          mapę znaków konsoli. Jednak jak mogliśmy zauważyć zamiast
+          polskich znaków wyświetlają się białe kwadraciki. Jeśli otworzymy
+          ten plik jeszcze raz, w pierwszej linii znajduje sie informacja, że 
+          te ustawienia nie są włączone domyślnie i trzeba je właczyć za pomocą
+          podanego polecenia.
+        </p>
+<pre class="code-block">
+$ sudo rc-update add consolefont boot
+</pre>
+        <p>
+          Po restarcie, polskie znaki powinny poprawnie się wyświetlać.
+        </p>
+        <p>
+          Kiedy uruchomimy środowisko graficzne oraz terminator, to tutaj też
+          może być problem z polskimi znakami. Problem wynika z tego, że
+          serwer <em>xorg</em>, nie ma załadowanego polskiego układu klawiatury
+          Układ klawiatury dla <em>X Window</em> może być ładowany przed jego 
+          startem, więc dodamy kolejne trzecie polecenie do pliku
+          <em>~/.xinitrc</em>. Polecenie to umieszczamy nad poleceniem
+          <code class="code-inline">exec</code>.
+        </p>
+<pre class="code-block">
+setxkbmap -layout pl
+</pre>
+        <p>
+          Po zamknięciu <em>Fluxbox</em>-a (opcja <em>Exit</em> w submenu
+          <em>Fluxbox</em>) i uruchomieniu jeszcze raz środowiska graficznego,
+          polskie znaki w <em>terminatorze</em> powinny się wyświetlać
+          poprawnie.
+        </p>
+        <p>
+          Podczas aktualizacji systemu zostanie zainstalowana nowa wersja
+          programu <em>NetworkManager</em>. Instalacja tej aktualizacji
+          usuwa ten program jako usługę, co może nieco utrudnić nam życie,
+          ponieważ będzie trzeba za każdym razem łączyć się samodzielnie
+          z internetem, jest to jeszcze do zniesienia jeśli mamy
+          zainstalowany pakiet <em>dhclient</em>. <em>NetworkManager</em>
+          zawiera kilka wygodnych narzędzi jak <em>nmtui-connect</em>
+          (menedżer połaczeń sieciowych) czy <em>nmtui-hostname</em>. Ze
+          względu na ten problem kazałem podczas instalacji skopiować plik 
+          usługi
+          NetworkManager. Teraz wystarczy go przekopiować do katalog 
+          <em>/etc/init.d</em> nadać odpowiednie uprawnienia i dodać do
+          uruchomienia wraz ze startem systemu.
+        </p>
+<pre class="code-block">
+$ sudo su
+# cp /root/NetworkManager /etc/init.d
+# chmod +x /etc/init.d/NetworkManager
+# rc-update add NetworkManager boot
+</pre>
+        <p>
+          Ostatnim zagadnieniem na tej liście będzie nazwa komputera. Podczas
+          instalacji wsponiałem, że zdefiniowanie nazwy hosta w pliku tak jak 
+          każe przewodnik instalacji nic nie da ponieważ to nie działa.
+          Podczas uruchamiania systemu, uruchamiana jest również usługa
+          <em>hostname</em> jednak jej start kończy się fiaskiem. Dlaczego?
+          Otóż dlatego, że mino odczytu nazwy z pliku podanego w poradniku to
+          w systemie brakuje programu, który tę nazwę ustawi - polecenia 
+          <strong>hostname</strong>. 
+          Podejrzewam, że usługa ta jest jedną z domyślnych systemu
+          <em>OpenRC</em>, a sama dystrybujcja wykorzystująca tego typu wersję
+          programu <em>init</em> nie przewiduje potrzeby posiadania polecenia
+          <em>hostname</em>. Jedynym w miarę zadawalającym wynikiem jest
+          użycie wspomnianego już narzędzia <strong>nmtui-hostname</strong>.
+          Problem z tym rozwiązaniem jest tego typu, że nazwa zostanie 
+          ustawiona dopiero po zalogowaniu się użytkownika. Po wydaniu
+          polecenia:
+        </p>
+<pre class="code-block">
+$ sudo mntui-hostname
+</pre>
+        <p>
+          Wyświetli się okienko z polem do wpisania nazwy komputera, następnie
+          wybieramy "Ok", jeśli nazwa nie zostanie ustawiona od razu wymagany
+          będzie restart systemu.
+        </p>
+        <p>
+          Opisane powyżej problemy prawdopodbnie występują wyłącznie w wersji
+          OpenRC Parabola GNU/Linux-libre.
+        </p>
+      </li>
+    </ol>
+    <p>
+      Podsumowując, dużo satysfakcji daje posiadanie w pełni wolnego systemu
+      operacyjnego na mogło by się wydawać tak zamkniętym sprzęcie jakim
+      może być ten MacBook. Sam jestem zdumiony, że wszystko w nim działa od
+      możliwości uruchomienia środowiska graficznego po sieć bezprzewodową to
+      pierwsze potrafi nie być tak oczywiste a o tym drugim na wielu sprzętach
+      przenośnych możemy poprostu zapomnieć lub dokupić sobie adapter z chipem,
+      dla którego istnieje wolny sterownik. Jaką kartę kupić możemy sprawdzić
+      na tym portalu: <a href="https://deviwiki.com/">https://deviwiki.com</a>.
+      Problem z korzystaniem z komputera tego typu jest klawiatura, MacBooki
+      mają inny okład klaiwszy od zwykłych pecetowych klawiatur. Sam system
+      posiada kilka niedociągnęć. Podejrzewam jednak, że niema dystrybucji
+      doskonałej, a bazując na swoich doświadczeniach zauważyłem, że im więcej
+      warstw (duża ilość róźnych demonów, podsystemów itp.) tym więcej jest
+      z taką dystrybucją problemów. Warto by naprawić w tej dystrybucji tę
+      nazwę komputera bo to trochę żałosne. Każą Ci to zrobić w poradniku
+      instalacji, a to i tak niedziała (XD). Czy będe korzystał z tego
+      komputera i systemu? Podoba mi się wydajność opisanego tu rozwiązania
+      na tym sprzęcie. Jedyną wadą może być brak dostępu do maszyn wirtualych,
+      ale mam w zanadzrzu jescze kilka serwerów. Więc myślę, że tak.
+      Wracając do klawiatury. MacBooki zarówno
+      te stare jak i te nowe posiadają inny układ klawiatury, różni się on
+      o tyle, że przesiadając się na z PC na Maca i odwrotnie trzeba
+      się chwilę do niej przyzwyczaić. Komputery Apple
+      w swoich klawiaturach mają zamieniony miejscem (względem klawiatur PC) 
+      prawy alt. Klawisz ten to modyfikator do
+      wpisywania liter diakrytycznych specyficznych dla konkretnego języka.
+      W moim przypadku gdy korzystam na PC z klawiatur gamingowych nie 
+      posiadają one prawego klawisza Windows. Posiadają przycisk Fn, który nie
+      jest przekazywany do komputera przez klawiaturę, więc nie miałem z czym
+      zamienić klawisza alt, ale jeśli nie w tę strone to może w drugą. Na
+      MacBooku zamienię prawy alt z prawym CMD.
+      Znalazłem na serwisie <a href="https://superuser.com">superuser.com</a>
+      jak zamienić ze sobą klawisze na środowiskach graficznych opartych na
+      <em>X Window</em>. Potrzebny jest dodatkowy <em>dot-file</em> 
+      <em>.Xmodmaprc</em> w katalogu
+      domowym użytkownika oraz dodatkowe polecenie w pliku <em>.xinitrc</em>.
+      Poniżej znajduje się listing pliku <em>.Xmodmaprc</em> z poleceniami dla 
+      programu <strong>xmodmap</strong>.
+    </p>
+<pre class="code-block">
+remove mod5 = ISO_Level3_Shift
+remove mod4 = Super_R
+keycode 108 = Super_R
+keycode 134 = ISO_Level3_Shift
+add mod5 = Super_R
+add mod4 = ISO_Level3_Shift
+</pre>
+    <p>
+      Po utworzeniu pliku zapisujemy polecenie, które uruchomi zamianę klawiszy
+      przed uruchomieniem środowiska graficznego (polecenie umieszczamy przed
+      poleceniem <code class="code-inline">exec</code>). To rozwiązanie działa 
+      tylko dla środowiska graficznego.
+    </p>
+<pre class="code-block">
+xmodmap ~/.Xmodmaprc
+</pre>
+    <p>
+      Z czystej ciekawości postanowiłem sprawdzić na większości swoich sprzętów
+      jak na nich będzie funkcjonować Parabola. Poniżej zamieściłem tabelkę z
+      nazwą sprzętu oraz z tym co działa a co nie.
+    </p>
+    <table style="text-align: center;">
+      <tr>
+        <th style="border-bottom: 1px solid black;">Lp.</th>
+        <th style="border-bottom: 1px solid black;">Nazwa sprzętu</th>
+        <th>GUI</th>
+        <th>Audio</th>
+        <th>Wi-Fi</th>
+        <th>Uwagi</th>
+      </tr>
+      <tr>
+        <td>1.</td>
+        <td>Apple MacBook A1181</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+            <td style="text-align: justify;">
+          32-bitowe EFI, trzeba specjalnie przygotować dysk USB, żeby zbootwać 
+          Linux-a na tym sprzęcie.
+        </td>
+      </tr>
+      <tr>
+        <td>2.</td>
+        <td>Saphire Pure White Fusion<br />AMD E-350 mini-ITX</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>N/A</td>
+        <td style="text-align: justify;">
+            Domyślnym wyjściem audio jest port HDMI, możemy zmienić to
+            wyświetlając listę wyjść audio oraz wskazując odpowiednie wyjście
+            sterownikowi. Listę wyjść możemy wyświetlić za pomocą polecenia:
+<pre class="code-block">
+$ lspci -knn | grep -iA2 audio
+</pre>
+            Lista domyślnie numerowana jest od 0. Jest to istotne, ponieważ
+            trzeba podać <em>index</em> - pozycję na liście.
+            Domyślne wyjście ustawiamy tworząc plik <em>default.conf</em> w
+            katalogu <em>/etc/modprobe.d</em>. W pliku zapisujemy poniższą
+            linię.
+<pre class="code-block">
+options snd_hda_intel index=1
+</pre>
+        </td>
+      </tr>
+      <tr>
+        <td>3.</td>
+        <td>HP Z600 Workstation</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>N/A</td>
+        <td style="text-align: justify;">
+          Bardzo szybkie działanie systemu!
+        </td> 
+      </tr>
+      <tr>
+        <td>4.</td>
+        <td>Gigabyte H55M-UD2H/i5-650/<br />16GB DDR3 1333MHz/GeForce 210</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>N/A</td>
+        <td style="text-align: justify;"></td>   
+      </tr>
+      <tr>
+        <td>5.</td>
+        <td>HP 550</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>&#9746;</td>
+        <td style="text-align: justify;">
+          Karta sieciowa Broadcom, brak wolnego sterownika.
+        </td>
+      </tr>
+      <tr>
+        <td>6.</td>
+        <td>Dell Wyse Z90D7</td>
+        <td>&#9745;</td>
+        <td>&#9745;</td>
+        <td>N/A</td>
+        <td style="text-align: justify;">
+            Problemy z UEFI, przy próbie zainstalowania systemu wyświetla się
+            <em>"Could not prepare boot variable: No space left on device"</em>.
+            Nie możliwe jest zbootowania z BIOS. Zainstalowałem 
+            <strong>rEFInd</strong> na
+            dysku USB w środowisku zmienionego katalogu (dysk z zainstalowanym
+            system oraz programem rozruchowym w trybie BIOS), przez co program
+            utworzy wpis w menu umożliwiający uruchomienie z niego jądra.
+            Program należy zainstalować z repozytorium a następnie wydać
+            poniższe polecenie.
+<pre class="code-block">
+refind-install --usedefault /dev/sdXY
+</pre>
+            Gdzie <code class="code-block">/dev/sdXY</code> jest partycją
+            stworzoną na dysku USB, partycja powinna być ustawiona na
+            <em>EFI</em> (kod typu partycji w programie <em>fdisk</em>: 
+            <em>ef</em>) oraz sformatowana na <em>FAT-32</em>.</td>
+      </tr>
+    </table>
+    <p>
+      Jeden wpis nie oznacza całej tabeli, w miarę moich możliwości będę
+      sprawdzał inne sprzęty, o aktualizacjach będę informował w changelogu
+      na stronie głównej.
+    <p>
+    <p>
+      Źródła:
+    </p>
+    <ol>
+        <li><a href="https://wiki.debian.org/InstallingDebianOn/Apple/MacBook/2-1">Przydatne informacje podczas tworzenia USB z obrazem płyty dla MacBook 2,1</a></li>
+        <li><a href="https://wiki.parabola.nu/Installation_Guide">
+            Poradnik instalacji Parabola GNU/Linux-libre</a></li>
+        <li><a href="https://superuser.com/questions/277990/how-do-i-swap-alt-and-windows-keys-with-xmodmap">
+            Zamiana klawiszy za pomocą xmodmap na https://superuser.com</a>
+        </li>
+        <li><a href="https://forums.debian.net/viewtopic.php?t=123902">
+            Ustawienie domyślnego wyjścia audio dla sterownika HDA Intel</a>
+        </li>
+        <li><a href="https://wiki.archlinux.org/title/REFInd">
+            Artykuł o rEFInd na Wiki Arch Linux</a></li>
+    </ol>
+    <p>
+      ~xf0r3m
+    </p>
+       </div>
+
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/linux/generowanie_certyfikatu_Let's_Encrypt_typu_wildcard.html b/articles/linux/generowanie_certyfikatu_Let's_Encrypt_typu_wildcard.html
new file mode 100644 (file)
index 0000000..27834b2
--- /dev/null
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type"image/png" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+<p class="header_link"> 
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+        <h1 class="title">Generowanie certyfikatu SSL Let's Encrypt typu Wildcard</h1>
+        <p>
+            Pośród materiałów odnośnie GNU/Linux znajduje się też taki nt. generowania <strong>certyfikatu SSL</strong> podpisanego przez samego siebie. W tym materiale wykorzystamy ogólnodostępny urząd certyfikacji - usługę <strong>Let's Encrypt</strong>. Nie wiem jaka jest geneza tej usługi, ale śmiem przypuszczać że ideą, która za tym stoi jest umożliwienie każdemu posiadaczowi domeny wygenerowanie certyfikatu SSL, w celu zabezpiecznia transmisji pomiędzy jego serwerami a klientami korzystającymi z usług świadczonych przez ten serwer. Cel sczytny, ale każdy kij ma dwa końce. Do momentu upowszechnienia się Let's Encrypt, "zielona kłódka" oznaczała serwer godny zaufania, ponieważ tylko komercyjne certyfikaty były akceptowane przez przeglądarkę bez zastrzeżeń.
+                                               Teraz tylko tyle że "kłódka" jest zielona, nie może oznaczać że serwer jest wiarygodny, teraz liczy się głównie wystawca, jednak aby zobaczyć kto jest wystawcą danego certyfikatu należy kliknąć w tą "kłódkę" i będziemy mieli taki napis jak "Connection secure" lub "Połączenie zabezpieczone" kilkamy w tą strzałeczkę po prawej stronie i powinno się wyświetlić "Verified by: " lub "Zweryfikowano przez: " i nazwa wystawcy. Oczywiście nie możemy demonizować Let's Encrypt bo naprawdę jest to coś dobrego, chciałbym tutaj tylko uczulić na to że jeśli logujemy się do banku to jeśli już weryfikujemy czy połączenie jest bezpieczne, to sprawdźmy wystawcę, na 99,9% na pewno nie powinno być nim Let's Encrypt.
+                                               Chyba że to jakiś bank dla Januszy, to warto zmienić bank wtedy. Tak samo jest kontami na socjalacha czy skrzynkach mailowych. Duże korporacje mają swoje wewnętrzne urzędy, które dbają o ich certyfikaty. Obecnie intruzi, którzy stosują phishing, często wykorzystują Let's Encrypt aby jeszcze bardzie uwiarygodnić strony do wyłudzania danych. Nie mniej jednak każdy może mieć taki certyfikat wystarczy posiadanie domeny. Certyfikat, który będzie akceptowany w 100% przez przeglądarkę. I tutaj dowiemy się jak go uzyskać.
+        </p>
+        <p>
+            Pierwszą czynnością jest zdobycie oprogramowania, które umożliwi nam uruchomienie procesu generowania certyfikatu przez Let's Encrypt. W zależności od systemu, czy jest <em>Raspbian/RasPiOS</em> pownieważ chcemy uzyskać nasz certyfikat na <em>Raspberry Pi</em>, co może być ciekawym pomysłem o ile powstrzymamy się z wykorzystaniem karty z Raspberry do czegoś innego, kiedy będzie nam ona potrzebna. Nie jest to niezbędne, ale lepiej jest zachować system na którym uzyskało się certyfikat poźniej będzie go łatwiej odnowić, certyfikaty Let's Encrypt ważne są tylko przez 3 miesiące, oczywiście odnawiać będziemy tylko certyfikaty wystawione manualnie. Zatem dla Raspbiana powiniśmy wydać poniższe polecenia.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt install certbot
+</pre>
+        <p>
+            Jeśli korzystamy z Ubuntu to należy na początku sprawdzić powyższe polecenia, a jeśli ono niezadziała, to należy spróbować tych poleceń poniżej.
+        </p>
+<pre class="code-block">
+$ sudo add-apt-repository ppa:certbot/certbot
+$ sudo apt update
+$ sudo apt install certbot
+</pre>
+        <p>
+            Jeśli wykorzystujemy inną dystrybucje niż powyższe to spóbujmy zainstalować pakiet certbot za pomocą menedżera pakietów używanej przez nasz dystrybucji. Gdy na nawet to się nie powiedzie, to wtenczas możemy odpytać naszą wyszukiwarkę "How to install certbot on", po słowie "on" podajemy nazwę naszej dystrybucji.
+        </p>
+        <p>
+            Po zainstalowaniu certbot-a w naszym systemie, zalogujmy się do konfiguracji domeny u swojego operatora, żeby uwierzytelnić się (pokazać że domena należy do nas) będziemy musieli dodać dwa rekordy DNS. Kiedy już się zalogujemy to wydajemy poniższe polecenie, uruchomi ono cały proces uzyskiwania certyfikatu.
+        </p>
+<pre class="code-block">
+$ sudo certbot certonly --manual -d *.&lt;nazwa_domeny&gt; -d &lt;nazwa_domeny&gt; --agree-tos --no-bootstrap --manual-public-ip-logging-ok \
+--preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
+</pre>
+        <p>
+            Jeśli kopiujemy to polecenie pamiętajmy o tym że należy podać w polach <code class="code-inline">&lt;nazwa_domeny&gt;</code> nazwę swojej domeny. Po wydaniu tego polecenie zostaniemy zapytani o adres email. Polecam podać prawdziwą skrzynkę ponieważ na nią przyjdzie wiadomość o wygasającym certyfikacie.
+        </p>
+<pre class="code-block">
+Saving debug log to /var/log/letsencrypt/letsencrypt.log
+Plugins selected: Authenticator manual, Installer None
+Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): &lt;adres_email&gt;
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+</pre>
+        <p>
+            Po podaniu adresu email zostaniemy zapytani o to czy chcemy się zapisać tak jak by do newsletter-a EFF.
+        </p>
+<pre class="code-block">
+Would you be willing to share your email address with the Electronic Frontier Foundation, a founding
+partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to
+send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital
+freedom.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+(Y)es/(N)o:
+</pre>
+        <p>
+            Po udzieleniu odpowiedzi na powyższe pytanie, rozpocznie się uzyskiwanie certyfikatów. Aby uzyskać certyfikaty musimy wprowadzić jedno lub dwukrotnie nowy <strong>rekord typu TXT</strong> w konfiguracji naszej domeny. Rekord powinień mieć nazwę <code class="code-inline">_acme-challenge.&lt;nazwa_domeny&gt;</code>, gdzie za <code class="code-inline">nazwa_domeny</code> podstawiamy nazwę naszej domeny wartością tego rekordu będzie ciąg znaków wyświetlony tak jak na poniższym komunikacie.
+        </p>
+<pre class="code-block">
+Please deploy a DNS TXT record under the name
+_acme-challenge.&lt;nazwa_domeny&gt; with the following value:
+
+[Tutaj pojawi się tekst challengu]
+
+Before continuing, verify the record is deployed.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Press Enter to Continue
+</pre>
+        <p>
+            W powyższym polu <code class="code-inline">[Tutaj pojawi się tekst challengu]</code> pojawi się ciąg znaków jaki należy umieścić w polu wartości rekordu. Zwróćmy uwagę na przedostatnią linijkę komunikatu <code class="code-inline">Before continuing, verify the record is deployed.</code> (ang. Przed kontynuowaniem, należy upewnić się że rekord jest wdrożony). Aby to zrobić wydajmy w wierszu polecenia (terminalu) następujące polecenie.
+        </p>
+<pre class="code-block">
+$ dig -t TXT _acme-challenge.&lt;nazwa_domeny&gt;
+</pre>
+        <p>
+            Poniżej znajduje się odpowiedź, dla przykładu wylisowałem rekordy tego typu dla mojej domeny.
+        </p>
+<pre class="code-block">
+; &lt;&lt;&gt;&gt; DiG 9.16.12 &lt;&lt;&gt;&gt; -t TXT _acme-challenge.morketsmerke.net
+;; global options: +cmd
+;; Got answer:
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 37679
+;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags:; udp: 512
+;; QUESTION SECTION:
+;_acme-challenge.morketsmerke.net. IN   TXT
+
+;; ANSWER SECTION:
+_acme-challenge.morketsmerke.net. 3600 IN TXT   "G6XrpiukUNExZy_5iOJgaqqA4oxQiDJlhW0MIkXs82s"
+_acme-challenge.morketsmerke.net. 3600 IN TXT   "Z2ibO22FCPjxOQBTYuMz4H_S3UyRU8c2SJO4zsQ9ifY"
+
+;; Query time: 600 msec
+;; SERVER: 192.168.8.1#53(192.168.8.1)
+;; WHEN: wto mar 02 19:08:33 CET 2021
+;; MSG SIZE  rcvd: 173
+</pre>
+        <p>
+            Na podstawie danych zwróconych przez polecenie, możemy ustalić czy nasz rekord jest już osiągalny w Internecie, może się zdarzyć że długo nie będziemy mogli uzyskać odpowiedzi, niestety będziemy musieli się uzbroić w cierpliwość. Kiedy uzyskamy oczekiwany rezultat, wtedy dopiero będziemy mogli nacisnąć enter.
+        </p>
+        <p>
+            Jest wielce prawdopobne że po zatwierdzeniu jednego challenge-u, niezbędny będzie drugi. Procedura wygląda identycznie. Tutaj jednak z sprawdzeniem wdrożenia rekordu może być problem ponieważ serwery DNS, utrzymują ostatnie wyniki zapytań w pamięci podręczej. Najlepiej jest użyć do tego drugie komputera wraz z drugim łączem internetowym np. z komórki.
+        </p>
+        <p>
+            Po udanym procesie zostaniem wyświetlone dłuższe podsumowanie zawierające napis "Congratulations!" świadczący o pomyślnym wykonaniu zadania w nim również będą zawarte ścieżki na których znajdują się certyfikaty, warto przeszukać katalog <em>/etc/letsencrypt</em>, ponieważ te ścieżki wskazują na dowiazania symboliczne, to prawdziwe pliki certyfikatu (plik certyfikatu oraz klucz prywatny) mogą nam się przydać o ile bedziemy przenościć certyfikat na inne serwery.
+        </p>
+<!--
+<pre class="code-block">
+Tu wstawić komunikat o uzyskaniu certyfikatów Let's Encrypt
+</pre>
+-->
+        <p>
+            Istnieje możliwość wygenerowania certyfikatu dla jednego hosta. Cały proces wygląda analogicznie, różni się tylko polecenie, które z resztą znajduje się
+            poniżej.
+        </p>
+<pre class="code-block">
+$ sudo certbot certonly --manual -d &lt;nazwa_hosta&gt;.&lt;nazwa_domeny&gt; -d &lt;nazwa_domeny&gt; --agree-tos --no-bootstrap --manual-public-ip-logging-ok \
+--preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
+</pre>
+        <p>
+            Jedyną róznicą jest podanie nazwy hosta jak wartości przełącznika <code class="code-inline">-d</code>, zamiast nazwy wieloznacznej (*.&lt;nazwa_domeny&gt;).
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/linux/generowanie_certyfikatów_self-signed_OpenSSL.html b/articles/linux/generowanie_certyfikatów_self-signed_OpenSSL.html
new file mode 100644 (file)
index 0000000..0e4779e
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.net">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+        <h1 class="title">Generowanie certyfikatu SSL Self-Signed za pomocą pakietu OpenSSL</h1>
+        <p>
+            <strong>Jednym z założeń używania certyfikatów SSL jest uwierzytelnienie serwera przed klientem</strong>, innymi słowy - przedstawienie podmiotu zarządzającego maszyną, po to aby klient miał pewność że połączył się z właściwym serwerem. Takie certyfikaty są wydawane przez firmy trzecie, które są w stanie poświadczyć że witryna www.example.com należy do firmy Example Inc. Wydanie takiego certyfikatu może kosztować grube pieniądze w zależności od tego co dany certyfikat oferuje. Komercyjny certyfikat często wyświetla się w przeglądarce jako zielona kłódka przy adresie strony. W dziesiejszych czasach wystarczy dysponować domeną, aby móc posiadać "zieloną kłódkę" na swojej stronie. Takie certyfikaty wystawiane są przez <strong>Let's Encrypt</strong> i każdy, dosłonie każdy może sobie taki certyfikat wyrobić. A co jeśli nie posiadamy żadnej domeny i chcemy np. zabezpieczyć nasz serwer www, za pomocą <strong>certyfikatu SSL</strong> (protokołu HTTPS, certyfikat jest tylko narzędziem), którego zawsze pierwszorzędnym celem jest zabezpieczenie transmisji pomiędzy klientem a serwerem. Możemy:
+        </p>
+        <ul style="list-style-type: upper-alpha;">
+                <li>Użyć certyfikatu wbudowanego w serwer Apache, o ile używamy tego programu jako serwera WWW oraz mamy zaufanie do tego certyfikatu.</li>
+                <li>Wygenerować własny certyfikat wraz parą kluczy RSA. Klucze są niezbędne do wygenerowania certyfikatu, których np długość możemy ustawić. Od długości klucza zależy bezpieczeństwo naszej transmisji.
+                </li>
+        </ul>
+        <p>
+            Aby utworzyć swój własny certyfikat SSL wydajemy poniższe polecenie.
+        </p>
+<pre class="code-block">
+$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt
+</pre>
+    <p>
+        Z względu na to gdzie chcemy ten certyfikat zapisać musimy wydać to polecenie z odpowiednimi uprawnieniami. <code class="code-inline">req</code> oznacza że <strong>OpenSSL</strong> bedzie używać modułu do podpisu żądań certyfikatu schematu <em>X.509</em> zapisanego w formacie <em>PKCS#10</em>, jest klasyczny moduł do obsługi certyfikatów wykorzystywanych przez HTTPS, <code class="code-inline">-x509</code> spowoduje że wygenerowany certyfikat będzie miał strukturę schematu x509, a nie klasycznego certyfikatu, <code class="code-inline">-nodes</code> wyłącza szyfrowanie klucza prywatnego, dzieki czemu nie będzie potrzebne hasło klucza podczas każdego restartu certyfikatu (niestety, klucz nie jest przez to zbyt bezpieczny). <code class="code-inline">-days 365</code> ustala przez ile dni certyfikat będzie ważny. Wartością tej opcji może być wyłącznie dodatnia liczba całkowita. Wraz z certyfikatem generujemy potrzebną parę kluczy.
+                               Za pomocą opcji <code class="code-inline">-newkey</code>, tworzymy nową parę kluczy, jako wartośc dla tej opcji podajemy algorytm wykorzystywany do wygenerowania kluczy w tym przypadku jest <code class="code-inline">rsa</code> po dwukropku (<strong>:</strong>) podana jest długość klucza tutaj <code class="code-inline">2048</code> bitów co jest standardem na dziesiejsze czasy, krótszych kluczy sam OpenSSL nie będzie chciał stworzyć. Opcja <code class="code-inline">-keyout</code> wskazuje miejsce gdzie klucz ma zostać zapisany, a opcja <code class="code-inline">-out</code>, wskazuje miejsce zapisu wygenerowanego certyfikatu. Te dwie scieżki należy zapisać będą potrzebne do wskazania plików certyfikatu w pliku konfiguracyjnym serwera WWW.
+    </p>
+    <p>
+        Kiedy wygenerowaliśmy i wdrożyliśmy nasz certyfikat przejdź do strony, którą nim zabezpieczyliśmy. Do wiemy się z infomacji zwróconych przez przeglądarkę że nasz nie jest godny zaufania, a kłódka będzie posiadać znak ostrzegawczy. Dlaczego tak się dzieje ? Każda przeglądarka posiada własną bazę zaufanych wystawców certyfikatów. Jeśli certyfikat jakim serwer operuje nie posiada znaczników, którego kolwiek z nich wtenczas wyświetli nam się taka informacja. Wystawcy certyfikatów zwani również urzędami certyfikacji, posiadają własne certyfikaty służące do podpisu wniosków certyfikacyjnych, na ich podstawie generowane są certyfikaty. Jest wielce prawdopobne że urzędy wykorzystują to samo oprogramowanie co my. Nic nie stoi na przeszkodzie aby utworzyć sobie swój własny urząd certyfikacyjny i podpisywać za jego pomocą swoje certyfikaty. Niestety nie jest tak kolorowo jakby się mogło wydawać.
+                               Aby przeglądarka traktowała nasze certyfikaty jako zaufane musi posiadać w swojej bazie certyfikat naszego urzędu certyfikacji. Możemy zaimportować taki certyfikat do naszego systemu, wtedy po wejściu na strona kłódka będzie zielona. Niestety kłódka będzie zielona tylko tam gdzie zaimpotowalśmy certyfikat naszego urzędu.
+    </p>
+    <p>
+        Obecnie rzadko zdarza się potrzeba wygenerowania tego typu certyfikatów. Ale jeśli zajdzie taka potrzeba to teraz wiadmo, możemy to zrobić za pomocą pojedyńczego polecenia.
+    </p>
+    <p>~xf0r3m</p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/linux/greenOS/btw_i_use_arch.html b/articles/linux/greenOS/btw_i_use_arch.html
new file mode 100644 (file)
index 0000000..9d3f153
--- /dev/null
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+                               ____  _____
+   ____ _________  ___  ____  / __ \/ ___/
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \ 
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ / 
+ \__, /_/   \___/\___/_/ /_/\____//____/  
+/____/                                    
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">greenOS GNU/Linux 1.4 (btw i use Arch)</h1>
+    <p>
+      <strong>greenOS</strong> to póki co zdebrandowany Debian oldstable
+      zbudowany na minimalnej wersji bazowej (debootstap --variant=minbase).
+      Rozpowadzany w postaci obrazów LiveCD oraz archiwów z gotową hierarchią
+      katalogu głównego do rozpakowania na dysku. Instrukcja instalacji
+      znajduje się <a href="instalacja_greenos.html">tutaj</a>. 
+    </p>
+    <p>
+      Dane logowania do LiveCD to: <strong>root/toor</strong>.
+    </p>
+    <p>
+      Minimalna wersja bazowa została opatrzona następującymi pakietami:
+    </p>
+    <ul>
+      <li>net-tools</li>
+      <li>iproute2</li>
+      <li>wireless-tools</li>
+      <li>wget</li>
+      <li>openssh-client</li>
+      <li>vim</li>
+      <li>iputils-ping</li>
+      <li>man-db</li>
+      <li>texinfo</li>
+      <li>less</li>
+      <li>dosfstools</li>
+      <li>isc-dhcp-client</li>
+      <li>fdisk</li>
+      <li>whiptail</li>
+      <li>locales</li>
+      <li>keyboard-configuration</li>
+      <li>console-setup</li>
+      <li>rsync</li>
+      <li>git</li>
+      <li>neofetch</li>
+      <li>ntfs-3g</li>
+      <li>sudo</li>
+      <li>bash-completion</li>
+      <li>vrms</li>
+      <li>grub2 (tylko rootfs)</li>
+      <li>wpasupplicant</li> 
+    </ul>
+    <p>
+      Locales ustawione są en_US.UTF-8, układ klawiatury na Angielski (USA),
+      kodowanie konsoli na UTF-8 z domyślnymi wariantami. Serwer lustrzany
+      ustawiony jest na deb.debian.org. W dystrybucji nie znajduje się żadne
+      nie wolne oprogramowanie, i tak już zostanie. W oficjalnych wydaniach
+      gdy będzie to już dystrybucja i będzie ona posiadać własne
+      repozytorium, nie wolne oprogramowanie i jemu pochodne nie będą możliwe
+      do zainstalowania.
+    </p>
+    <p>
+      Obecnie wspierane są dwie ogólnodostępne architektury. Nie ma sensu
+      przenoszenie greenOS na inne bardziej egzotyczne, bo i tak prawdopodobnie
+      nie zostanie on na nich uruchomiony. Wspierane architektury to amd64 oraz
+      i386. Adresy do obrazów oraz archiwów znajdują się poniżej.
+    </p>
+    <ul>
+      <li>amd64 LiveCD:
+        <ul>
+          <li><a href="https://sourceforge.net/projects/greenos/files/iso/greenOS_1.4_amd64.iso/download">sourceforge.net</a></li>
+        </ul>
+      </li>
+      <li>i386 LiveCD:
+        <ul>
+          <li><a href="https://sourceforge.net/projects/greenos/files/iso/greenOS_1.4_i386.iso/download">sourceforge.net</a></li>
+        </ul>
+      </li>
+      <li>archiwum amd64:
+        <ul> 
+          <li><a href="https://sourceforge.net/projects/greenos/files/rootfs/rootfs_1.4_amd64.tgz/download">sourceforge.net</a></li>
+        </ul>
+      </li>
+      <li>archiwum i386:
+        <ul>
+          <li><a href="https://sourceforge.net/projects/greenos/files/rootfs/rootfs_1.4_i386.tgz/download">sourceforge.net</a></li>
+        </ul>
+      </li>
+    </ul>
+    <p>
+      Listy zmiany publikowane są na stronie projektu greenOS w serwisie git po
+      tym adresem: <a href="https://github.com/xf0r3m/greenOS">https://github.com/xf0r3m/greenOS</a>.
+    </p>   
+    <p>
+-- Changelog --
+    </p>
+    <p>
+      -- 18.06.2021 - Wydanie nieoficjalnej wersji greenOS oznaczonej nazwą kodową "first".<br />
+      -- 21.08.2021 - Wydanie pierwszej oficjalnej wersji greenOS oznaczonej nazwą kodową "one".<br />
+      -- 24.09.2021 - Zawieszenie wsparcia dla greenOS<br />
+      -- 05.12.2021 - Reaktywacja projektu greenOS<br />
+      -- 30.01.2022 - Wydanie greenOS wersji 1.1, zmiany w obrazie LiveCD
+      znajduje się <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_1.1_livecd.txt">
+      tutaj</a>, natomiast zmiany w archiwum
+      <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_1.1_rootfs.txt">tutaj</a><br />
+      -- 30.01.2022 - Wydanie wersji greenOS Ratpoison<br />
+      -- 27.03.2022 - Wydanie wersji greenOS 1.2, zmiany we wszystkich wersjach
+      dystrybucji znajdują się tutaj: <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_greenOS_1.2.txt">tutaj</a><br />
+      -- 27.03.2022 - Wydanie wersji greenOS greenServer<br />
+      -- 05.05.2022 - Zmiany w greenOS, wydanie greenOS w wersji 1.3<br />
+      -- 06.05.2022 - Wydanie greenOS w wersji 1.4<br />
+    </p>
+  </div>
+  <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/greenOS/index.html b/articles/linux/greenOS/index.html
new file mode 100644 (file)
index 0000000..73ee583
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       <body>
+<pre>
+                               ____  _____
+   ____ _________  ___  ____  / __ \/ ___/
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \ 
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ / 
+ \__, /_/   \___/\___/_/ /_/\____//____/  
+/____/                                    
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">greenOS</h1>
+    <ul class="special_list">
+           <li><a href="torwards_the_sun.html">greenOS 1 - 1.2 (Torwards the sun)</a></li>
+           <li><a href="btw_i_use_arch.html">greenOS 1.3 - 1.4 (btw i use Arch)</a></li>
+           <li><a href="instalacja_greenos.html">Poradnik instalacji greenOS</a></li>
+    </ul>
+  <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/greenOS/instalacja_greenos.html b/articles/linux/greenOS/instalacja_greenos.html
new file mode 100644 (file)
index 0000000..df66070
--- /dev/null
@@ -0,0 +1,464 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+                               ____  _____
+   ____ _________  ___  ____  / __ \/ ___/
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \ 
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ / 
+ \__, /_/   \___/\___/_/ /_/\____//____/  
+/____/                                    
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">Instalacja greenOS</h1>
+    <p>
+      GreenOS dostarczany jest bez instalatora. Przez co daje ogromne możliwość
+      konfiguracji systemu przed jego pierwszym uruchomieniem. Instalacja 
+      składa się z kilku poleceń.
+    </p>
+    <ol>
+      <li>
+        Uruchamiamy na naszej maszynie docelowej jakiegoś Linux-a w wersji Live,
+        może być to dowolna dystrybucja, którą akurat mamy pod ręką. Do 
+        instalacji wykorzystywać będzięmy podstawowe narzędzia. GreenOS 
+        również jest dostępny wersji LiveCD, można go uruchomić zarówno w 
+        trybie BIOS jak i UEFI.
+      </li>
+      <li>
+        <p>
+          Instalacja greenOS wymaga połączenia z Internetem, skądś należy 
+          pobrać paczkę z plikami katalogu głównego (rootfs).</p> 
+          <!--<p>Połączenie
+          sieciowe Ethernet odbywa się automatycznie, ze względu na
+          NetworkManager, połączyć się z siecią bezprzewodową możemy za pomocą
+          apletu konsoli NetworkManagera: <em>nmtui-connect</em>. W nim
+          wybieramy jedną z sieci, jeśli sieć jest zabezpieczona hasła to aplet
+          wyświetli okienko, w którym podamy hasło, po zatwierdzeniu hasła
+          następuje łącznie z siecią.
+        </p>
+<pre class="code-block">
+# nmtui-connect
+</pre>-->
+   
+<pre class="code-block">
+# dhclient $interface
+</pre>
+        <p>
+          gdzie <code class="code-inline">$interface</code> to nazwa interfejsu
+          Ethernet w systemie, możemy sprawdzić ją za pomocą polecenia 
+          <code class="code-inline">ip a</code>. Jeśli połączenie 
+          przewodowe nie jest dostępne, a mamy możliwość skorzystania z sieci 
+          bezprzewowdowej (tj. mamy widoczną kartę sieciową w systemie, oraz 
+          dostęp do jakiejś sieci bezprzewodowej), to podłaczanie się do sieci
+          bezprzewodowej należy zacząć od włączenia karty, za pomocą polecenia:
+        </p>
+<pre class="code-block">
+ip link set $interface up
+</pre>
+        <p>
+          <code class="code-inline">$interface</code> = interfejs sieci 
+          bezprzewodowej, następnie przeskanować otoczenie w poszukiwaniu
+          sieci bezprzewodowej, do której mamy dostęp. Do tego celu należy 
+          użyć polecenia:
+        </p>
+<pre class="code-block">
+iwlist $interface scan
+</pre>
+        <p>
+          Potrzebujemy tylko SSID, a to polecenie zwraca dużą ilość danych, 
+          należy przepuścić jej wyjście przez polecenie 
+          <em>grep</em> z wyrażeniem "SSID", dzięki temu poleceniu reszta 
+          danych wyjściowych zostanie odfiltrowana, a wyświetlone zostaną 
+          tylko nazwy sieci (SSID). W większości przypadków, połączenie się z 
+          siecią będzie wymagało klucza, w zależności od użytch zabepieczeń 
+          różnić się będzie metoda przyłączenia się do sieci. Jeśli nasza sieć 
+          używa standardu WPA, wtenczas należy użyć programu 
+          <em>wpa_supplicant</em>. Wymaga on pliku konfiguracyjnego, w którym 
+          znajdują się deklaracje sieci. Plik ten generuje się przekierowując 
+          standardowe wyjście polecenia <em>wpa_passphrase</em> do pliku. Plik 
+          może być zapisany gdzie kolwiek, poleceniu <em>wpa_supplicant</em> i 
+          tak podajemy ściężkę do niego. `wpa_passphrase` do wygenerowania 
+          plik musi mieć SSID sieci oraz klucz PSK, podajemy te informacje 
+          jako argumenty pozycjne:
+        </p>
+<pre class="code-block">
+wpa_passphrease RogueAP 123Test123 &gt; wpa_supplicant.conf
+</pre>
+        <p>
+          Po wygenerowaniu pliku konfiguracyjnego możemy przyłączyć się do
+          sieci za pomocą polecenia <em>wpa_supplicant</em>.
+        </p>
+<pre class="code-block">
+wpa_supplicant -B -D wext -i $interface -c $configFile
+</pre>
+        <p>
+          Gdzie:
+            <ul>
+              <li><code class="code-inline">$interface</code> - nazwa
+                bezprzewodowego interfeju sieciowego w systemie
+              </li>
+              <li><code class="code-inline">$configFile</code> - plik
+                konfiguracyjny <em>wpa_supplicant</em>, zawierający
+                profile sieci.
+              </li>
+            </ul>
+          Program powyświetleniu kilku komunikatów, przejdzie w tło, przez co
+          nie będzie zakłócać pracy w terminalu czy konsoli, na której go 
+          uruchmiliśmy. Aby upewnić się czy zostaliśmy przyłączeni możemy 
+          wydać polecenie:
+        </p>
+<pre class="code-block">
+iwconfig $interface
+</pre>
+        <p>
+          Polecenie zwróci informacje na temat połączenia z siecią bezprzwodową
+          w polu <code class="code-inline">Access point:</code>, powiniśmy
+          zobaczyć BSSID punktu dostępowego, jeśli w tym polu widnieje napis
+          <code class="code-inline">Not-Associated</code> oznacza to, że
+          nie zostaliśmy przyłączeni do sieci. Jeśli przyłaczenie się
+          powiodło to jedyne co nam pozostało w tym przypadku to pobrać adres
+          IP z DHCP.
+        </p>
+      </li>
+      <li>
+        <p>
+          Następną czynnością do wykonania jest partycjonowanie dysku. Tutaj
+          w zależności od trybu jakiego wymaga nasz komputer do działania, czy
+          jest to BIOS czy UEFI, musimy odpowiednio spartycjonować nasz dysk.
+          W trybie UEFI, należy pamiętać partycji EFI. Nie chcę tutaj narzuć
+          jak należy spartycjonować dysk. Jednak poniżej wstawie schemat,
+          który powinien działać w każdym możliwym przypadku:
+        </p>
+        <table>
+          <tr>
+            <th>Urządzenie</th>
+            <th>Boot</th>
+            <th>Rozmiar</th>
+            <th>Typ partycji</th>
+          </tr>
+          <tr>
+            <td>/dev/sda1</td>
+            <td>*</td>
+            <td>(<em>Rozmiar dysku</em> - 1GB)</td>
+            <td>Linux</td>
+          </tr>
+          <tr>
+            <td>/dev/sda2</td>
+            <td></td>
+            <td>1GB (<em>Reszta</em>)</td>
+            <td>Rozszerzona</td>
+          </tr>
+          <tr>
+            <td>/dev/sda5</td>
+            <td></td>
+            <td>1GB (<em>cały rozmiar partycji rozszerzonej</em>)</td>
+            <td>Linux swap / Solaris</td>
+          </tr>
+        </table>
+        <p>
+          Narzędziem do partycjonowania dostępnym na <em>LiveCD greenOS</em>
+          jest <em>fdisk</em>.
+        </p>
+        <p>
+          Partycjonowanie dla UEFI różni się nieco do partycjonowania dla BIOS
+          poza tymi powyższymi partycjami potrzebna będzie jeszcze jedna
+          partycja.
+        </p>
+        <table>
+          <tr>
+            <th>Urządzenie</th>
+            <th>Boot</th>
+            <th>Rozmiar</th>
+            <th>Typ partycji</th>
+          </tr>
+          <tr>
+            <td>/dev/sda1</td>
+            <td></td>
+            <td><em>nie mniej niż 100MB</em></td>
+            <td>EFI (FAT-12/16/32)</td>
+          </tr>
+          <tr>
+            <td>/dev/sda2</td>
+            <td></td>
+            <td>(<em>pozostała większość</em> - 1GB)</td>
+            <td>Linux</td>
+          </tr>
+          <tr>
+            <td>/dev/sda3</td>
+            <td></td>
+            <td><em>Reszta</em></td>
+            <td>Rozszerzona</td>
+          </tr>
+          <tr>
+            <td>/dev/sda5</td>
+            <td></td>
+            <td><em>cała partycja rozszerzona</em></td>
+            <td>Linux swap / Solaris</td>
+          </tr>
+        </table>
+        <p>
+          Te schematy partycjonowania powinny się sprawdzić. Po zapisaniu
+          zmian na dyskach, należy partycje sformatować na odpowiednie
+          systemy plików. To jest: 
+        </p>
+        <ul>
+          <li>partycja <strong>EFI</strong>:
+<pre class="code-block">
+# mkfs.vfat -F32 /dev/sda1
+</pre>
+          </li>
+          <li>partycje <strong>Linux</strong>-a, np:
+<pre class="code-block">
+# mkfs.ext4 /dev/sda2
+</pre>
+          </li>
+          <li>partycja <strong>swap</strong>:
+<pre class="code-block">
+# mkswap /dev/sda5
+</pre>
+          </li>
+        </ul>
+        <p>
+          Po sformatowaniu partycji, tę przeznaczoną na główny system plików
+          montujemy w katalogu np. <em>/mnt</em> lub <em>/media</em>.
+        </p>
+<pre class="code-block">
+# mount /dev/sda1 /mnt
+</pre>
+        <p>
+          Następnie aktywujemy swap.
+        </p>
+<pre class="code-block">
+# swapon /dev/sda5
+</pre>
+      </li>
+      <li>
+        <p>
+          Jeśli główny system plików został poprawnie zamontowany, a
+          inne katalogi głównego systemu plików, takiej jak np. <em>/home</em>
+          czy <em>/usr</em> będą na innych dyskach, to należy utworzyć teraz
+          te katalogi w miejscu montowania głównego systemu pliku i zamontować
+          te dyski, zeby poźniej nie bawić się w kopiowanie. Po ewewntualnym
+          zamontowaniu pozostałych katalogów, możemy pobrać archwium z
+          <em>rootfs</em>, w tym celu przechodzimy do katalogu montowania 
+          głównego systemu plików następnie wydajemy polecenie:
+        </p>
+<pre class="code-block">
+/mnt# wget http://ftp.morketsmerke.net/greenOS/archiwum_z_systemem.tgz
+</pre>
+        <p>
+          Po ściągnięciu archiwm należy je rozpakować, do tego wystarczy
+          użyć polecnia <em>tar</em> z odpowiednimi przełącznikami.
+        </p>
+<pre class="code-block">
+# tar -xzvf rootfs.tgz
+</pre>
+        <p>
+          Po rozpakowaniu, archiwum należy usunać aby nie zalegało na dysku.
+        </p>
+      </li>
+      <li>
+        <p>
+          Teraz kiedy mamy już pliki dystrybucji, możemy wygenerować plik
+          <em>/etc/fstab</em>, w tym celu przekierujemy wyjście polecenia
+          <em>blkid</em>, do pliku <em>/mnt/etc/fstab</em>.
+        </p>
+<pre class="code-block">
+# cd
+# blkid &gt; /mnt/etc/fstab
+</pre>
+        <p>
+          Niestety samo przkierowania wyjścia <em>blkid</em> nie wygeneruje
+          poprawnego pliku <em>fstab</em>, jednak zaoszczędzi nam przepisywania
+          UUID-ów. Poniżej zamieszcze listing zawierający poprawne wpisy
+          dla poszczególnych partycji.
+        </p>
+<pre class="code-block">
+# Partycja EFI dla instalacji UEFI.
+UUID="..."  /boot/efi vfat  umask=0077  0 1
+
+# Partycje Linuxa
+UUID="..."  $mountPoint ext4  defaults  0 1
+
+# Partycja swap
+UUID="..."  none  swap  sw  0 0
+</pre>
+        <p>
+          <code class="code-inline">$mountPoint</code> - punkt montowania,
+          może być: <em>/</em> jak i <em>/home</em>.
+        </p>
+      </li>
+      <li>
+        <p>
+          Po wygenerowaniu <em>fstab</em>, przyszedł czas na ustawienie nazwy
+          komputera dla instalowanego systemu. Należy zrobić w dwóch miejscach
+          w pliku <em>/mnt/etc/hostname</em> oraz <em>/mnt/etc/hosts</em> pod
+          wpisem adresu <code class="code-inline">127.0.1.1</code>. Nazwa
+          komputera może składać się z małych i dużych liter, cyfr oraz
+          myślinika.
+        </p>
+      </li>
+      <li>
+        <p>
+          Pozostałe czynności należy wykonać już na zmienionym katalogu 
+          głównym. Ta zmiana spowoduje, że będzemy mogli działać 
+          na instalowanym systemie. Ale zanim to jednak nastąpi musimy
+          podmontować w instalowanym systemie kilka katalogów systemowych, aby
+          np. z poziomu zmienionego root-a (katalogu głównego), był
+          widoczny dysk twardy, aby była możliwość zainstalowania programu 
+          rozruchowego (<em>GRUB</em>-a), w tym celu wykorzystamy jedną z 
+          konstrukcji powłoki:
+        </p>
+        <p>
+          <u>Dla instalacji w trybie <strong>BIOS</strong>:</u>
+        </p>
+<pre class="code-block">
+# for i in /dev /dev/pts /proc /run /sys; do mount -B $i /mnt$i; done
+</pre>
+        <p>
+          <u>Dla instalacji w trybie <strong>UEFI</strong>:</u>
+        </p>
+<pre class="code-block">
+# for i in /dev /dev/pts /proc /run /sys /sys/firmware/efi/efivars; do mount -B $i /mnt$i; done
+</pre>
+
+        </p>
+        <p>
+          Po zamontowaniu powyższych katalogów, możemy zmienić katalog główny.
+        </p>
+<pre class="code-block">
+# chroot /mnt /bin/bash
+</pre>
+        <p>
+          W tym momencie powinniśmy przeskoczyć automatycznie do katalogu 
+          głównego, nic innego się nie zmieni, co może nie dezorientujące
+          dlatego warto zmienić sobie znak zachęty (<em>prompt</em>), aby
+          rozróżnić zmieniony katalog główny od katalogu systemu z LiveCD.
+        </p>
+<pre class="code-block">
+# export PS1="(chroot) ${PS1}"
+</pre>
+        <p>
+          Teraz nie pownniśmy mieć wątpliwości, w którym z katalogów głównych 
+          się znajdujemy. Teraz możemy zająć się ustawianiem haseł oraz
+          użytkowników. Na początek zmienimy hasło użytkownika <em>root</em>.
+          Wszystkie polecenia wykonywane na zmienionym katalogu głównym są
+          oznaczone przedrostkiem <code class="code-inline">(chroot)</code>
+        </p>
+<pre class="code-block">
+(chroot)# passwd
+</pre>
+        <p>
+          Następnie utworzymy nowego użytkownika, z którego konta będziemy
+          korzystać podczas pracy na komputerze.
+        </p>
+<pre class="code-block">
+(chroot)# adduser $username
+</pre>
+        <p>
+          <code class="code-inline">$username</code> - nazwa użytownika.
+        </p>
+      </li>
+      <li>
+        <p>
+          Ostatnią czynnością została instalacja programu rozruchowego,
+          istnieje pełna dowolność, jednak w pobranym <em>rootfs</em>,
+          zainstalowany został już <em>GRUB</em> dla <em>i386-pc</em>, więc 
+          przy instalacji
+          w trybie UEFI lub wykorzystaniu przez nas innego bootloadera trzeba
+          będzie zainstalować odpowiedni pakiet. W tym przewodniku skupie się
+          wyłącznie na <em>GRUB</em>. Instalacja <em>GRUB</em> w trybie BIOS 
+          wygląda następująco.
+        </p>
+<pre class="code-block">
+(chroot)# grub-install $disk
+</pre>
+        <p>
+          Gdzie <code class="code-inline">$disk</code> - wystąpienie dysku w
+          katalogu <em>/dev</em>, tj. <em>/dev/sda</em>, <em>/dev/sdb</em> itp.
+          Po zainstalowaniu <em>GRUB</em> na dysku, pozostało jedynie
+          wygenrowanie pliku konfiguracyjnego <em>GRUB</em>-a.
+        </p>
+<pre class="code-block">
+(chroot)# update-grub
+</pre>
+        <p>
+          Powyższe polecenie wygeneruje pliki konfiguracyjne <em>GRUB</em>-a.
+          Po wykonaniu tej czynności instalacja jest zakończona, pozostaje 
+          tylko posprzątać.
+        </p>
+        <p>
+          Instalacje w trybie UEFI, przeprowadza się w nieco inny sposób. Żeby
+          zainstalować <em>GRUB</em>-a w trybie UEFI, będziemy potrzebować
+          odrębnego pakietu niż ten, który jest zainstalowany.
+        </p>
+<pre class="code-block">
+(chroot)# apt update
+(chroot)# apt install grub-efi
+</pre>
+        <p>
+          Po instalacji pakietu musimy zamontować partycje EFI, aby to zrobić
+          należy utworzyć dla niej odpowiedni punkt montowania, będzie nim 
+          katalog <em>/boot/efi</em>:
+        </p>
+<pre class="code-block">
+(chroot)# mkdir /boot/efi
+</pre>
+        <p>
+          Po utworzeniu katalogu montujemy partycję EFI.
+        </p>
+<pre class="code-block">
+(chroot)# mount $efiPartition /boot/efi
+</pre>
+        <p>
+          Gdzie <code class="code-inline">$efiPartition</code> jest partycją
+          EFI w systemie. Po zamontowaniu, możemy przejść do instalacji
+          <em>GRUB</em>-a.
+        </p>
+<pre class="code-block">
+(chroot)# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian
+</pre>
+        <p>
+          Ostatnia czynność jest identyczna dla obu trybów, pozostało
+          wygenerować plik konfiguracyny.
+        </p>
+<pre class="code-block">
+(chroot)# update-grub
+</pre>  
+        <p>
+          Po wygenerowaniu pliku konfiguracyjnego <em>GRUB</em>-a czy to w
+          trybie UEFI czy BIOS, opuszczamy zmieniony katalog główny.
+        </p>
+<pre class="code-block">
+(chroot)# exit
+</pre>
+        <p>
+          Sprzątnie w tym wpadku będzie polegać na kulturalnym odmontowaniu
+          systemów plików. Do tego celu wykorzystamy konstrukcję powłoki, która
+          została już raz użyta podczas instalacji.
+        </p>
+<pre class="code-block">
+# umount -R /mnt
+</pre>
+        <p>
+          Instalacja została zakończona, jedyne co pozostaje to uruchomić
+          ponownie komputer.
+        </p>
+      </li>
+    </ol>
+  </div>
+  <p class="footer">
+         2021; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/greenOS/torwards_the_sun.html b/articles/linux/greenOS/torwards_the_sun.html
new file mode 100644 (file)
index 0000000..49e16d6
--- /dev/null
@@ -0,0 +1,224 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       <body>
+<pre>
+                               ____  _____
+   ____ _________  ___  ____  / __ \/ ___/
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \ 
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ / 
+ \__, /_/   \___/\___/_/ /_/\____//____/  
+/____/                                    
+
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">greenOS GNU/Linux (Torwards the sun)</h1>
+    <p>
+      <strong>greenOS</strong> to lekka, oparta na Debianie dystrybucja 
+      przeznaczona do ogólnego użytku. 
+      Dostarczana jest w postaci archiwum z preinstalowanym i
+      prekonfigurowanym jądrem oraz oprogramowaniem, dzięki czemu może zostać
+      zainstalowana z dowolnej innej dystrybucji, nie koniecznie uruchomionej
+      LiveCD. 
+    </p>
+    <p>
+      Zrzut ekranu przestawiający wersję Desktop:
+      <a target="_blank" href="https://i.ibb.co/BgJSBW0/g-OS-TTS-screenshot.png">
+        <figure>
+          <img src="https://i.ibb.co/cx8GxCS/g-OS-TTS-ss-thunbnail.png">
+          <figcaption>Kilknij obrazek, aby otworzyć w pełnym rozmiarze.</figcaption>
+        </figure>
+      </a> 
+    </p>
+    <p>
+      <strong>Celem dystrybucji</strong> jest dostarczenie użytkownikowi 
+      stabilnego systemu operacyjnego wraz z popularnym oprogramowaniem,
+      którego instalacja na dystrybucjach Linuxa może nie być oczywista. 
+      Dystrybucja jest kompromisem pomiedzy stylem <em>user friendly</em> a 
+      hakerską regułą KISS.
+      Wiele dotyczasowych czynności takich jak np. logowanie (dawniej za pomocą
+      konsoli obecnie za pomocą menedżera wyświetlania) zostało uproszczonych.
+      Tej dystrybucji jednak daleko do bycia typowym desktopem przyjaznym
+      użytkownikowi. Nadal można ją uznać z hakerską.
+    </p>
+    <p>
+      <strike>Dystrybucja została ograniczona do jednej wersji <strong>Desktop</strong>.
+      Patrząc na obecny sprzęt oraz zasoby jakimi operują współczesne komputery
+      ta sama wersja świetnie sprawdzi się na serwerze.</strike> 
+      Dołączone oprogramowanie:
+    </p>
+    <ul>
+      <li><strong>XTerm</strong> - emulator terminala</li>
+      <li><strong>X File Editor</strong> - okienkowy menedżer plików</li>
+      <li><strong>Midnight Commander</strong> - konsolowy menedżer plików</li>
+      <li><strong>Geany</strong> - nieco bardziej rozbudowany edytor tekstu</li>
+      <li><strong>gVim</strong> - legendarny edytor Vim z nakładką graficzną</li>
+      <li><strike><strong>Spotify</strong> - populary serwis streamingowy muzyki</strike></li>
+      <li><strike><strong>Discord</strong> - nowoczesny komunikator internetowy,
+             pozwalający na tworzenie własnych wirtualnych serwerów.</strike></li>
+      <li><strong>Mozilla Firefox</strong> - przeglądarka internetowa</li>
+      <li><strong>qmmp</strong> - odtwarzacz muzyki</li>
+      <li><strong>VLC</strong> - odwarzacz plików video</li>
+      <li><strong>xpdf</strong> - czytnik plików PDF</li>
+      <li><strong>HexChat</strong> - klient protokołu IRC</li>
+      <li><strong>Mozilla Thunderbird</strong> - klient poczty</li> 
+    </ul>
+    <p>
+      greenOS jest również rozporowadzany na zasadzie <strong>LiveCD</strong>. 
+      Wersja LiveCD
+      jest porównywalna z wersją instalowaną na dysku jednak instalowany tam 
+      menedżer okien
+      IceWM pochodzi z repozytorium Debiana a nie z ręcznej kompilacji. 
+      Z racji że to LiveCD, nie ma tutaj Ustawień oraz Gier wykorzystywanych w
+      w zainstalowanej werjsji. Preinstalowane oprogramowanie dalej pozostaje
+      to samo. Poniżej znajduje się link do pobrania obrazu LiveCD: 
+    </p>
+   
+    <ul>
+      <li>Obraz płyty LiveCD: 
+        <a href="https://sourceforge.net/projects/greenos/files/iso/greenOS_1.2_amd64.iso/download">
+          greenOS_1.2_amd64.iso</a>
+      </li>
+    </ul>
+    <p>
+      Dane logowania na obrazach LiveCD (nazwa użytkownika/hasło)
+    </p>
+    <ul>
+      <li>root/toor</li>
+    </ul>
+    <p>
+      Aby nie narzucać niczego oraz zapewnić elastyczność instalacji, greenOS
+      dostarczany jest bez instalatora. Dystrybucje należy zainstalować ręcznie
+      posiłkując się <a href="instalacja_greenos.html">poradnikiem instalacji</a>.
+    </p>
+    <p>
+      Archiwa z dystrybucją w głównym wydaniu (<strong>Main</strong>) znajdują 
+      się poniżej oraz pod adresem:
+      <a href="https://sourceforge.net/projects/greenos/files/rootfs/rootfs_1.2.tgz/download">
+       https://sourceforge.net/projects/greenos/files/rootfs/rootfs_1.2.tgz/download</a>.
+    </p>
+    <p>
+      Inne wydania dystrybucji:
+    </p>
+    <ul>
+      <li><strong>greenOS Ratpoison</strong> - 
+          <a href="https://sourceforge.net/projects/greenos/files/rootfs/rootfs_rp_1.2.tgz/download">
+          https://sourceforge.net/projects/greenos/files/rootfs/rootfs_rp_1.2.tgz/download</a><br />
+          Wersja dystrybucji oparta na manedżerze okien <strong>ratpoison</strong>.
+          Zainstalowane oprogramowanie:
+          <ul>
+            <li><strong>terminator</strong> - emulator terminala,</li>
+            <li><strong>Mozilla Firefox</strong> - przeglądarka internetowa,</li>
+            <li><strong>cmus</strong> - terminalowy odtwarzacz muzyki,</li>
+            <li><strong>ranger, Midnight Commander</strong> - terminalowe 
+              menedżery plików,</li>
+            <li><strong>feh</strong> - prosta przeglądarka plików graficznych,</li>
+            <li><strong>mpv</strong> - otwarzacz plików wideo</li>
+          </ul>
+          Menedżer <em>ratpoison</em> wsparto menedżerem wyświetlania
+          <strong>xdm</strong> oraz menedżerem kompzycji <strong>picom</strong>.
+          Pełna lista pakietów znajduej się pod tym adresem:
+          <a href="https://github.com/xf0r3m/greenOS/blob/main/rp_installed_packages_1.2.txt">
+            https://github.com/xf0r3m/greenOS/blob/main/rp_installed_packages_1.2.txt</a> 
+      </li>
+      <li><strong>greenOS greenServer</strong> -
+          <a href="https://sourceforge.net/projects/greenos/files/rootfs/rootfs_gs_1.2.tgz/download">https://sourceforge.net/projects/greenos/files/rootfs/rootfs_gs_1.2.tgz/download</a><br />
+          Wersja dystrybucji przeznaczona to zastosowań serwerowych. W pełni
+          zgodna z GNU/Linux Debian 10 Buster. Zainstalowane oprogramowanie:
+          <ul>
+            <li><strong>OpenSSH</strong> - serwer dostępu do zdalnej powłoki
+              projektu OpenSSH, będącego podgrupą projektu OpenBSD.</li>
+            <li><strong>Vim</strong> - edytor tekstu</li>
+            <li><strong>ranger</strong> - menedżer plików</li>
+          </ul>
+          Pełna lista pakietów znajduje się pod tym adresem:
+          <a href="https://github.com/xf0r3m/greenOS/blob/main/gs_installed_packages_1.2.txt">
+            https://github.com/xf0r3m/greenOS/blob/main/gs_installed_packages_1.2.txt</a>
+      </li>
+    </ul>
+    <p>
+      Poprzednie wersje dystrybucji znajdują się pod adresem:
+      <a href="https://sourceforge.net/projects/greenos/files/">
+      https://sourceforge.net/projects/greenos/files/</a>.
+    </p>
+    <h2>Specyficzne rzeczy wymagające obsługi:</h2>
+    <ul>
+      <li>Wpisów w menu dokonujemy ręcznie posiłkując się zapisanym już w pliku
+          <em>~/.icewm/menu</em> wpisami lub dokumentacją IceWM dostępną na stronie
+          <a href="https://ice-wm.org/man/">https://ice-wm.org/man/</a>.</li>
+      <li>Zmiany wyświetlania obrazu generowane przez <em>Ustawienia ekranu</em>
+          zapisywane są wewnątrz pliku w katalogu <em>.screenlayout</em>, aby
+          zastosować ustawienia w należy uruchomić plik przed uruchomieniem
+          mendżera okien. <em>Lightdm</em> korzysta z pliku <em>~/.xsession</em>
+          więc w nim należy dodać tę linię przed uruchomienim <em>icewm</em>
+          <em>exec icewm-session</em>:
+<pre class="code-block">
+sh -c ~/.screenlayout/plik_ustawien_arandr.sh &amp;
+</pre>
+          Z <em>plik_ustawien_arandr</em> podajemy swoją nazwą pod którą
+          zostały zapisane zamiany.</li>
+      <li>Jeśli w systemie jest wiele wyjść audio, i nie mamy dźwieku 
+          uruchamiając coś na <em>yt</em>, to system może domyślnie przypisał
+          sobie inną kartę dziwiękową niż byśmy tego chcieli. Za pomocą 
+          poniższego
+          polecenia wyświetlamy dostępnie karty w systemie. Należy zapamiętać
+          pozycję pożądanej karty na wypisanej przez polecenie liście.
+<pre class="code-block">
+$ lspci -knn | grep -iA2 audio
+</pre>
+          Po ustaleniu kolejności domyślnej karty dzwiękowej, należy ustawić
+          ją w pliku <em>/etc/modprobe.d/default.conf</em>, plik 
+          najprawdopodobniej
+          nie istnieje, więc trzeba go będzie utworzyć. W pliku zapisujemy
+          poniższą linię:
+<pre class="code-block">
+options snd_hda_intel index=N
+</pre>
+          Za <code class="code-inline">N</code> wstawiamy pozycję karty na
+          liście z poprzedniego polecenia.</li>
+      <li>W <strong>greenServer</strong> interfejsy sieciowe nie są zarządzane 
+          przez żaden
+          program, dlatego jeśli chcemy uzyskać połączenie sieciowe w tym
+          systemie to najprościej użyć polecenia:
+<pre class="code-block">
+# /sbin/dhclient
+</pre>
+          Możemy również od razu przejść do statycznej konfiguracji sieci lub
+          skonfigurować interfejsy sieciowe podczas instalacji systemu po
+          przełączeniu katalogu głównego.</li>
+    </ul>
+    <p>
+      greenOS rozprowadzany jest <strong>bez gwarancji przydatności</strong>.
+      Autor nie ponosi odpowiedzialności za szkody wyrządzone instalacją lub
+      korzystaniem z greenOS. Miłej zabawy!
+    </p>
+    <p>
+-- Changelog --
+    </p>
+    <p>
+      -- 18.06.2021 - Wydanie nieoficjalnej wersji greenOS oznaczonej nazwą kodową "first".<br />
+      -- 21.08.2021 - Wydanie pierwszej oficjalnej wersji greenOS oznaczonej nazwą kodową "one".<br />
+      -- 24.09.2021 - Zawieszenie wsparcia dla greenOS<br />
+      -- 05.12.2021 - Reaktywacja projektu greenOS<br />
+      -- 30.01.2022 - Wydanie greenOS wersji 1.1, zmiany w obrazie LiveCD
+      znajduje się <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_1.1_livecd.txt">
+      tutaj</a>, natomiast zmiany w archiwum
+      <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_1.1_rootfs.txt">tutaj</a><br />
+      -- 30.01.2022 - Wydanie wersji greenOS Ratpoison<br />
+      -- 27.03.2022 - Wydanie wersji greenOS 1.2, zmiany we wszystkich wersjach
+      dystrybucji znajdują się tutaj: <a href="https://github.com/xf0r3m/greenOS/blob/main/changelog_greenOS_1.2.txt">tutaj</a><br />
+      -- 27.03.2022 - Wydanie wersji greenOS greenServer<br />
+    </p>
+  </div>
+  <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/greenOSAE.html b/articles/linux/greenOSAE.html
new file mode 100644 (file)
index 0000000..b34beef
--- /dev/null
@@ -0,0 +1,419 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+                               ____  _____ ___    ______
+   ____ _________  ___  ____  / __ \/ ___//   |  / ____/
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \/ /| | / __/   
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ / ___ |/ /___   
+ \__, /_/   \___/\___/_/ /_/\____//____/_/  |_/_____/   
+/____/                                                  
+                                    
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">greenOS Arch Edition</h1>
+    <p>
+      greenOS Arch Edition jest to skonfigurowany w odpowieni sposób Arch Linux.
+      Swoim wyglądem ma przypominać greenOS, jednak nie jest to samodzielna
+      dystrybucja. Poniżej znajduje się zrzut ekranu, przestawiający pulpit.
+    </p>
+    <p>
+      <a href="https://i.ibb.co/7tm6MjM/green-OSAE-desktop-screenshot.png">
+        <figure>
+          <img src="https://i.ibb.co/yFcp0cJ/green-OSAE-desktop-screenshot-thumbnail.png" />
+          <figcaption>Kilknij obrazek, aby otworzyć w pełnym rozmiarze</figcaption>
+        </figure>
+      </a>
+    </p>
+    <p>
+      W tej konfiguracji użyto manadżera wyświetlania <em>LightDM</em> oraz
+      środowiska graficznego <em>XFCE4</em>. Zainstalowano takie programy jak
+      Firefox, Thunderbird, VLC, QMMP, Redshift, Snap, ncspot oraz KVM.
+      Poniżej znajduje się lista kroków, którą należy wykonać, aby
+      skonfigurować w ten sposób Arch Linux. Podanej listy można użyć do
+      utworzenia skryptu, lub wprowadzać polecenia ręcznie dokonują niezbędnych
+      dla siebie modyfikacji. Tak przygotowany system, można spakować do
+      archiwum i instalować na róznych maszynach zaoszczędzając wten sposób
+      czas na konfigurowaniu identycznych środowisk jak i reinstalacji
+      stanowiska z tym systemem w tej konfiguracji.
+    </p>
+    <p>
+     <ol>
+      <li>
+        Pobranie najnowszego obrazu Arch Linux-a i uruchomienie z niego maszyny
+        wirtualne bądź fizycznego komputera. Obraz płyty możemy pobrać z linku poniżej
+        <a href="http://ftp.icm.edu.pl/pub/linux/distributions/archlinux/iso">
+          http://ftp.icm.edu.pl/pub/linux/distributions/archlinux/iso
+        </a>.
+      </li>
+      <li>
+        Po uruchomieniu się systemu, uruchamiamy program <em>tmux</em>,
+        dzielimy konsole na dwa poziome okna (w języku polskim brakuje dobrego
+        tłumaczenia słowa angielskiego "pane"). Na jednym zostawiamy prompt
+        (znak zachęty) na drugim uruchamiamy polecenie 
+        <em>installation_guide</em>. Instalujemy system zgodnie z wytycznymi
+        poradnika. Jest jednak kilka czynności jakie należy wykonać w trakcie
+        instalacji.
+        <ul>
+        <li>Pakiety do zainstalowania (przy pobieraniu obrazu): base, linux,
+              linux-firmware,
+              networkmanager, grub, vim, man-db, man-pages, texinfo.</li>
+        <li>Po zamianie głównego katalogu, na ten obrazu należy uruchomić 
+              Network Manager:
+<pre class="code-block">
+[archiso /]# systemctl enable NetworkManager.service
+</pre>
+        </li>
+        <li>
+          W pliku <em>/etc/vconsole.conf</em> poza zmienną <em>LANG</em>
+          zapisujemy zmienną <em>FONT</em> ustawioną na <em>lat2-16</em> oraz
+          zmienną <em>FONTMAP</em> ustawioną na <em>8859-2</em>
+        </li>
+        <li>
+          Tworzymy użytkownika, instalujemy <em>sudo</em>, które ustawiamy w
+          taki sposób aby nie trzeba było wpisywać hasła (ten podpunkt można
+          potraktować wedle własnych preferencji).
+        </li>
+       </ul>
+      </li>
+      <li>
+        Instalujemy środowisko graficzne:
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo pacman -Syu xfce4 xfce4-goodies xorg lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings
+</pre>
+      </li>
+      <li>
+        Zmieniamy kilka ustawień <em>lightdm</em>, po to aby wczytało
+        zainstalowany wcześniej temat, oraz reagowało odpowienio na różnych
+        kartach graficznych.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo vim /etc/lightdm/lightdm.conf
+#w sekcji [LightDM] usuwamy znak komentarz sprzed poniższej opcji i nadajemy
+#jej poniższą wartość.
+logind-check-graphical=true
+#w sekcji [Seat:*] tak jak powyżej
+greeter-session=lightdm-gtk-greeter
+</pre>
+      </li>
+      <li>
+        Tapety. Pobranie tapet greenOS. Ten punkt można sobie odpuścić jeśli,
+        ktoś szuka tylko konfiguracji XFCE dla Arch.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo pacman -Syu wget
+[user@greenOSAE ~]$ wget https://i.ibb.co/5Y8F1mr/greenos-wallpaper.png
+[user@greenOSAE ~]$ wget https://i.ibb.co/2MJvLyH/greenos-lightdm-wallpaper.png
+[user@greenOSAE ~]$ sudo mv greenos-lightdm-wallpaper.png /usr/share/pixmaps
+[user@greenOSAE ~]$ sudo mv greenos-wallpaper /usr/share/backgrounds/xfce
+</pre>
+      </li>
+      <li>
+        Włączenie LightDM. Cały trick tej konfiguracji polega na tym, że 
+        użyjemy mendżera wyświetlania, przez co użytkownik koncowy
+        takiego systemu nie zorientuje się nawet, że środowisko graficzne na
+        tym sprzęcie było instalowane z ręki. Ponieważ po załadowaniu systemu
+        wystartuje LightDM, po zalogowaniu użytkownika wystaruje on pierwsze
+        dostępne środowisko graficzne, o ile użytkownik nie zdefiniował 
+        inaczej, za pomocą pliku <em>.xinitrc</em>.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo systemctl enable lightdm
+</pre>
+      </li>
+      <li>
+        Restart komputera. Po załączeniu <em>LightDM</em>, możemy zrestartować
+        komputer, aby sprawdzić czy nasze środowisko graficzne zostanie
+        poprawnie uruchomione. Jeśli nasze środowisko nie wystatowało, ekranie
+        pojawiąją się różne dziwne rzeczy związane z grafiką. Może to
+        oznaczać, że brakuje odpowiedniego sterownika, niestety źle działający
+        <em>LightDM</em>, psuje również działanie pozostałych konsol. Tak więc
+        aby go wyłączyć musimy uruchomić system z <em>LiveCD Arch Linux</em>
+        podmontować główny system plików, następnie zmienić główny katalog
+        za pomocą polecenia <code class="code-inline">arch-chroot</code>,
+        następnie wyłączyć <em>LightDM</em> poniższym poleceniem:
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo systemctl disable lightdm
+</pre>
+        Następnie uruchomić ręcznie XFCE, jednak będzie to wymagać stworzenia
+        pliku <em>.xinitrc</em>. Po zalogowaniu się na swoje konto.
+<pre class="code-block">
+[user@greenOSAE ~]$ vim .xinitrc
+exec startxfce4
+#zapisujemy zamiany.
+[user@greenOSAE ~]$ startx
+</pre>
+        Po wydaniu ostatniego polecenia środowisko powinno wystartować.
+        W późniejszych podpunktach będzie podane jak zainstalować sterownik
+        Nvidii (jest nieco powszechniejsza w użyciu niż Radeon choć mniej
+        rekomendowana).
+      </li>
+      <li>
+        Konfiguracja XFCE. Po zalogowaniu się usuwamy dolny panel, a górny
+        przenosimy na dół. Następnie zmieniamy ilość przestrzeniu roboczych
+        ilość pozostawiamy wedle uznania. Usuwamy to podstawowe menu i
+        zastępujemy je <em>Menu Whisker</em>. Konfigurując menu, w zakładce
+        <em>Przycisk panelu</em> pole <em>Wyświetlanie</em> ustawiamy na
+        <em>Ikona i etykieta</em> Ustawiamy następnie swoją ikonę i etykietę, jeśli jednak ma być to greenOS, to należy pobrać
+        z <a href="https://i.ibb.co/fS0sHyD/leaf.png">
+          https://i.ibb.co/fS0sHyD/leaf.png</a> ikonę oraz
+        ustawić etykietę na <em>greenOS</em>. Z panelu usuwamy wskaźnik baterii
+        jeśli będziemy używać systemu na laptopie, to możemy go zostawić.
+        Modyfikujemy przyciski sesji, z polu <em>Wygląd</em> ustawiamy
+        <em>Przyciski sesji</em>, z przycisków odznaczamy wszystkie, poza
+        <em>Zablokowaniem ekranu</em> znajdującym się pod nim 
+        <em>sepraratorem</em> oraz <em>Wyłączeniem</em>. Za pomocą apletu
+        <em>Wygląd</em> wybranym z menu (kategoria <em>Ustawienia</em>), 
+        zmieniamy motyw systemu na <em>Adwaita (ciemny)</em>. Na koniec 
+        zmieniamy tapetę, klikając PPM na pulpit i wybierając
+        <em>Ustawienia pulpitu</em> następnie jedną z tapet.<br />
+        <u>Problem z tapetą użytkownika:</u><br />
+        Jeśli zamierzamy użyć tego systemu jako archiwum, to warto mieć na
+        uwadze, że XFCE mimo ustawionej tapety, która za każdym wyłączeniem/
+        włączeniem komputera jest taka sam to po ponowym zainstalowaniu systemu
+        z archiwum tapeta jest inna mimo tego samego konta. Przyczyn problemu
+        nieznam, chociaż mam jego rozwiązanie XFCE (jeden z jego programów)
+        cały czas ustawia tę samą tapetę, z racji tego należy ją przenieść, ale
+        tak żeby nie zginęła. Na przykład do <em>/usr/share/pixmaps</em>.
+<pre class="code-block">
+[user@greenOSAE ~]$ mv /usr/share/backgrounds/xfce/xfce-verticals.png /usr/share/pixmaps
+</pre>
+        Następnie tworzymy dowiązanie symboliczne do naszej tapety o nazwie
+        wskazującej na tą niedawno przeniesioną.
+<pre class="code-block">
+[user@greenOSAE ~]$ ln -s /usr/share/backgrounds/xfce/greenos_wallpaper.png /usr/share/backgrounds/xfce/xfce-verticals.png
+</pre>
+        Teraz tapeta powinna być cały czas taka sama. 
+      </li>
+      <li>
+        Polskie znaki w terminalu. Jeśli uruchomimy terminal to możemy
+        zauważyć, że nie można wpisać żadnego z polskich znaków. Należy to
+        naprawić, wymaga to jednego polecenia i zrestartowania komputera.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo localectl set-x11-keymap pl
+</pre>
+        Restartujemy komputer, lub zamykamy i uruchamiamy ponownie serwer
+        <em>X window</em>.
+      </li>
+      <li>
+        Ustawienia terminala. W preferencjach emulatora terminala w zakładce
+        <em>Kolory</em> wybieramy profil <em>Zielone na czarnym</em> oraz
+        kolor aktywnych kart na jaskrawożółty, w zakładce <em>Wygląd</em>
+        zmieniamy czcionkę na <em>Source Code Pro Regular</em> oraz ustawiamy
+        przezroczyste tło na poziomie 0.85.
+      </li>
+      <li>
+        Zmiana kolorystki okna logowania, tapety okna logowania oraz domyślnego
+        obrazu użytkowników. W tym celu uruchamiamy program
+        <em>lightdm-gtk-greeter-settings</em> i ustawiamy motyw na
+        <em>Adwaita-dark</em> i ikony na <em>Adwaita</em>. Następnie ustawiamy
+        tapetę. Z folderu <em>/usr/share/pixmaps</em> wybieramy
+        <em>greenos_lightdm_wallpaper.png</em>. Kolejną rzeczą do ustawienia
+        jest domyślny obraz użytkowników, z pod menu wybieramy plik następnie
+        wybieramy logo Arch Linux <em>/usr/share/pixmaps/archlinix-logo.png</em>
+      </li>
+      <li>
+        Instalacja oprogramowania użytkowego.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo pacman -Syu firefox thunderbird vlc qmmp pulseaudio pulseaudio-alsa pavucontrol
+</pre>
+      </li>
+      <li>
+        Instalacja sterowników własnościowych od Nvidii.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo pacman -Syu nvidia
+[user@greenOSAE ~]$ sudo mkinitcpio -P
+</pre>
+      </li>
+      <li>
+        Instalacja oprogramowania Redshift. Program ten pomagachronić wzrok
+        podczas wieczornej pracy przy komputerze usuwając barwę niebieską - 
+        ocieplając wyświetlane kolory. Ze względów geograficznych nie wszędzie
+        na świecie jest noc, dlatego też ten program do swojego działania
+        połączenia z GPS lub ręcznego podania lokalizacji. Tak też zrobimy w
+        naszym przypadku. Podamy ręcznie współrzędne geograficzne. Najpierw 
+        jednak pobierzemy domyślną konfigurację Redshift i zapiszemy ją na
+        ścieżce: <em>~/.config/redshift/redshift.conf</em>, konfigurację można
+        pobrać z linku poniżej:
+        <a href="https://raw.githubusercontent.com/jonls/redshift/master/redshift.conf.sample">https://raw.githubusercontent.com/jonls/redshift/redshift/master/redshift.conf.sample</a>
+        W pliku w sekcji <em>[manual]</em> podajemy współrzędne geograficzne,
+        które możemy pobrać z tego odnośnika: <a href="https://location.services.mozilla.com/v1/geolocate?key=geoclue">https://location.services.mozilla.com/v1/geolocate?key=geoclue</a>.
+        Kolejną rzeczą jak została do ustawienia jeśli chodzi
+        o Redshift to jest to autostart. W ustawieniach przechozimy do 
+        <em>Sesja i uruchamianie</em>, w zakładce <em>Uruchamiane programy</em>
+        kilkamy <em>+</em> w oknie <em>Dodawanie programu</em>,w polu
+        <em>Nazwa</em> wpisujemy <em>Redshift</em>, opis można pominąć, w polu
+        <em>Polecenie</em> wpisujemy <em>/usr/bin/redshift</em>. Po ponownym
+        zalogowaniu Redshift powinien zostać uruchomiony.
+      </li>
+      <li><strike>
+        Instalacja snap oraz ncspot. <em>Snap</em> jest rodzajem mendżera 
+        pakietów
+        dającym m.in. możliwość instalowania tego samego
+        oprogramowania na różnych dystrybucjach, z kolei
+        <em>ncspot</em> jest lekką wersją klienta serwisu
+        <em>Spotify</em>. Na Arch Linux <em>Snap</em> nie jest
+        od tak dostępny, i trzeba go zainstalować z pakietów
+        AUR. Pakiety AUR są paczkami zawierającymi kod źródłowy przygotowany do
+        kompilacji pod Arch Linux, skompilowany kod może zostać zamieniony na 
+        pakiet mendżera <em>Pacman</em> i zostać przez niego zinstalowany jak
+        każdy inny pakiet pobrany z repozytorium. Na początek ppotrzebujemy
+        oprogramowania do pobrania pakietu AUR oraz jego kompilacji:
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo pacman -Syu git base-devel
+</pre>
+        Następną czynnością jest skolonowanie repozytorium ze snapd i
+przjeście do katalogu zawierającego pobrane pliki.
+<pre class="code-block">
+[user@greenOSAE ~]$ git clone https://aur.archlinux.org/snapd.git
+[user@greenOSAE ~]$ cd snapd
+</pre>
+        Teraz przechodzimy do kompilacji z pomocą polecenia
+        <code class="code-inline">makepkg</code>. Opcja <em>-s</em> nakazuje
+        zainstalować wszystkie zależności potrzebne do zbudowania pakietu a 
+        opcja <em>-i</em> zapyta o instalacje pakietu zaraz po jego zbudowaniu.
+        Po zostając w katalogu <em>snapd</em> wywołujemy poniższe polecenie:
+<pre class="code-block">
+[user@greenOSAE ~]$ makepkg -si
+</pre> 
+        Po zbudowaniu musimy włączyć i uruchomić socket dla snapd oraz utowrzyć 
+        dowiązanie symboliczne.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo systemctl enable --now snapd.socket
+[user@greenOSAE ~]$ sudo ln -s /var/lib/snapd/snap /snap
+</pre>
+        Teraz należy zrestartować maszynę, po uruchomieniu wydajemy następujące
+        polecenie.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo snap install ncspot
+</pre>
+        Może się zdarzyć, że zostanie wyświetlony błąd 
+        <em>Too early for operations...</em>, wtedy należy wydać poniższe
+        polecenie i spróbować ponownie wydać polecenie instalacji.
+<pre class="code-block">
+[user@greenOSAE ~]$ sudo snap refresh
+</pre></strike>
+      </li>
+      <li>
+        Ostatnią czynnościa do wykonania, pozostaje
+        zainstalować jakąś metodę wirtualizacji. Oracle VirtualBox nie jest
+        dobry rozwiązaniem jeśli chodzi o systemy Linux ze
+        względu na to iż bywa niestabilny, szczególnie te wersje od 6.0.
+        Do wyboru pozostaje KVM oraz XEN. Ja przesiadłem się z VirtualBox-a na 
+        właśnie KVM i to też zainstalujemy. Instalacje rozpoczynamy od
+        zainstalowania paczek z repozytorium.
+<pre class="code-block">
+[user@greenOSAE: ~]$ sudo pacman -Syu virt-manager qemu vde2 ebtables dnsmasq bridge-utils openbsd-netcat
+</pre>
+        Następnie włączamy usługę do autostartu i uruchamiamy ją.
+<pre class="code-block">
+[user@greenOSAE: ~]$ sudo systemctl enable libvirtd.service
+[user@greenOSAE: ~]$ sudo systemctl start libvirtd.service
+</pre>
+        Kolejną rzeczą jaką należy wykonać jest odblokowanie opcji w pliku
+        <em>/etc/libvirt/libvirtd.conf</em> musimy od szukać
+i odblokować <code class="code-inline">unix_sock_group = "libvirt"</code> oraz
+        <code class="code-inline">unix_sock_rw_perms = "0770"</code>.
+        Zapisujemy zmiany w pliku. Abyśmy mogli korzystać z
+maszyn wirtualnych jako zwykły użytkownik musimy dodać użytkownika do grupy
+        oraz ją utworzyć.
+<pre class="code-block">
+[user@greenOSAE: ~]$ sudo usermod -a -G libvirt user
+[user@greenOSAE: ~]$ newgrp libvirt
+</pre>
+        Na koniec należy zrestartować usługę.
+<pre class="code-block">
+[user@greenOSAE: ~]$ sudo systemctl restart libvirtd.service
+</pre>
+      </li>
+     </ol> 
+    </p>
+    <p>
+      Podsumowując Arch Linux jest dystrybucją na pewno skierowaną do bardziej
+      zaawansowanych użytkowników. W zamian za trudy konfiguracji mamy dostęp
+      najnowszego jądra oraz najnowszych wersji programów.
+      Dzięki staraniom deweloperów Arch-a możemy zainstalować
+      Linuxa np. na Chrombookach i wykorzytać w pełni potencjał
+      takiej maszyny. Gdzie np. na dystrybucjach pochodnych
+      Debiana jak i na samym Debianie na części (jak nie na większości) 
+      Chromebooków nie będzie działać dźwięk. Proszę nie brać tej oceny jako
+      atak wymierzony w kierunku Debiana, ponieważ nadal nie 
+      znam bardziej stablinej dystrybucji niż Debian. Wciąż
+      ze wsparciem dla starego sprzętu, czego brakuje w Arch-u czy CentOS-ie.
+    </p>
+    <p>
+      <u>Źródła:</u><br />
+      <ol>
+        <li>
+          <u>Problemy z grafiką LightDM</u>
+          <a href="https://wiki.archlinux.org/title/LightDM#Autologin_does_not_work">https://wiki.archlinux.org/title/LightDM#Autologin_does_not_work</a>
+        </li>
+        <li>
+          <u>Ustawienie tematu dla LightDM</u>
+          <a href="https://wiki.archlinux.org/title/LightDM#Greeter">https://wiki.archlinux.org/title/LightDM#Greeter</a>
+        </li>
+        <li>
+          <u>Instalacja sterowników własnościowych Nvidii</u>
+          <a href="https://wiki.archlinux.org/title/Nvidia#Installation">https://wiki.archlinux.org/title/Nvidia#Installation</a>
+        </li>
+        <li>
+          <u>O Redshift:</u>
+          <a href="https://wiki.archlinux.org/title/Redshift#Configuration">https://wiki.archlinux.org/title/Redshift#Configuration</a>
+        </li>
+        <li>
+          <u>Dodanie programu do autostartu:</u>
+          <a href="https://wiki.archlinux.org/title/XFCE#Autostart">https://wiki.archlinux.org/title/XFCE#Autostart</a>
+        </li>
+        <li><strike>
+          <u>Instalacja Snap na Arch Linux:</u>
+          <a href="https://snapcraft.io/docs/installing-snap-on-arch-linux">https://snapcraft.io/docs/installing-snap-on-arch-linux</a></strike>
+        </li>
+        <li>
+          <u>Instalacja KVM na Arch Linux:</u>
+          <a href="https://linuxhint.com/install_configure_kvm_archlinux">https://linuxhint.com/install_configure_kvm_archlinux</a>
+        </li>
+      </ol>
+    </p>
+    <p>
+      Jeśli komuś nie chce się wykonywać powyższych czynności, to może pobrać
+      gotowe archiwum znajdujące się pod poniższym odnośnikiem.
+    </p>
+    <p>
+      <a href="https://sourceforge.net/projects/greenosae/files/rootfs/greenOSAE-2.0.2.tgz/download">https://sourceforge.net/projects/greenosae/files/rootfs/greenOSAE-2.0.2.tgz/download</a>
+    </p>
+    <p>
+      Procedura instalacji jest zgodna z greenOS, jedyną różnicą jest tworzenie
+      pliku konfiguracyjnego GRUB-a, do tego wykorzystujemy to polecenie:
+    </p>
+<pre class="code-block">
+# grub-mkconfig -o /boot/grub/grub.cfg
+</pre>
+    <p>
+      Zmiany, których dokonano na oryginalnym archiwum, aby można było je
+      upublicznić znajdują się <a href="https://github.com/xf0r3m/greenOSAE/blob/main/changelog_greenOSAE_2.0.1.txt">tutaj</a>. Z kolei lista zainstalowanych pakietów <a href="https://github.com/xf0r3m/greenOSAE/blob/main/greenOSAE_installed_packages.txt">tutaj</a>.
+    </p>
+    <p>
+      Changelog najnowszej wersji znajduje się <a href="https://github.com/xf0r3m/greenOSAE/blob/main/changelog_greenOSAE_2.0.2.txt">tutaj</a>.
+    </p>
+    <p>
+      -- Changelog --
+    </p>
+    <p>
+      -- 11.02.2022 - Aktualizacja oryginalnego archiwum i upublicznienie go<br />
+      -- 11.02.2022 - Nowa wersja archiwum, zamiany w changelog-u powyżej<br />
+    </p>
+    <p>
+    ~xf0r3m
+    </p>
+  </div>
+  <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/greenOSTe.html b/articles/linux/greenOSTe.html
new file mode 100644 (file)
index 0000000..0df638a
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+                               ____  ___________   
+   ____ _________  ___  ____  / __ \/ ___/_  __/__ 
+  / __ `/ ___/ _ \/ _ \/ __ \/ / / /\__ \ / / / _ \
+ / /_/ / /  /  __/  __/ / / / /_/ /___/ // / /  __/
+ \__, /_/   \___/\___/_/ /_/\____//____//_/  \___/ 
+/____/
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">greenOS Trisquel edition GNU/Linux (Torwards the sun)</h1>
+    <p>
+       <strong>greenOSTe</strong> jest to wersja <strong>Trisquel GNU/Linux</strong>
+        a nie samodzielna dystrybucja. Można powiedzieć że jest <em>flavour</em>
+        tej dystrybucji. <em>Trisquel</em> podobnie jak opisywana już na tej
+        stronie <em>Parabola</em> jest w pełni wolną dystrybucją. Oznaczna to 
+        mniej więcej tyle, że dystrybucja nie posiada oficjalnie żadnego
+        zamkniętego oprogramowania w swoich repozytoriach, a jądro pozbawione
+        jest blobów binarnych. Dystrybucje tego typu mogą skorzystać z projektu
+        <strong>Linux-libre</strong> dostarczającego takie jądro (patrz:
+        <em>Parabola GNU/Linux-libre</em>) lub samodzielnie kompilować jądro
+        pozbawione modułów dostarczanych w postaci binarnych blobów
+        (<em>Trisquel GNU/Linux</em>, <em>PureOS GNU/Linux</em>).
+    </p>
+    <a target="_blank" href="https://i.ibb.co/wwTQ6Cw/green-OSTe-ss.png">
+      <figure>
+        <img src="https://i.ibb.co/mcRgmf0/green-OSTe-ss-thumbnail.png" alt="green-OSTe-ss-thumbnail" border="0">
+        <figcaption>Kliknij obrazek, aby otworzyć w pełnym rozmiarze.</figcaption>
+      </figure>
+    </a>
+    <p>
+        Celem tej wersji jest wykorzystanie rozwiązań znanych z <em>greenOS</em>
+        w zastosowaniach gdzie niechcemy wykorzystać klasycznego jądra oraz
+        zamkniętego oprogramowania. Zestaw dostarczanego oprogramowania został 
+        uszczuplony o 
+        całe zamknięte oprogramowanie wykorzystywane w greenOS oraz o
+        menadżer wyświetlania <em>lightdm</em>. Środowisko graficzne
+        uruchamiane jest na życzenie użytkownika za pomocą polecenia
+    </p>
+<pre class="code-block">
+$ startx
+</pre>
+    <p>
+        Lista programów dostarczanych wraz z <em>greenOSTe</em>:
+    </p>
+    <ul>
+      <li><strong>icewm</strong> - Menadżer okien,</li>
+      <li><strong>Mozilla Firefox 91.4.1esr</strong> - 
+          Przeglądarka internetowa</li>
+      <li><strong>X-File Editor</strong> - Menadżer plików,</li>
+      <li><strong>Midnight Commander</strong> - Menadżer plików (tekstowy),</li>
+      <li><strong>Geany</strong> - Proste IDE, bardziej zaawansowany notatnik,</li>
+      <li><strong>gVim</strong> - Legendarny edytor Vim, wraz z nakładką
+          graficzną <em>gtk3</em>,</li>
+      <li><strong>qmmp</strong> - Odtwarzacz plików audio,</li>
+      <li><strong>mpv</strong> - Odtwarzacz plików multimedialnych, uruchamiany
+          z terminala.</li>
+      <li><strong>HexChat</strong> - klient sieci IRC,</li>
+      <li><strong>mutt</strong> - Klient pocztowy (tekstowy).</li>
+    </ul>
+    <p>
+      Podobnie jak w przypadku <em>greenOS</em>, <em>greenOSTe</em> jest
+      dostępny w postaci LiveCD, link do obrazu znajduje się poniżej:
+    </p>
+    <ul>
+      <li><a href="https://sourceforge.net/projects/greenoste/files/iso/greenOSTe_9.0.1_amd64.iso/download">
+          greenOSTe_9.0.1_amd64.iso</a></li>
+    </ul>
+    <p>
+      Instalacja wygląda identycznie jak w przypadku <em>greenOS</em>, jedyną
+      różnicą jest pobierana paczka z głównym system plików, poniżej znajduje
+      się do niej link:
+    </p>
+    <ul>
+      <li><a href="https://sourceforge.net/projects/greenoste/files/rootfs/rootfs_9.0.1.tgz/download">
+          rootfs_9.0.1.tgz</a></li>
+    </ul>
+    <p>
+      Z racji wydania aktualizacji poprzednie wydania greenOSTe dostępne są
+      pod adresem: <a href="https://sourceforge.net/projects/greenoste/files">https://sourceforge.net/projects/greenoste/files</a>.
+    </p>
+    <p>
+      greenOSTe rozprowadzany jest <strong>bez gwarancji przydatności</strong>.
+      Autor nie ponosi odpowiedzialności za szkody wyrządzone instalacją lub
+      korzystaniem z greenOSTe. Miłej zabawy!
+    </p>
+    <p>
+-- Changelog --
+    </p>
+    <p>
+      -- 30.12.2021 - Wydanie pierwszej wersji greenOS Trisquel edition
+    </p>
+  </div>
+  <p class="footer">
+         2022; COPYLEFT; ALL RIGHTS REVERSED;
+  </p>
+
+</body>
+</html>
diff --git a/articles/linux/index.html b/articles/linux/index.html
new file mode 100755 (executable)
index 0000000..997a04e
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <ul class="special_list">
+      <li><a href="Alpine_Linux_jako_bramka_sieciowa.html">
+        Alpine Linux jako bramka sieciowa</a></li>
+      <li><a href="generowanie_certyfikatów_self-signed_OpenSSL.html">
+        Generowanie certyfikatów self-signed OpenSSL</a></li>
+      <li><a href="generowanie_certyfikatu_Let's_Encrypt_typu_wildcard.html">Generowanie certyfikatu Let's Encrypt typu wildcard</a></li>
+      <li><a href="instalacja_aktualizacja_pakietów_na_Arch_Linux.html">Instalacja i aktualizacja pakietów na Arch Linux</a></li>
+      <li><a href="instalacja_Alpine_Linux.html">Instalacja Alpine Linux</a></li>
+      <li><a href="instalacja_kontenerów_LXD.html">Instalacja kontenerów LXD</a></li>
+      <li><a href="instalacja_sandstorm.io.html">Instalacja Sandstorm.io</a></li>
+      <li><a href="instalacja_Spotify_oraz_atom.io_za_pomocą_Snap.html">Instalacja Spotify oraz atom.io za pomocą Snap</a></li>
+      <li><a href="instalacja_systemu_z_własnego_obrazu_LiveCD_z_Debianem.html">Instalacja systemu z własnego obrazu LiveCD</a></li>
+      <li><a href="NFS_-_udostepnianie_i_montowanie_udziałów.html">NFS - udostępnienianie i montowanie udziałów</a></li>
+      <li><a href="przekierowanie_portów_do_kontenerów_LXD.html">Przekierowanie portów do kontenerów LXD</a></li>
+      <li><a href="samba_AD_DC_-_Instalacja.html">Samba AD DC - Instalacja</a></li>
+      <li><a href="samba_AD_DC_-_NTP.html">Samba AD DC - NTP</a></li>
+      <li><a href="tworzenie_logicznych_woluminów_LVM.html">Tworzenie Logicznych woluminów LVM.</a></li>
+      <li><a href="tworzenie_RAID_programowych_w_systemach_GNU_Linux.html">Tworzenie RAID programowych na systemach GNU Linux</a></li>
+      <li><a href="własne_LiveCD_z_Debianem.html">Własne LiveCD z Debianem</a></li>
+      <li><a href="Parabola_GNU_Linux-libre.html">Parabola GNU/Linux-libre</a></li>
+      <li><a href="szyfrowany_rootfs_na_greenOS.html">Szyfrowany rootfs na greenOS</a></li>
+      <li><a href="szyfrowany_rootfs_na_greenOSTe.html">Szyfrowany rootfs na greenOSTe</a></li>
+      <li><a href="greenOS/index.html">greenOS</a></li>
+      <li><a href="greenOSAE.html">greenOS Arch Edition</a></li>
+      <li><a href="greenOSTe.html">greenOS Trisquel Edition</a></li>
+      <li><a href="OTP/index.html">Old Terminal Project</a></li>
+      <li><a href="uruchomienie_skryptu_podczas_ładowania_systemu_-_jednostka_systemd.html">Uruchomienie skryptu podczas ładowania systemu - jednostka systemd.html</a></li>
+      <li><a href="instalacja_sterowników_Nvidii_na_Debian_11.html">Instalacja własnościowego sterownika graficznego Nvidii na Debian 11</a></li>
+               </ul>
+       </div>
+
+       <p class="footer">
+               2022; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/linux/instalacja_Alpine_Linux.html b/articles/linux/instalacja_Alpine_Linux.html
new file mode 100644 (file)
index 0000000..44486ed
--- /dev/null
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+
+               <h1 class="title">Instalacja Alpine Linux</h1>
+               <p>
+               <strong>Alpine Linux</strong> jest jedną z moich ulubionych dystrybucji. Lekki i bezpieczny system, który po niewielkiej konfiguracji może stać się systemem codziennego użytku. Dystrybcja dostaczona przez norweskich deweloperów znajduje zastosowanie na wielu platformach w tym <em>Raspberry Pi</em>. Cechami charakterystycznmi tej dystrybucji jest <strong>OpenRC</strong> jako program init, BusyBox oraz możliwość działania z pamięci RAM. Warto również wspomnieć że twórcy systemu wspierają również aplikację, która pozwala administrować systemem z poziomu przeglądarki WWW.
+               </p>
+               <ol>
+                       <li><strong>Start</strong><br />
+                               <p>
+                                       <strong>Po załadowaniu płyty, system wystartuje na zasadzie LiveCD. Poprosi nas o zalogowanie się. Logujemy się na konto użytkownika root bez hasła.</strong> Jeśli chcemu coś sprawdzić przed instalacją to jest najlepszy moment. Kiedy będziemy gotowi na instalację systemu wydajemy poniższe polecenie:
+                               </p>
+<pre class="code-block">
+# setup-alpine
+</pre>
+                       </li>
+                       <li><strong>Układ klawiatury</strong><br />
+                               <p>
+                                       Pierwszą rzeczą jaką musimy ustawić jest układ klawiatury. Na początku wybieramy układ na podstawie kraju, a następnie układy stostowane na obszarze danego kraju. Przeważnie naszym wyborem jest <code class="code-inline">pl</code>, <code class="code-inline">pl</code>.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/44Dp2R4/ia-kbd-layo1.png" alt="Instalcja Alpine Layout klawiatury 1" />
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/ypjYPd1/ia-kbd-layo2.png" alt="Instalacja Alpine Layout klawiatury 2" />
+                               </p>
+                       </li>
+                       <li><strong>Nazwa komputera</strong><br />
+                               <p>
+                                       Po wybraniu układu klawiatury instalator zapyta nas o nazwę dla naszego systemu, tutaj możemy wpisać co nam się podoba. Zazwyczaj możemy używać małych liter, cyfr oraz myślnika. Ja podałem nazwę dystrybucji w raz z wersją systemu tak zazwyczaj robię na maszynach wirtualnych, ale jeśli chodzi o fizyczne maszyny to wpisuje zazwyczaj model komputera.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/6y7Rbp9/ia-hostname.png" alt="Instalacja Alpine nazwa komputera" />
+                               </p>
+                       </li>
+                       <li><strong>Inicjalizcja interfejsów</strong><br />
+                               <p>
+                                       Teraz przyszedł czas na określnie konfiguracji sieciowej naszego Alpine-a. Z poziomu instalatora mamy duże możliwośći konfiguracji interfejsów, aby przygotować nasz system do pracy na urządzeniach sieciowych. Póki co przygotujemy system ogólnego użytku. Więc, na pocztku wybieramy interfejs do do incjalizacji.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/m5gjdgq/ia-initinterface1.png" alt="Instalacja Alpine incjalizacja interfejsów1" />
+                               </p>
+                               <p>
+                                       Następnie zostaniemy zapytani o adres IP dla tego interfejsu. Tutaj warto na chwile zatrzymać się i pomyśleć na przeznaczeniem naszego systemu. Jeśli jest to maszyna wirtualna np. tylko do tego żeby sobie uruchomić ten system to może być dhcp, jeśli do czegoś innego np. do rzeczy dewelperskich to warto zastosować jakiś stały adres, poza pulą naszego sieciowego serwera DHCP. Dla bramki, adres zależy od interfejsu jaki inicjujemy. Sposób konfiguracji interfejsu zewnetrznego jest podyktowany przez ISP, a adresy wenętrzne zawsze maja stały adres pierwszego komputera w tej sieci. W moim przypadku jest środowisko emulacjyne QEMU (bez kvm), więc intefejs ustawiam na <code class="code-inline">dhcp</code>.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/nPprf8w/ia-initinterface2.png" alt="Instalacja Alpine inicjalizacja interfejsów2" />
+                               </p>
+                               <p>
+                                       Po konfiguracji interfejsu, jeśli w systemie znajdują się jeszcze jakieś nie skonfigurowane interfejsy sieciowe to instalator zapyta czy chcemy je skonfigurować. Tutaj możemy ustawić stałe adresy dla intefejsów wewnętrznych bramki.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/rMXVSjs/ia-initinterface3.png" alt="Instalacja Alpine inicjalizacja interfejsów3" />
+                               </p>
+                       </li>
+                       <li><strong>Hasło dla użytkownika <em>root</em></strong><br />
+                               <p>
+                                       Następnym krokiem jest ustawienie hasła użytkownika <em>root</em> w systemie. W zależności od zastosowania systemu należy wybrać odpowiednie hasło. Dla systemów, które są podłączone do sieci lub są częścia systemów produkcyjnych to dla nich trzeba ustawić jakieś bezpieczne hasło, z kolei dla maszyny testowej możemy ustawić jakieś słabe hasło byle by go nie zgubić. Jeśli je zapomnimy to stracimy czas na usunięcie go lub reinstalacje systemu. Ja sobie ustawie hasło: toor. Hasło dość łatwe do zapamiętania, stosowanie tego hasła zapoczątkowa dystrybucja BackTrack, a poźniej Kali Linux.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/PhnSv5J/ia-rootpassword.png" alt="Instalacja Alpine hasło dla root-a" />
+                               </p>
+                       </li>
+                       <li><strong>Strefa czasowa</strong><br />
+                               <p>
+                                       System aby mógł poprawnie wyświetlać informacje nt. daty oraz czasu potrzebuje strefy czasowej jaka nas obejmuje. Jeśli nie znamy naszej rodzimej strefy czasowej (<code class="code-inline">Europe/Warsaw</code>) możemy wybrać '<code class="code-inline">?</code>', przez co zostanie nam wyświetlona lista.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/G0WpSKJ/ia-timezone.png" alt="Instalacja Alpine lista stref czasowych" />
+                               </p>
+                               <p>
+                                       Pod nazwami kontynetów kryją się stolice lub wieksze miasta państw tych kontynentów. Dla Polski możemy wybrać albo <code class="code-inline">Poland</code> albo <code class="code-inline">Europe/Warsaw</code>.
+                               </p>
+                       </li>
+                       <li><strong>Proxy dla HTTP/FTP</strong><br />
+                               <p>
+                                       Po ustaleniu strefy czasowej instalator zapyta o adres proxy dla ruchu protoków HTTP oraz FTP, jeśli nasz ruch nie przechodzi przez proxy to pozostawiamy wartość domyślną ustawioną na <code class="code-inline">none</code>, w przeciwnym wypadku podajemy adres naszego pośrednika.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/RTs68p1/ia-httpftpproxy.png" alt="Instalacja Alpine, adres proxy http_ftp" />
+                               </p>
+                       </li>
+                       <li><strong>Instalacja klienta NTP</strong><br />
+                               <p>
+                               <a href="#ntp">Patrz przedostatni pragraf.</a>
+                               </p>
+                       </li>
+                       <li><strong>Wybór serwera lustrzanego</strong><br />
+                               <p>
+                                       Po podaniu informacji nt. proxy, zostanie wyświetlona nam lista serwerów lustrzanych do wyboru źródła repozytorium. Możemy wybrać 1 z 55 podając numer z listy, wpisać własny adres URL, co prawdopodobnie daje możliwość użycia lokalnego mirrora, wpisać literę 'r' co spowoduje ustawienie losowego serwera, wpisać literę 'f', przez co zostanie wybrany najszybszy serwer lub wpisać literę 'e', przez co będziemy mogi edytować listę repozytoriów. Zawsze tutaj wybieram serwer nr 37, jest chyba najszybszym mirrorem w Polsce.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/mCmZX6S/ia-selectmirror.png" alt="Instalacja Alpine, wybór serwera lustrzanego" />
+                               </p>
+                       </li>
+                       <li><strong>Ustalenie daemona SSH</strong><br />
+                               <p>
+                                       Alpine Linux podczas instalacji domyślnie daje możliwość zainstalowania serwera SSH, na naszej maszynie. Do wyboru mamy ogólnodostępne serwery SSH: dropbear oraz openssh. Dla systemów wbudowanych gdzie liczy się każdy KB RAM-u, warto wybrać dropbear. Nie ma on co prawda dobrego wsparcia SFTP, ale pełne dla SCP, więc można jakoś sobie poradzić z transferem plików, jest on jednak mniej zasobożerny niż OpenSSH. Poza systemami wbudowanymi to raczej lepiej zainstalować klasyczne OpenSSH.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/jz902VJ/ia-sshdaemon.png" alt="Instalacja Alpine, wybór daemon ssh" />
+                               </p>
+                       </li>
+                       <li><strong>Instalacja właściwa systemu</strong><br />
+                               <p>
+                                       Przebieg instalacji został w Alpine Linux, bardzo uproszczony na samym początku zostaje nam wyświetlona lista dysków.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/PNR5XG7/ia-listdisk.png" alt="Instalacja Alpine, lista dysków" />
+                               </p>
+                               <p>
+                                       Następnie instalator prosi nas o wskazanie dysku do instalacji. Po zatwierdzeniu dysku, wybieramy sposób instalacji systemu. Do wyboru mamy dwie opcje, <code class="code-inline">sys</code> lub <code class="code-inline">data</code>. Pierwszy z nich to sposób klasyczny system jest instalowany na dysku i korzysta z niego jak każdy inny GNU/Linux. Opcją numer dwa jest załadowanie systemu do pamięci RAM, i wykorzystanie prawie całej przestrzeni dyskowej do celów aplikacji, które mają być hostowane na naszym Alpine Linux-ie. Do partycjjonowania dysków możemy również wykorzystać LVM. Jednak powyższe tryby pozostaje takie same tylko że z użyciem woluminów logicznych.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/F5R86Yx/ia-diskinstallmode.png" alt="Instalacja Alpine, tryb instalacji" />
+                               </p>
+                               <p>
+                                       Po wybraniu trybu instalacji zostaniemy zapytani o to czy kontynuować ponieważ wybrany dysk zostaniewyczyszczony aby móc zainstalować na nim nasz system, to jest ostatnia szansa na przerwanie instalacji, jeśli mamy taką potrzebę.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/YpG4zby/ia-diskconfirm.png" alt="Instalacja Alpine, zatwierdzenie dysku" />
+                               </p>
+                               <p>
+                                       Po zatwierdzeniu, dysk zostaje sformatowany i rozpoczyna się proces instalacji.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/LY584Sz/ia-installationprocess.png" alt="Instalacja Alpine, proces instalacji" />
+                               </p>
+                               <p>
+                                       Kiedy wskaźnik postępu osiągnie 100 % wtedy rozpoczną się czynności poinstalacjyne.
+                               </p>
+                               <p>
+                                       <img src="https://i.ibb.co/V91PVYy/ia-installationprocess2.png" alt="Instalacja Alpine, czynności poinstalacjyne, koniec instalacji" />
+                               </p>
+                               <p>
+                                       Ostatni komunikat mówi nam że system został poprawnie zainstalowany i teraz należy opuść środowisko LiveCD. Restartujemy naszą maszynę i bootujemy ją z dysku. System powinien się uruchomić.
+                               </p>
+                       </li>
+               </ol>
+               </p>
+               <p id="ntp">
+                       Alpine Linux korzysta z serwerów NTP, do ustalenia daty i czasu, jednak nie przy każdej instalacji. Jeśli ktoś korzysta z QEMU to instalator nie będzie proponował instalacji NTP, klient NTP co jakiś czas musi komunikować się serwerami czasu, co może podwodować dodatkowe obciązenie systemu, a samo QEMU nie jest hipernadzorcą jest jedynie programem emulacyjnym więc i tak wydajność gosczonych przez niego systemów jest nie zbyt zadowalająca. Instalator Alpine to zwykły skrypt powłoki, pozostawiony przypuszczalnie dla zmiany trybu instalacji systemu i wewnątrz niego możemy sprawdzić dlaczego instalator nie instaluje klient NTP, na naszym systemie. Klient NTP nie zostanie zainstalowany w przypadku szybkiej instalacji (<code class="code-inline">setup-alpine -q</code>), instalacji na QEMU oraz w przypadku uruchomienia instalatora na kontenerze LXC.
+               </p>
+               <p>
+                       <img src="https://i.ibb.co/S72vPcw/ia-ntpclient.png" alt="Instalacja Alpine, instalacja klienta NTP" /><br />
+               </p>
+               <p>
+               ~xf0r3m
+               </p>
+
+                       </div>
+                       <p class="footer">
+                               2021; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+
+               </body>
+       </html>
diff --git a/articles/linux/instalacja_Spotify_oraz_atom.io_za_pomocą_Snap.html b/articles/linux/instalacja_Spotify_oraz_atom.io_za_pomocą_Snap.html
new file mode 100644 (file)
index 0000000..f3ee93c
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Instalacja klienta Spotify oraz edytora Atom.io za pomocą snap</h1>
+        <p>
+            Wielu pewnie będzie zastanwiać się dlaczego tworzę materiał dla dwóch poleceń. Odpowiedź jest dość prosta, po to żeby nie przeszukiwać Internetu w celu ich znalezienia. Ja jestem człowiekiem, który dość szybko sie nudzi i korzystam z wielu różnych komputerów oraz wielu różnych systemów. Ciągle nie mogę znaleźć tej jedynej konfiguracji, której już bym nie zmieniał. A to na jednym komputerze klawiatura nie taka, a to coś się dzwięk psuje, bo nie ma odpowiedniego sterownika. Tworząc pewien projekt korzystałem z Della Optiplex GX620, żaden potwór, dlatego też padała decyzja aby zainstalować na nim Lubuntu i stąd się wziął ten materiał. Teraz korzystam z innego systemu operacyjnego, ale jeśli najkorzystniejszą opcją będzie wykorzystanie Lubuntu, to zamiast przeszukiwać Internet w poszukiwaniu poleceń związanych z instalacją tych dwóch programów, skorzystam z zasobów, które już posiadam. Tworzenie materiału dla dwóch poleceń, jest dla mnie jak zapisanie ich w notesie, tylko że ten mój notes, ta
+            cała moja strona o jakże enigmatycznej nazwie "morketsmerke.net", jest podłączony do Internetu. Mogę z niego skorzystać o każdej porze i gdzie kolwiek będę, ponieważ w dziejszych czasach nawet śpimy z komputerami. Oczywiście będę mogł z tego korzystać, dopóki będę zapewniać moim usługom warunki techniczne, takie jak ogólnodostępny serwer podłączony do Internetu, jak i domenę aby łatwiej nawigować pomiędzy zgromadzonymi przez siebie materiałami. Tak zgromadzonymi, ponieważ rzadko tworze własne. Zazwyczaj robie tak że szukam czegoś Internecie, sprawdzam czy to działa lub jeśli coś nie działa staram się tak dobrać czynności aby to działało. Tłumaczę często na jezyk polski znaleziska, tworzę listę czynności (poniekąd algorytm) aby uruchomić jakąś usługę, na sam koniec rozwijam to aby miało formę artykułu na bloga.
+        </p>
+        <p>
+            Wracając do głównego tematu, żeby zainstalować <em>Spotify</em> oraz <em>Atom.io</em> za pomocą <strong>snap</strong>, wystarczy że wykonamy poniższe polecenia.
+        </p>
+<pre class="code-block">
+$ sudo snap install spotify
+$ sudo snap install --classic atom
+</pre>
+        <p>
+            Na tej stronie na pewno będą pojawiać się materiały odnośnie pojedyńczych poleceń nie będą one tak długie jak ten, jednak chciałem tutaj wiele rzeczy wyjaśnić.
+        </p>
+                               <p>
+                                       P.S. Mamy 01.04.2021, wczoraj zainstalowałem na Debianie ze snap Atom.io i niestety nie chciało się uruchomić. Usunąłem i zainstalowałem ręcznie, sciągając pakiet z oficjanej strony - wszystko działa. Minus tego rozwiązania jest taki, że aktualizacji będzie trzeba dokonywać ręcznie.
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+</body>
+</html>
diff --git a/articles/linux/instalacja_aktualizacja_pakietów_na_Arch_Linux.html b/articles/linux/instalacja_aktualizacja_pakietów_na_Arch_Linux.html
new file mode 100644 (file)
index 0000000..ffd14c4
--- /dev/null
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+        <h1 class="title">Instalacja oraz aktualizacja pakietów na dystrybucjach bazujących na Arch Linux</h1>
+        <p>
+            Przez długi okres czasu trzymałem się kurczowo, jednej rodziny systemów GNU/Linux były to dystrybucje oparte o <strong>Debian</strong>: Ubuntu, Kali Linux itd. Znałem manager pakietów w tych dystrybucjach. Jednak kiedyś następuje czas na zmiany, wraz z czasopismem Linux Magazine była dołączona płyta DVD zawierająca dystrybucję Manjaro. Ta dystrybucja jest to taki "user-friendly" <strong>Arch Linux</strong>, jest czymś w rodzaju Ubuntu lub Linux Minta tylko zamiast Debiana jest właśnie Arch. Pomysłodawca wykonał kawał świetnej roboty przybliżając ludziom niezwiązanym za bardzo z Linuxem tą dystrybucje skierowaną głównie do entuzjastów. Podobnie jest z Debianem, tylko że on już zdąrzył dorosnąć i jest chyba najbardziej stabilną dystrybucją, której rozwój w 100% spoczywa w rękach społęczności. Ten materiał myślę że jest dla wszystkich tych, którym nie chce się przedzierać przez strony podręcznika a zaczynają swoją przygodę z Manjaro lub innym Arch-em.
+                                               Pierwszą rzeczą jaką zawsze robie po zainstalowaniu jakie kolwiek nowego systemu jest zainstalowanie aktualizacji, no chyba że jest to Debian, wtedy instaluje go z Internetu - podczas instalacji pobierze najnowsze pakiety. Więc jak możemy dokonać aktualizacji w systemach opartych na Arch Linux? Wydajmy poniższe polecenie.
+        </p>
+<pre class="code-block">
+$ sudo pacman -Syu
+</pre>
+        <p>
+            To polecenie spowoduje odświeżenie bazy pakietów, w raz z kluczami, które uwierzytelniają repozytoria. W Arch-ach jest wykonywane jawnie tak samo w RPM-amch takich jak Fedora czy <strong>Red Hat</strong>, w DEB-ach klucz trzeba wczytać ręcznie aby w ogóle zacząć wymieniać informacje z danym repozytorium. Po aktualizacji bazy następuje wyszukanie najnowszych wersji zainstalowanych pakietów i wyświetlenie ich listy. Zatwierdzamy aktualizacje i najnowsze pakiety zostaną ściągnięte i zainstalowane w naszym systemie.
+        </p>
+        <p>
+            Kolejną rzeczą jaką na pewno chcielibyśmy zrobić to sobie coś zainstalować. Instalacja jest równie prosta.
+        </p>
+<pre class="code-block">
+$ sudo pacman -S &lt;nazwa_pakietu&gt;
+</pre>
+        <p>
+            Do instalacji wykorzystujemy to samo polecenie tylko, że z jednym przełącznikiem nie z trzema. Po przełączniku <code class="code-inline">-S</code> podajemy nazwę pakietu. Jeśli nie znamy nazwy, możemy poszukać pakietów na stronie Arch Linux po tym linkiem: <a href="https://archlinux.org/packages/">https://archlinux.org/packages/</a>.
+        </p>
+        <p>
+            Jak możemy się domyślić nie wszystkie dystrybucje bazują na protoplastycznych trzech trzonach takich jak Red Hat, Debian czy <strong>Slackware</strong>. Jest wiele niezależnych dystrybucji, takich jak sam Arch, <strong>Gentoo</strong> czy przytaczany na tej stronie <strong>Alpine Linux</strong>. Do rozeznania się w dystrybucjach może posłużyć nam ta infografika: <a href="https://upload.wikimedia.org/wikipedia/commons/8/8c/Linux_Distribution_Timeline_Dec._2020.svg">https://upload.wikimedia.org/wikipedia/commons/8/8c/Linux_Distribution_Timeline_Dec._2020.svg</a>. Niezależne distra (skrót od dystrybucje) posiadają one raczej swoje programy służace do zarządania pakietami oprogramowania. Dlatego warto wyrobić sobie nawyk aby poszukać informacji na temat instalacji pakietów na stronie danej dystrybucji, a nie tracić czas na wyszukiwanie
+            takich artykułów jak ten.
+        </p>
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+</body>
+</html>
diff --git a/articles/linux/instalacja_kontenerów_LXD.html b/articles/linux/instalacja_kontenerów_LXD.html
new file mode 100644 (file)
index 0000000..516cf25
--- /dev/null
@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+        <h1 class="title">Instalacja kontenerów LXD/LXC</h1>
+        <p>
+            Kontenery <strong>LXD/LXC</strong> są kompromisem pomiędzy konternerami aplikacji takimi jak <em>Docker</em> oraz maszyna wirtualnymi <em>kvm</em> czy <em>xen</em>. Po ściągnięciu obrazu dostajemy czysty system operacyjny tak jakby to była świeżo zainstalowana maszyna wirtualna, ale to nadal przestrzeń użytkowa (userspace) ze współdzielonym wraz z hostem jądrem - kontener. Kontener będzie posiadać oddzielne wszystko to co kojarzy nam się z system operacyjnym, z tym elementami, których możemy hipotetycznie dotknąć. Do instalacji wybrałem serwer z system Ubuntu Server 18.04, ponieważ akurat taki miałem od ręką.
+        </p>
+        <p>
+            Pierwszą czynnością jaką wykonamy jest dodanie naszego użytkownika do grupy <code class="code-inline">lxd</code>, uwaga ta grupa może nie być dostępna przed instalacją pakietu LXD, więc jeśli to polecenie się nie powiedzie należy je wykonać zaraz po zainstalowaniu pakietu.
+        </p>
+<pre class="code-block">
+$ sudo usermod --append --groups lxd <nazwa_użytkownia>
+</pre>
+        <p>
+            Podczas instalacji tym przypadku wykorzystałem system plików <strong>ZFS</strong>, jako magazyn danych dla kontenerów. ZFS wybieram głównie, gdy dane kontenerów będą przechowywane w oddzielnym dysku. Kiedy storage kontenerów jest wspódzielony z system operacyjnym to wtenczas wybieram <strong>dir</strong> - klasyczny katalog. Póki co Ubuntu w tej wersji nie wspiera natywnie ZFS dlatego też trzeba doinstalować jego obsługę z repozytorium. Jeśli będziemy korzystać z istniejącego dysku to
+            należy utworzyć na nim partycję na całej jego wielkości.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt install zfsutils-linux
+</pre>
+        <p>
+            W wielu systemach dostępny jest manager pakietów snap. Na tej stronie możemy sprawdzić czy dla naszej dystrybucji jest on wspierany: <a href="https://snapcraft.io/docs/installing-snapd">https://snapcraft.io/docs/installing-snapd</a>, kiedy uporamy się z instalacją snapa, możemy przejść do instalacji
+            właściwego pakietu.
+        </p>
+<pre class="code-block">
+$ sudo snap install lxd
+</pre>
+        <p>
+            Po zainstalowaniu pakietu, środowisko trzeba jescze zaincjować. Wydając poniższe polecenie uruchomimy kreator, który zbierze niezbędne do konfiguracji informacje. Postaram się przetłumaczyć te pytania.
+        </p>
+<pre class="code-block">
+$ sudo lxd init
+</pre>
+
+        <p>
+            Zatem:
+        </p>
+<pre class="code-block">
+Would you like to use LXD clustering ? (yes/no) [default=no]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz użyć klastrowania LXD?</em> - spowoduje uruchomienie LXC w trybie klastrowania, czy umożliwie podłączenia do sieci węzłów, wszystkie węzły posiadają jedną bazę danych i są zarządzane za pomocą pojedyńczych poleceń. Klaster ma za zadanie łatwiejsze zarządzanie dużą ilością serwerów z LXC.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>.
+                               </p>
+<pre class="code-block">
+Do you want to configure a new storage pool ? (yes/no) [default=yes]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz skonfigurować nową przestrzeń danych</em> - odpowiedź na to pytanie uruchomi, inicjalizacje przestrzeni danych (storage) dla kontenerów.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>.
+                               </p>
+<pre class="code-block">
+Name of the new storage pool [default=default]:
+</pre>
+                               <p>
+                                       <em>Nazwa nowej przestrzeni danych?</em> - tutaj możemy nadać nazwę przestrzeni danych dla naszych kontenerów.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna / nazwa własna</strong>
+                               </p>
+<pre class="code-block">
+Name of the storage backend to use (btrfs, dir, lvm, zfs) [default=zfs]
+</pre>
+                               <p>
+                                       <em>Rodzaj przestrzeni danych</em> - możemy teraz wybrać jaka technologia zostanie użyta do zarządzania przestrzenią danych naszych kontenerów, dla oddzielnych dysków wybieram zfs, ponieważ daje najkorzystniejsze efekty, kontener ma do dyspozycji tak jakby cały dysk (wykorzystuje obraz przestrzeni ZFS), dla dysku współdzielonego z systemem używam klasyczny dir. Do tego drugiego trzeba mieć odpowiednio duży dysk. Odpowiedź może być zasugerowana w zależności od dostępności danych technologii w systemie.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <code class="code-inline">zfs</code> / <code class="code-inline">dir</code>. <em>Patrz wyżej.</em>
+                               </p>
+<pre class="code-block">
+Would you like to use an existing block device ? (yes/no) [default=no]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz użyć istniejącego dysku?</em> - wskazujemy dysk, ale tylko jeśli wybraliśmy zfs lub inny rodzaj storage-u, której jest również system plików w UNIX-ach, wyjątkiem będzie lvm, który jest sposobem zarządzania przestrzenią dyskową nie stricte system plików.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>yes</strong>.
+                               </p>
+<pre class="code-block">
+Path to existing block device:
+</pre>
+                               <p>
+                                       <em>Ścieżka do istniejącego dysku</em> - musi to być partycja, najlepiej zrobić ją jeszcze przed rozpoczęciem inicjacji.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>np. /dev/sda1</strong>
+                               </p>
+<pre class="code-block">
+Would you like to connect to a MASS server? (yes/no) [default=no]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz podłączyć się do serwera MAAS?</em> - MAAS - technologia chmury od Canonical Ltd. <a href="https://maas.io">https://maas.io</a>
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>
+                               </p>
+<pre class="code-block">
+Would you like to create a new local network bridge? (yes/no) [default=yes]
+</pre>
+                               <p>
+                                       <em>Czy chcesz utworzyć nowy most sieci lokalnej?</em> - tworzymy sieć lokalną dla kontenerów, to coś jak <em>intnet</em> w VirtualBox. Od poźniejszych ustawień będzie zależeć jak będzie wyglądać ich komunikacja, jednak między sobą oraz systemem je hostującym będzie ona dość swobodna.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>
+                               </p>
+<pre class="code-block">
+What should the new bridge be called ? [default=lxdbr0]
+</pre>
+                               <p>
+                                       <em>Jaką nazwę nadać dla nowego mostu?</em> - interfejsu między którym będzie wymieniana komunikacja pomiędzy wirtualnymi interfejsami kontenerów a interfejsem systemu hostującego.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna / dowolna</strong>
+                               </p>
+<pre class="code-block">
+What IPv4 address should be used ? (CIDR subnet notation, "auto", "none") [default=auto]
+</pre>
+                               <p>
+                                       <em>Jakiego adresu IPv4 należy użyć? [adres z notacją CIDR, "auto", "none"]</em> - podajemy adres dla mostu, jedenocześnie ustalając klasę adresów dla naszych kontererów poprzez podanie maski CIDR.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>192.168.56.1/24 / dowolna inna.</strong>
+                               </p>
+<pre class="code-block">
+Would you like LXD to NAT IPv4 traffic on your bridge? [default=yes]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz przepuścić przez NAT ruch na twoim moście?</em> - Ustawając tutaj yes lub no, możemy wybrać czy kontenery będą miały dostęp do sieci poza system je hostującym czy też nie.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>.
+                               </p>
+<pre class="code-block">
+What IPv6 address should be used? (CIDR subnet notation, "auto" or "none") [default=auto]: none
+</pre>
+                               <p>
+                                       <em>Jakiego adresu IPv6 należy użyć? [adres z notacją CIDR, "auto", "none"]</em> - możemy zefiniować adres IPv6, jeśli z nich korzystamy, ja z nich nie korzystam więc ustawiam <code class="code-inline">none</code>
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>w zależności od potrzeb / none</strong>
+                               </p>
+<pre class="code-block">
+Would you like LXD to be available over network (yes/no) [default=no]:
+</pre>
+                               <p>
+                                       (Czy chcesz aby LXD by dostępny przez sieć?) - jeśli mamy wiele serwerów pod kontrolą to możemy to ustawić, następnie zarządzać
+                                       nimi wszystkimi z jednego, umożliwienie dostępu do LXD przez sieć da nam również możliwość przenoszenia kontenerów między serwerami.
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>w zależności od potrzeb, dla pojedyńczego serwera zostawiamy domyślnie.</strong>
+                               </p>
+<pre class="code-block">
+Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
+</pre>
+                               <p>
+                                       <em>Czy chcesz automatyczne aktualizować pobrane obrazy kontenerów?</em>
+                               </p>
+                               <p>
+                       <u>Odpowiedź:</u> <strong>domyślna</strong>
+                               </p>
+<pre class="code-block">
+Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
+</pre>
+                               <p>
+                                       <em>(Czy chcemy wydrukowac wygenerowaną na podstawie naszych odpowiedzi konfiguracje LXD?)</em>
+                               </p>
+                               <p>
+                                       <u>Odpowiedź:</u> <strong>domyślna</strong>
+                               </p>
+        <p>
+            Po tym ostatnim pytaniu, środowisko LXC zostanie skonfigurowane do użycia. Kiedy zostanie nam zwrócony znak zachęty możemy przejść do utworzenia naszego
+            pierwszego kontenera. Aby utworzyć kontener należy wydać poniższe polecenie.
+        </p>
+<pre class="code-block">
+$ lxc launch ubuntu:18.04 c1
+</pre>
+        <p>
+            Gdzie <code class="code-inline">launch</code> jest poleceniem odpowiedzialnym za tworzenie nowych kontenerów, <code class="code-inline">ubuntu:18.04</code> jest nazwą źródła obrazu systemu operacyjnego, w tym przypadku określnego wyłącznie wersją, który służy do utworzenia kontenera, <code class="code-inline">c1</code> jest nazwą naszego kontenera. System LXC wspiera wiele systemów operacyjnych, ich lista znajduje się tutaj: <a href="https://us.images.linuxcontainers.org/">https://us.images.linuxcontainers.org/</a>, aby skorzystać z innych systemów niż ubuntu, należy skorzystać z oficjalnego
+            źródła, a nazwę zródła możemy sprawdzić wydając polecenie:
+        </p>
+<pre class="code-block">
+$ lxc remote list
+</pre>
+        <p>
+            Teraz dla przykładu możemy stworzyć kontener np. z GNU/Linux Debian, wydając poniższe polecenie. Dla Debiana możemy odwoływać zarówno numerem wersji jak i jej nazwą, identycznie dla Ubuntu.
+        </p>
+<pre class="code-block">
+$ lxc launch images:debian/10/amd64 c1
+</pre>
+        <p>
+            Po utworzeniu kontenera możemy się na niego zalogować aby móc na nim działać jak byśmy siedzieli przed konsolą prawdziwego serwera. Logowania możemy dokonać na dwa sposoby, jako użytkownik <em>root</em>, lub użytkownik nieuprzywilejowany z możliwością użycia polecenia podnoszącego uprawnienia. Niestety ten drugi sposób nie jest standardem i to czy możliwe będzie wykorzystanie go czy też nie, zależy głównie od konstrukcji obrazu kontenera. Druga opcja stosowana jest np. w Ubuntu, z kolei w Debianie już nie. Dlatego zachęcam do skorzystania z pierwszego sposobu.
+        </p>
+        <ul>
+            <li>Zalogowanie się na kontener jako <em>root</em> - <code class="code-inline">lxc exec &lt;nazwa_kontenera&gt; -- /bin/bash</code></li>
+            <li>Zalogowanie się jako zwykły użytkownik z prawami do <code class="code-inline">sudo</code> - <code class="code-inline">lxc exec &lt;nazwa_kontenera&gt; -- sudo --login --user ubuntu</code>(użytkownik wykorzystywany przez obrazy Ubuntu oraz Linux Mint)</li>
+        </ul>
+        <p>
+            Zalogowanie się do kontenera uruchomi powłokę interaktywną w środowisku kontenera, a co jeśli chcemy wykonać pojedyńcze polecenie, a nie uruchamiać powłokę? W tym przypadku zamiast <code class="code-inline">/bin/bash</code> wstawiamy polecenie jak ma zostać wykonane. Kiedy jednak wydajemy takie
+            polecenie, to musimy mieć świadomość tego że jest ono wykonywane z uprawnieniami użytkownika <em>root</em>, chociaż jeżeli coś popsujemy na kontenerze
+            zawsze możemy usunąć i uruchomić jeszcze raz, w prosty i szybki sposób, a nie ślęcząc przez instalacją po raz kolejny systemu bo zapomnieliśmy wyeksportować czystej maszyny zaraz po instalacji systemu, o fizycznych serwerach już nie wspominając.
+        </p>
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+</body>
+</html>
diff --git a/articles/linux/instalacja_sandstorm.io.html b/articles/linux/instalacja_sandstorm.io.html
new file mode 100644 (file)
index 0000000..654a673
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Instalacja Sandstorm.io</h1>
+               <p>
+                       <strong>Sandstorm.io</strong> jest platformą do samodzielnego hostowania popularnych aplikacji internetowych i współdzielenia ich z innymi, usprawniając tym pracę zespołów. Do zainstalowania mamy 78 różnych aplikacji, dostępnych po tym adresem <a href="https://apps.sandstorm.io/">https://apps.sandstorm.io/</a>. Warto dodać że te aplikacje są specjalnie przygotowanymi na potrzeby platformy obrazami. Nie są to pełne aplikacje, jakie otrzymalibyśmy przy samodzielnej instalacji na jednym z naszych serwerów, dlatego też używanie sandstorm jako platformy testowej dla aplikacji mija się z celem. Sama instalacja nie jest trudna, składa się ona w pierszym etapie z wyboru trybu instalacji, czy jest to <strong>instalacja normalna</strong>, po której nasz serwer będzie widoczny w Internecie pod podaną przez nas subdomeną czy <strong>instalacja developerska</strong>, instalowana lokalnie na komputerze, dostępna pod adresem "local.sandstorm.io:6080", dzięki czemu uzyskamy możliwośc przetestowania aplikacji, niestety lokalnie. Drugi etap instalacji będzie polegać na wyborze sposobu logowania zespołu do platformy czy ustawień skrzynki mailowej dla powiadomień. Tutaj opiszę instalajcję normalną, ma ona jednak spore wymagania jak stały publiczny adres IP czy też użycie maszyny wirtualnej lub fizycznego serwera.
+               </p>
+               <ol>
+                       <li>Pobranie skryptu oraz instalacja usługi na serwerze.
+                               <p>
+                                       Instalacja sandstorm najlepiej rozpocząć od zalogowania sie jako administrator (<em>root</em>) na serwerze przeznaczonym pod jego instalację. Na stronie <a href="https://sandstorm.io/install">https://sandstorm.io/install</a>, w okienku "HTTPS-verified install" znajduje się polecenie, które kopiujemy do naszego terminala. Pobrany zostanie skrypt instalacyjny, który zaraz po automatycznym uruchomieniu zapyta się o tryb instalacji w tym wypadku wybieramy opcje nr. 1. Wpisując po prostu '1'. W trakcie czynności przeprowadzanych przez instalator zostaniemy zapytani o subdomenę, jaka ma działać pod domeną '.sandcats.io' oraz o adres email, który zostanie wykorzystany do generowania certyfikatu Let's Encrypt oraz
+                                       uwierzytelnienia w razie potrzeby odzyskania domeny w trakcie ewentualnej migracji na inny serwer. Reszta czynności wykonuje się automatycznie, po zakończeniu pracy zostanie nam zwrócony link, pod który nalezy się udać aby skonfigurować naszą platformę.
+                               </p>
+                       </li>
+                       <li>Konfiguracja serwera.
+                               <p>
+                                       Pierwszą rzeczą jaką będziemy musieli skonfigurować jest metoda logownia. Do wyboru mamy kilka, jednak jedna wydaje się posiadać gwarancję działania oraz jest w miarę łatwa do skonfigurowania - Google. Kiedy wybierzemy logowanie za pomocą konta Google to cała procedura konfiguracji zostanie wypisana powyżej niezbędnych do konfiguracji pól. Jedyną czekającą na nas tutaj zagadką może być nazwa aplikacji w ekranie akceptacji OAUTH, możemy wpisać cokolwiek, np. sandstorm. Po uzyskaniu potrzebnych informacji, przechodzimy dalej. Jeśli komuś potrzebne są następne konfiguracje może je ustawić wedle uznania. Po zakończeniu konfiguracji nie pozostało nam nic innego jak tylko przejść do instalacji aplikacji i zaproszenia naszych znajomych do korzystania z usług.
+                               </p>
+                       </li>
+               </ol>
+               <p>
+                       Korzystając z Sandstorm przez krótki okres czasu miałem mieszane odczucia. Jedna z aplikacji, która była odpowiedzialna za przechowywanie plików nie chciała ich uploadować do podfolderów, jedynie do głównego katalogu. Może zrezyngnowałem z tej platformy ponieważ nie wykorzystywałem jej zgodnie z przeznaczniem a żądałem platformy do hostowania aplikacji w Internecie, a nie kilku usług dostępnych dla wąskiego grona odbiorców. Jednak mylący może być fakt, że <strong>Ghost</strong> system CMS do hostowania blogów, wspiera (obraz na tej platformie) udostepnienie tej aplikacji w sieci (pozwolenie na dostęp do treści tam umieszczonych poza logowanie do platformy). Teraz patrząc na to z boku, używanie sandstorm może prostym sposobem na wdrożenie intranetu. Sandstorm jest złym rozwiązaniem dla ludzi szukających łatwego hostingu usług w siecie, ale świetnym rozwiązaniem dla zespołów, które chcą mieć wszystko w jedym miejscu.
+               </p>
+               <p>
+                       ~xf0r3m
+               </p>
+               <p>
+                       P.S. Jeśli kogoś interesuje instalacja platformy Sandstorm, to pod tym linkiem, znajduje się dość ciekawy wpis na serwisie Reddit: <a href="https://www.reddit.com/r/selfhosted/comments/bsoduu/about_sandstormio/">https://www.reddit.com/r/selfhosted/comments/bsoduu/about_sandstormio/</a>, który może zaważyć na tym czy dalej będziemy chcieli ją instalować.
+               </p>
+       </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+</body>
+</html>
diff --git a/articles/linux/instalacja_sterowników_Nvidii_na_Debian_11.html b/articles/linux/instalacja_sterowników_Nvidii_na_Debian_11.html
new file mode 100755 (executable)
index 0000000..cb31199
--- /dev/null
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Instalacja własnościowego sterownika graficznego Nvidii na Debian 11</h1>
+                 <p>
+        Jeśli w naszym komputerze z Debian 11 zainstalowana jest karta
+        graficzna Nvidii, to na pierwszy rzut oka może okazać się, że wszystko
+        jest w porządku. Dzieje się to za sprawą wolnego sterownika Nouveau.
+        Niestety nie wszystko jest takie wspaniałe na jakie wygląda. Uruchommy
+        w tym systemie jakieś dynamiczne wideo to od razu zauważymy poziome 
+        linie "rozdzierające" obraz (ang. <em>screen tearing</em>). Otwarty 
+        sterownik niestety nie sprawdza się zbyt dobrze w tym przypadku, w 
+        szczególności gdy w naszym komputerze znajdują się układy graficzne z 
+        serii GTX.
+                 </p>
+      <p>
+        Poniżej przedstawie instalację <strong>odpowiedniego</strong>
+        sterownika dla kart graficznych Nvidii w dystrybucji Debian 11.
+        Do tego celu użyłem komputera z GTX 1050 Ti. Natomiast wykorzystanym 
+        przeze mnie środowiskiem graficznym jest XFCE z LightDM.
+      </p>
+      <p>
+        Nie wiem czy system, który jest zainstalowany na waszych komputerach 
+        był już wykorzystywane, ale w moim przypadku jest świerza instalacja
+        więc muszę skonfigurować <em>sudo</em> dla mojego użytkownika.
+      </p>
+<pre class="code-block">
+$ su root
+Hasło:
+# echo "xf0r3m ALL=(ALL:ALL) NOPASSWD:ALL" &gt;&gt; /etc/sudoers
+# (ctrl + d)
+$ sudo su
+#
+</pre>
+      <p>
+        Dla osób, które rozpoczynają dopiero swoją przygodę z dystrybucjami
+        GNU/Linux, zalecam aby nie zapisywały 
+        <code class="code-inline">NOPASSWD</code> przed <em>czwartym</em>
+        <code class="code-inline">ALL</code> dla własnego bezpieczeństwa.
+      </p>
+      <p>
+        Na początku najlepiej jest wyłączyć środowisko graficzne, aby można
+        było wygenerować nowe pliki konfiguracji serwera X.org. Nalepiej 
+        zrobić to za pomocą <em>systemd</em> zmieniając domyślny poziomu 
+        uruchomienia systemu.
+      </p>
+<pre class="code-block">
+$ sudo systemctl set-default multi-user.target
+</pre>
+      <p>
+        Po ponownym uruchomieniu komputera, możemy przejść do edycji adresów 
+        źródłowych repozytorium. Na końcu każdej linii dopisujemy <em>contrib</em>
+        oraz <em>non-free</em>.
+      </p>
+<pre class="code-block">
+$ sudo vim /etc/apt/source.list
+</pre>
+      <p>
+        Po edycji adresów musimy pobrać listy pakietów. 
+      </p>
+<pre class="code-block">
+$ sudo apt update
+</pre>
+      <p>
+        Po odświerzeniu list pakietów, instalujemy bardzo ważny pakiet. Z jego
+        pomocą określimy odpowiedni dla naszej karty sterownik
+        (pakiet Debian ze sterownikami). 
+      </p>
+<pre class="code-block">
+$ sudo apt install nvidia-detect
+</pre>
+      <p>
+        Po jego instalacji wydajemy poniższe polecenie:
+      </p>
+<pre class="code-block">
+$ sudo nvidia-detect
+</pre>
+      <p>
+        W przed ostatniej linii zapisana będzie konkretna nazwa pakietu 
+        sterownika jaki należy zainstalować. Cały proces możemu zautomatyzaować 
+        za pomocą jedenej linii i podać odpowiedni pakiet już poleceniu
+        <code class="code-inline">apt install</code>.
+      </p>
+<pre class="code-block">
+$ sudo apt install \
+&gt; $(sudo nvidia-detect | sed -n "$(($(sudo nvidia-detect | wc -l) - 1))p" | awk '{printf $1}') \
+&gt; firmware-misc-nonfree nvidia-xconfig
+</pre>
+      <p>
+        Po instalacji tych pakietów należy uruchomić ponownie system, jednakże
+        przed tą czynnością ustawimy "tryb graficzny" jako domyślny poziom
+        uruchomienia systemu. Następnie uruchamiamy ponownie komputer.
+      </p>
+<pre class="code-block">
+$ sudo systemctl set-default graphical.target
+$ sudo reboot
+</pre>
+      <p>
+        Po uruchomieniu systemu i zalogowaniu się do środowiska graficznego w 
+        terminalu wydajemy polecenie:
+      </p>
+<pre class="code-block">
+$ nvidia-settings
+</pre>
+      <p>
+        Powinnien nam pojawić się panel sterowania Nvidii, domyślnie wyświetlić
+        podsumowanie odnośnie karty graficznej.
+      </p>
+      <p>
+        Podsumowując. Podczas instalacji sterowników graficznych na Debian
+        warto użyć polecenia <em>nvidia-detect</em>, aby dobrać odpowiedni 
+        sterownik i proszę aby nie sugerować się tym co jest napisane na 
+        stronie Nvidii. Pakiety Debian aby pakiety stworzone przez Nvidię nie
+        są tożsame.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/linux/instalacja_systemu_z_własnego_obrazu_LiveCD_z_Debianem.html b/articles/linux/instalacja_systemu_z_własnego_obrazu_LiveCD_z_Debianem.html
new file mode 100644 (file)
index 0000000..567a888
--- /dev/null
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+         <p class="header_link">
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+      <h1 class="title">Instalacja system z własnego obrazu LiveCD z Debianem</h1>
+      <p>
+        Jakiś czas temu przedstawiono tutaj materiał o stworzeniu własnego
+        LiveCD z Debianem. Tutaj chciałbym iść o krok dalej. Rozważmy przypadek
+        taki, że korzystaliśmy z LiveCD przez dłuższy czas, obecnie już nie 
+        musimy z niego korzystać, ale chcemy zainstalować na stałe ten obraz
+        na swoim komputerze. Do realizacji tego będziemy potrzebować kolejnego
+        obrazu dystrybucji, tym razem w pełnej wersji (pomijamy opcję
+        <em>variant</em> podczas pobierania obrazu), oraz obrazu wykorzystanego
+        do stworzenia LiveCD
+      </p>
+      <p>
+        Dla celów porządkowych utworzymy katalog o nazwie
+        <em>custom-debian</em>.
+      </p>
+<pre class="code-block">
+# mkdir custom-debian
+</pre>
+      <p>
+        Do utworzonego katalogu pobieramy pełny obraz dystrybcji.
+      </p>
+<pre class="code-block">
+# debootstrap --arch=amd64 bullseye /root/custom-debian http://ftp.icm.edu.pl/debian
+</pre>
+      <p>
+        Kiedy obraz będzie gotowy do użycia, kopiujemy do niego zawartość 
+        katalogu obrazem LiveCD. 
+      </p>
+<pre class="code-block">
+# cp -prvv /root/customDebianLiveCD/chroot/* /root/custom-debian
+</pre>
+      <p>
+        Zmieniamy katalog główny na katalog obrazu
+      </p>
+<pre class="code-block">
+# chroot /root/custom-debian /bin/bash
+</pre>
+      <p>
+        Usuwamy pakiet <em>live-boot</em>.
+      </p>
+<pre class="code-block">
+# export $PS1="(chroot) ${PS1}"
+(chroot) # apt remove live-boot
+(chroot) # apt autoremove
+</pre>
+      <p>
+        Następnie przechodzimy do katalogu z pełnym obrazem i tworzymy w nim
+        archiwum zawierające wszystkie jego pliki i katalogi.
+      </p>
+<pre class="code-block">
+# cd custom-debian
+# tar -czvf custom-debian.tgz *
+</pre>
+      <p>
+        Tak przygotowane archiwum musimy gdzieś udostępnić, aby maszyna
+        uruchomiona z LiveCD mogła je swobodnie pobrać.
+      </p>
+      <p>
+        Kolejnym krokiem jest uruchomienie maszyny docelowej z LiveCD i
+        instalacja systemu z tej wcześniej przygotowanej paczki. Opis
+        instalacji znajduje się pod tym linkiem: 
+             <a href="https://morketsmerke.net/site/greenOS/instalacja_greenos.html">
+                     https://morketsmerke.net/site/greenOS/instalacja_greenos.html</a>
+        Tak przygotowany obraz dystrybucji instaluje się identycznie jak
+        greenOS.
+      </p>
+      <p>
+        W przedstawiony powyżej sposób możemy przygotować obraz dystrybucji
+        na podstawie wcześniej przygotowanego obrazu LiveCD, a następnie
+        zainstalować go swobodnie na dysku.
+      </p>
+      <p>
+         ~xf0r3m
+      </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+  </body>
+</html>
diff --git a/articles/linux/przekierowanie_portów_do_kontenerów_LXD.html b/articles/linux/przekierowanie_portów_do_kontenerów_LXD.html
new file mode 100644 (file)
index 0000000..721a6ed
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body style="font-family: monospace;" >
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Przekierowanie portów do kontenerów LXD</h1>
+        <p>
+            Gdzieś w tej kategorii znajduje się materiał odnośnie instalacji i inicjalizacji środowiska kontenerów LXD/LXC. Kiedy już nacieszyliśmy się tymi kontenerami, to czas zagonić je do pracy. Jak pamiętamy z wyżej wymienionego materiału podczas konfiguracji umożliwiliśmy komunikacje z Internetem oraz siecią lokalną serwera hostującego przez NAT. Stan komunikacji wygląda na taki jak że kontenery mogą komunikować z kim kolwiek, a z nimi nikt poza serwerem hostującym. A jeśli mają one dla nas hostować jakieś usługi to musimy mieć możliwość połączenia się z nimi. NAT w przypadku opartych na Debianie dystrybucji jest realizowany przez <em>iptables</em>. Warto zauważyć, że wewnątrz serwera hostującego zrobiła się taka mikrosieć, gdzie nasz interfejs mostu jest tym interfejsem wewnętrzny a główny interfejs sieciowy serwera, interfejsem zewnętrznym.
+                                               Czyli <strong>aby nasze kontenery mogły świadczyć usługi w Internecie trzeba dopuścić do nich ruch na wybranych portach</strong>, tak jakby było serwerami w klasycznej sieci lokalnej. Dowiadując się z tego materiału jak przekierować porty z interfejsu serwera do poszczególnych kontenerów, będziemy wiedzieć jak przekierować porty z interfejsu zewnętrzego naszej sieci do konkretnych serwerów, oczywiście o ile w naszej sieci wykorzystujemy bramkę opartą o iptables.
+        </p>
+<pre class="code-block">
+# iptables -t nat -I PREROUTING -i enp1s0 -p tcp -d 192.168.1.6 --dport 80 -j DNAT --to-destination 192.168.56.2:80
+</pre>
+               <p>
+                       W tablicy <code class="code-inline">nat</code>, w łańcuchu <code class="code-inline">PREROUTING</code> wstawiliśmy regułę, która przekieruje wszystkie pakiety, zaadresowane do naszego serwera kontenerów na porcie <code class="code-inline">80</code> do kontenera o adresie <code class="code-inline">192.168.56.2</code> na port <code class="code-inline">80</code>, za pomocą <strong>DNAT</strong> - zamiany adresu docelowego, w tym przypadku z adresu serwera na adres kontenera.
+               </p>
+               <p>
+                       Za pomocą pojedyńczego polecenia umożliwiliśmy połączenie dowolnego komputera w sieci z serwerem WWW uruchomionym na naszym kontenerze. Aby dostosować tę regułę do "port forwardingu" w naszej sieci opartej o bramkę z GNU/Linux-em, wystartczy zmienić interfejs i adresy, ewentualnie porty i protokół jeśli chcemy wypuścić coś innego niż HTTP.
+               </p>
+               <p>
+                       ~xf0r3m
+               </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+       </body>
+</html>
diff --git a/articles/linux/samba_AD_DC_-_Instalacja.html b/articles/linux/samba_AD_DC_-_Instalacja.html
new file mode 100644 (file)
index 0000000..103678e
--- /dev/null
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Samba AD DC - Instalacja</h1>
+        <p>
+            <strong>Samba Active Directory</strong> może być nieco lżejszą implementacją od usługi Active Directory oferowanej przez system Windows, jednak jego instalacja nie jest już taka prosta jak ma to miejsce w przypadku rozwiązań firmy Microsoft. Przedstawiona tutaj operacja będzie składać się z dwóch części, pierwsza z nich to właściwa instalacja usługi Samba AD DC, a drugą to <strong>instalacja usługi NTP, która jest niezbędną do prawidłowego funkcjonowania. Właśnie jest róźnica pomiędzy dwoma wyżej wymienionymi implementacjami, przy SAMBA AD jeśli zegar na komputerze klienta spóźnia się choćby o 5 minut to zalogowanie się na komputerze za pomocą użytkownika owej usługi może być już niemożliwe</strong>. Zatem przed przyłączeniem komputera do domeny, warto na początek ustawić serwer czasu na nasz kontroler domeny, a teraz zabierzemy się do właściwej instalacji. Na swój serwer wybrałem dystrybucje GNU/Linux Debian.
+        </p>
+        <p>
+            <ol>
+                <li><strong>Ustawienie statycznego adresu IP</strong>
+                    <p>
+                        Z racji tego że nasz system ma świadczyć jakieś usługi w sieci, więc powinien mieć stały adres IP. Dzięki temu można go łatwo odnaleźć w sieci oraz przypisać mu jakąś przyjazną nazwę. Otwieramy plik <em>/etc/network/interfaces</em>.
+                    </p>
+<pre class="code-block">
+allow-hotplug enp2s0
+iface enp2s0 inet static
+address 192.168.1.10
+netmask 255.255.255.0
+gateway 192.168.1.1
+dns-nameservers 192.168.1.1
+</pre>
+                </li>
+                <li><strong>Wyłączenie usługi systemd-resolved</strong>
+                    <p>
+                        Usługa systemd-resolved będzie kolidować z wbudowanymi usługami DNS Samby, więc musimy ją wyłączyć i statycznie w pliku <em>/etc/resolv.conf</em> ustawić adres IP serwera DNS, do którego będą przekazywane zapytania niezwiązane z domeną.
+                    </p>
+<pre class="code-block">
+$ sudo systemctl disable systemd-resolved.service
+$ sudo rm /etc/resolv.conf
+$ sudo su
+# echo "nameserver 192.168.8.1" > /etc/resolv.conf
+# echo "127.0.1.1   adc1" >> /etc/hosts
+# reboot
+</pre>              <p>
+                        Za pomocą polecenia <code class="code-inline">systemctl</code>, wyłączamy usługę systemd-resolved, nastepnie usuwamy przez nią stworzony plik <em>/etc/resolv.conf</em>, aby móc przekierować wyjście do plików w katalogu <em>/etc</em> musimy przełączyć się na użytkownika <em>root</em>, użycie polecenia <code class="code-inline">sudo</code> nie zadziała w tym przypadku. Do naszego nowego pliku <em>/etc/resolv.conf</em> dodajemy stały wpis adresu serwera DNS, w moim przypadku jest to adres bramy sieci, która jest nad moją siecią. Przedostatnia linia przedstawia dopisanie adresu przypisanego do naszej nazwy hosta do pliku <em>/etc/hosts</em>. Nie które aplikacje mogą ustalać tak nazwę hosta odpytując lokalny dns adresem <code class="code-inline">127.0.1.1</code>, tak robi np. polecenie <code class="code-inline">sudo</code>, które jeśli nie otrzyma odpowiedzi będzie wyświetlać komunikat po każdorazowym wykonaniu. Teraz należy uruchomić nasz serwer ponownie, aby uaktywnić wszystkie zmiany.
+                    </p>
+                </li>
+                <li><strong>Aktualizacja systemu</strong>
+                    <p>
+                        Po wykonaniu powyższych konfiguracji, jak przed każdą instalacją jakiego kolwiek pakietu warto zaktualizować nasz system.
+                    </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt dist-upgrade
+</pre>
+                </li>
+                <li><strong>Instalacja niezbędnego oprogramowania</strong>
+                    <p>
+                        Aby rozpocząć konfigurację Samba AD DC, musimy zainstalować poniższe oprogramowanie.
+                    </p>
+<pre class="code-block">
+$ sudo apt install samba krb5-user krb5-config winbind libpam-winbind libnss-winbind
+</pre>
+                    <p>
+                        Podczas instalacji pakietu <strong>Kerberos</strong> (systemu uwierzytelniania wykorzystywanego przez Sambę) zostaniemy poproszeni o podanie <em>sfery Kerberos</em> gdzie podajemy nazwę naszej domeny wielki literami, np. <em>TEST.LOCAL</em>, adresu serwera Kerberos w sferze - podajemy nazwę naszej domeny małymi literami oraz adres serwera administracyjnego - identycznie jak przy serwerze Kerberos w sferze. Jak możemy się domyślić, to za nazwą naszej domeny będzie kryć się nasz serwer, który obecnie konfigurujemy.
+                    </p>
+                </li>
+                <li><strong>Zatrzymanie usług</strong>
+                    <p>
+                        W procesach poinstalacyjnych pakietu <code class="code-inline">samba</code> plik usługi AD DC został wyłączony, uruchomione zostały usługi odpowiedzialne za <em>NetBIOS</em> oraz <em>SMB</em>, które w obecnej konfiguracji nie będą nam potrzebne. Zatrzymujemy również daemona <code class="code-inline">winbind</code>, ponieważ będzie on uruchamiany przez proces kontrolera domeny w razie potrzeby.
+                    </p>
+<pre class="code-block">
+$ sudo systemctl stop samba-ad-dc.service smbd.service nmbd.service winbind.service
+$ sudo systemctl disable smbd.service nmbd.service winbind.service
+</pre>
+                </li>
+                <li><strong>Zabezpieczenie pliku konfiguracyjnego Samby</strong>
+                    <p>
+                        Warto skopiować plik, który został dostarczony wraz z pakietem na tzw. w razie czego. Jeśli coś nie wyjdzie podczas promowania, to będziemy mogli ten plik przywrócić.
+                    </p>
+<pre class="code-block">
+$ sudo mv /etc/samba/smb.conf   /etc/samba/smb.conf.init
+</pre>
+                </li>
+                <li><strong>Promowanie serwera do roli kontrolera Samba AD DC</strong>
+                    <p>
+                        Przyszedł czas na tę chwilę, aby wreszczenie promować nasz serwer do roli kontrolera domeny, jednak nie ma co się za bardzo ekscytować. Ponieważ jedyna co mamy zrobić to wpisać tylko dwie informacje, o które zapyta skrypt tj. sferę, która jest identyczna jak w przypadku Kerberos - nazwa domeny z wielkich liter oraz hasło administratora AD, które musi składać się z min 8 znaków, jedna duża litera, jedna cyfra i nie może zawierać fragmentów loginu (administrator@TEST.LOCAL).
+                    </p>
+<pre class="code-block">
+$ sudo samba-tool domain provision --use-rfc2307 --interactive
+</pre>
+                </li>
+                <li><strong>Uruchamianie konfiguracji Kerberos</strong>
+                    <p>
+                        Przy promowaniu serwera skrypt wykonał za nas konfigurację Kerberos, naszym zadaniem jest tylko ją uruchomić linkując plik wygenerowany przez program do miejsca gdzie będzie mógł być odczytany przez daemona Kerberos.
+                    </p>
+<pre class="code-block">
+$ sudo mv /etc/krb5.conf /etc/krb5.conf.init
+$ sudo ln -s /var/lib/samba/private/krb5.conf /etc
+</pre>
+                </li>
+                <li><strong>Uruchomienie daemona Samba</strong>
+                    <p>
+                        Aby uruchomić uruchomić nasz kontroler domeny, musimy odblokować plik usługi.
+                    </p>
+<pre class="code-block">
+$ sudo systemctl unmask samba-ad-dc.service
+$ sudo systemctl start samba-ad-dc.service
+$ sudo systemctl status samba-ad-dc.service
+$ sudo systemctl enable samba-ad-dc.service
+</pre>
+                    <p>
+                        Po wykonaniu tych poleceń usługa powinna wystartować.
+                    </p>
+                </li>
+                <li><strong>Sprawdzenie portów używanych przez Sambę oraz poziomu funkcjonalności domeny.</strong>
+                    <p>
+                        Aby upewnić się że usług wystartowała, wydajmy poniższe polecenia.
+                    </p>
+<pre class="code-block">
+$ sudo ss -tulpn | egrep 'smbd|samba'
+$ sudo samba-tool domain level show
+</pre>
+                    <p>
+                        Pierwsze polecenie powinno zwrócić listę portów otwartych przez Sambę, natomiast drugie określić funkcjonalność domeny przyrównując ją do funkcjonalności usług domenowych systemu Windows, zobaczymy nawet wersje systemu Windows Server, z którym funkcjonalność usług katalogowych jest identyczna.
+                    </p>
+                </li>
+                <li><strong>Przekierowanie lokalnego DNS na kontroler.</strong>
+                    <p>
+                        Teraz kiedy mamy pewność że nasz kontroler domeny teoretycznie działa możemy przekierować lokalne zapytania do niego aby upewnić się że wszystkie informacje zostaną przekazane klientom kiedy ci będą chcieli się podłączyć. Dopisujemy adres pętli zwrotnej na początku listy serwerów DNS w konfiguracji interfejsu sieciegowego.
+                    </p>
+<pre class="code-block">
+allow-hotplug enp2s0
+iface enp2s0 inet static
+address 192.168.1.10
+netmask 255.255.255.0
+gateway 192.168.1.1
+dns-nameservers 127.0.0.1 192.168.1.1
+</pre>
+                    <p>
+                        Po zapisaniu zmian przejdziemy do przygotowania nowego pliku <em>/etc/resolv.conf</em>. Oczywiście możemy zmienić plik, który jest już obecny w systemie. Ja stworzyłem inny plik, następnie nadpisałem nim plik źródłowy.
+                    </p>
+<pre class="code-block">
+$ sudo su
+# echo "nameserver 127.0.0.1" > /etc/resolv.conf.bak
+# cat /etc/resolv.conf >> /etc/resolv.conf.bak
+# echo "search test.local" >> /etc/resolv.conf.bak
+# mv /etc/resolv.conf.bak /etc/resolv.conf
+</pre>
+                    <p>
+                        Na początku pliku znajduje się deklaracja serwera DNS z adresem pętli, następnie dopisałem obecną zawartość pliku <em>/etc/resolv.conf</em>, dodałem linię z sufksem domeny do przeszukiwania kiedy podamy nazwę krótką hosta, na koniec nadpisałem plik.
+                    </p>
+                </li>
+                <li><strong>Restart serwera.</strong>
+                    <p>
+                        Warto ponownie zrestartować serwer, aby wszystkie zmiany zostały uwzględnione.
+                    </p>
+<pre class="code-block">
+# reboot
+</pre>
+                </li>
+                <li><strong>Sprawdzenie poprawności konfiguracji kontrolera domeny</strong>
+                    <p>
+                        Poniżej przedstawiłem kilka kontrolnych poleceń, które powinny wykonać się bezbłędnie gdy kontroler AD jest prawidłowo skonfigurowany.
+                    </p>
+<pre class="code-block">
+$ ping -c3 &lt;nazwa_domeny&gt;
+$ ping -c3 &lt;nazwa_hosta&gt;.&lt;nazwa_domeny&gt;
+$ ping -c3 &lt;nazwa_hosta&gt;
+$ host -t A &lt;nazwa_domeny&gt;
+$ host -t A &lt;nazwa_hosta&gt;.&lt;nazwa_domeny&gt;
+$ host -t SRV _kerberos._udp.&lt;nazwa_domeny&gt;
+$ host -t SRV _ldap._tcp.&lt;nazwa_domeny&gt;
+$ kinit administrator@&lt;NAZWA_DOMENY_Z_WIELKICH&gt;
+$ klist
+</pre>
+                </li>
+            </ol>
+        </p>
+        <p>
+            Tymi poleceniami zakończymy część pierwszą, druga znajduje się pod tym linkiem: <a href="../../articles/linux/samba_AD_DC_-_NTP.html">Samba AD DC - NTP</a>
+        </p>
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+</body>
+</html>
diff --git a/articles/linux/samba_AD_DC_-_NTP.html b/articles/linux/samba_AD_DC_-_NTP.html
new file mode 100644 (file)
index 0000000..3a8386a
--- /dev/null
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Samba AD DC - NTP</h1>
+        <p>
+            Ten materiał jest to drugą częścią instalacji Samba AD DC, pierwsza część znajduje się pod tym linkiem: <a href="samba_AD_DC_-_Instalacja.html">Samba AD DC - Instalacja</a>. Tutaj zajmiemy się instalacją usługi <strong>NTP</strong>, która niestety jest wymagana w przypadku implementacji Samby. Nie przedłużając naszą pracę rozpoczniemy instalacji niezbędnego oprogramowania.
+        </p>
+<pre class="code-block">
+$ sudo apt install ntp ntpdate
+</pre>
+        <p>
+            Po zainstalowaniu wyżej wymienionych pakietów, przejdziemy do konfiguracji NTP. Otwieramy plik <em>/etc/ntp.conf</em>. Pierwszą czynnością będzie wyłączenie istniejących źródeł serwerów czasu po przez komentarz i dodanie poniższych.
+        </p>
+<pre class="code-block">
+pool 0.pool.ntp.org iburst
+pool 1.pool.ntp.org iburst
+pool 2.pool.ntp.org iburst
+</pre>
+        <p>
+            Pod zródłami znajdują się jeszcze jedno źródło, serwery zapasowe. Obecene serwery zapasowe wyłączamy, wstawiając na początku znak komentarza, następnie dopisujemy poniższe źródło.
+        </p>
+<pre class="code-block">
+pool 3.pool.ntp.org iburst
+</pre>
+        <p>
+            W pliku konfiguracjnym odszukujemy deklaracje <code class="code-inline">driftfile</code>. Pod tą deklaracją wpisujemy poniższe opcję wskazującą na socket łączący NTP wraz z Sambą.
+        </p>
+<pre class="code-block">
+ntpsigndsocket /var/lib/samba/ntp_signd/
+</pre>
+        <p>
+            Dopisujemy do opcji <code class="code-inline">restrict</code> wartości zabezpieczające nasz serwer NTP.
+        </p>
+<pre class="code-block">
+restrict default kod nomodify nopeer notrap mssntp
+</pre>
+        <p>
+            Zapisujemy zmiany w pliku konfiguracyjnym. Następnie ustawiamy odpowiednie uprawnienia dla folderu z gniazdem, który zdeklarowaliśmy w powyższym pliku.
+        </p>
+<pre class="code-block">
+$ sudo chown root:ntp /var/lib/samba/ntp_signd/
+$ sudo chmod 750 /var/lib/samba/ntp_signd/
+</pre>
+        <p>
+            Po ustawieniu uprawnień, restartujemy serwer.
+        </p>
+<pre class="code-block">
+$ sudo reboot
+</pre>
+        <p>
+            Gdy serwer się uruchomi możemy sprawdzić czy NTP działa. Na początku sprawdzimy jakie porty są otwarte w systemie.
+        </p>
+<pre class="code-block">
+$ sudo ss -tulpn | grep ntp
+</pre>
+        <p>
+            Odfiltrowałem wynik polecenia aby łatwiej by znaleźć interesujące nas informacje. Powinnismy znaleźć jakąś usługę która nasłuchuje na porcie UDP 123. Następnie możemy uruchomić poniższe polecenie aby wyświetlić podsumowanie połączenia ze z serwerami źródłowymi.
+        </p>
+<pre class="code-block">
+$ sudo ntpq -p
+</pre>
+        <p>
+            Odnośnie serwera NTP. <strong>Może być tak że serwer może się zawiesić i przestać odpowiadać na zapytania o aktualizacje czasu.</strong> Jedyne co możemy zrobić w tej sytuacji to zatrzymać usługę, z synchronizować datę i czas serwera z jakiś z oficjalnych zasobów i uruchomić usługę ponownie.
+        </p>
+<pre class="code-block">
+$ sudo systemctl stop ntp.service
+$ sudo ntpdate -b 2.pool.ntp.org
+$ sudo systemctl start ntp.service
+$ sudo systemctl status ntp.service.
+</pre>
+        <p>
+            Ostatnie polecenie nie jest wymagane, jednak warto upewnić się czy wszystko działa.
+        </p>
+        <p>
+            Po uruchomieniu NTP, możemy podłacząć komputery klienckie do naszej domeny. Pamiętajmy jednak żeby na początku w systemie ustawić serwer czasu na kontroler. Teraz możemy ustawić serwery DNS na nasz kontroler i podłączyć chociażby Windowsa. Windowsą sie łatwo podłacza, a warto ponieważ będziemy mogili zainstalować przystawkę dzięki której będziemy kontrolować naszą domenę z poziomu okienka. To koniec części drugiej, nie jest ona tak długa jak część pierwsza i mogła by zostać po prostu włączona do samej instalacji, jednak zostało to podzieleno ponieważ NTP stanowi odrębną usługę i może być wykorzystanie przy innych konfiguracjach serwerów, pomijając oczywiście część związną z socketem.
+        </p>
+        <p>
+            ~xf0r3m
+        </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+</body>
+</html>
diff --git a/articles/linux/szyfrowany_rootfs_na_greenOS.html b/articles/linux/szyfrowany_rootfs_na_greenOS.html
new file mode 100755 (executable)
index 0000000..9882cc2
--- /dev/null
@@ -0,0 +1,336 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">Szyfrowany rootfs na greenOS</h1>
+    <p>
+      Jeśli naszym głównym komputerem, z którego korzystamy na codzień jest
+      laptop, to zapewne dla własnej wygody mamy na nim wiele cennych danych,
+      których być może zniszczenie niebyło by aż tak bolesne jak dostanie się
+      tych informacji w niepowłone ręce. Temu właśnie ma służyć szyfrowanie
+      dysków. W tym przypadku będziemy szyfrować partycję zawierającą
+      główny system plików z wyłączeniem katalogu <em>/boot</em>. Z racji tego
+      iż greenOS nie korzysta z klasycznego debianowskiego programu 
+      <em>debian-installer</em> i instaluje się go ręcznie tak samo jak
+      <em>Arch Linux</em>. To instalacje z szyfrowaniem partycji z głównego
+      katalogu również musimy wykonać z ręki. Instalacje rozpoczynamy od
+      uruchomienia komputera z LiveCD. Możebyć to dowolny Debian lub greenOS.
+    </p>
+    <ol>
+      <li>Aktualizacja list pakietów dystrybucji.
+<pre class="code-block">
+# apt update
+</pre>
+      </li>
+      <li>Instalacja pakietu <strong>cryptsetup</strong> w środowisku LiveCD
+<pre class="code-block">
+# apt install cryptsetup
+</pre>
+      </li>
+      <li>
+          <p>
+          Partycjonowanie dysku. Tutaj jest to raczej sprawa indywidualna, ale
+          najbardziej klasyczny schemat partycjonowania została przestawiowy
+          w tabelce poniżej. Do partycjonowania dysku może służyć wbudowane
+          polecenie <em>fdisk</em>:
+          </p>
+<pre class="code-block">
+# fdisk /dev/sda
+</pre>
+        <table>
+          <tr>
+            <th>Urządzenie</th>
+            <th>Rozmiar</th>
+            <th>Punkt montowania</th>
+          </tr>
+          <tr>
+            <td>/dev/sda1</td>
+            <td>300M</td>
+            <td>/boot</td>
+          </tr>
+          <tr>
+            <td>/dev/sda2</td>
+            <td>-1G</td>
+            <td>/</td>
+          </tr>
+          <tr>
+            <td>/dev/sda5</td>
+            <td>1G</td>
+            <td>swap</td>
+          </tr>
+        </table>
+      </li>
+      <li>
+          <p>
+          Tworzymy system plików dla partycji przeznaczonej na katalog
+          <em>/boot</em>.
+          </p>
+<pre class="code-block">
+# mkfs.ext4 /dev/sda1
+</pre>
+      </li>
+      <li>
+          <p>
+          Tworzymy szyfrowany wolumin na partycji przeznaczonej na główny
+          system plików. Program poprosi o potwierdzenie
+          działania poprzez wpisane DUŻYMI literami słowa: <em>YES</em>.
+          Następnie poprosi o podanie klucza (hasła) do odszyfrowania woluminu.
+          </p>
+<pre class="code-block">
+# cryptsetup -y -v luksFormat /dev/sda2
+</pre>
+      </li>
+      <li>
+          <p>
+          Otwieramy szyfrowany wolumin. Program zapyta o klucz.
+          </p>
+<pre class="code-block">
+# cryptsetup open /dev/sda2 cryptroot
+</pre>
+        <p>
+        Ostatni argument jest nazwą, pod którą będzie odwoływać się do
+        odszyfrowanego woluminu. Mapowanie (nazwa) znajduje się w katalogu
+        <em>/dev/mapper</em>.
+        </p>
+      </li>
+      <li>
+          <p>
+          Tworzymy system plików na odszyfrowanym woluminie.
+          </p>
+<pre class="code-block">
+# mkfs.ext4 /dev/mapper/cryptroot
+</pre>
+      </li>
+      <li>
+          <p>
+          Montujemy system plików woluminu w katalogu <em>/mnt</em>.
+          </p>
+<pre class="code-block">
+# mount /dev/mapper/cryptroot /mnt
+</pre>
+      </li>
+      <li>
+          <p>
+          Tworzymy katalog <em>/mnt/boot</em>, dla oddzielnej partycji
+          <em>/boot</em>.
+          </p>
+<pre class="code-block">
+# mkdir /mnt/boot
+</pre> 
+      </li>
+      <li>
+          <p>
+          Montujemy partycje przeznaczoną na katalog <em>/boot</em> we
+          wcześniej utworzonym katalogu.
+          </p>
+<pre class="code-block">
+# mount /dev/sda1 /mnt/boot
+</pre>
+      </li>
+      <li>
+          <p>
+          Przechodzimy do katalogu <em>/mnt</em> i pobieramy paczkę z plikami
+          bazowymi dystrybucji.
+          </p>
+<pre class="code-block">
+# cd /mnt
+# wget http://ftp.morketsmerke.net/greenOS/rootfs.tgz
+</pre>
+      </li>
+      <li>
+          <p>
+          Rozpakowujemy pliki bazowe.
+          </p>
+<pre class="code-block">
+# tar -xzvf rootfs.tgz 
+</pre>
+      </li>
+      <li>
+          <p>
+          Tworzymy system plików dla partycji ze <em>swap</em>-em.
+          </p>
+<pre class="code-block">
+# cd
+# mkswap /dev/sda5
+</pre>
+      </li>
+      <li>
+          <p>
+          Przekierowujemy wyjście polecenia <em>blkid</em> do pliku
+          <em>/mnt/etc/fstab</em>. Musimy wyedytować zawartość tego pliku, aby
+          wyglądał mniej więcej tak:
+          </p>
+<pre class="code-block">
+# blkid &gt; /mnt/etc/fstab
+# vim /mnt/etc/fstab
+
+UUID="..."  /boot ext4  defaults  0 2
+UUID="..."  none  swap  sw  0 0
+/dev/mapper/cryptroot / ext4  defaults  0 1
+</pre>
+      </li>
+      <li>
+          <p>
+          Montujemy katalogi systemowe do podkatalogów w <em>/mnt</em> aby
+          widoczne były urządzenia komputera w środowisku <em>chroot</em>.
+          </p>
+<pre class="code-block">
+for i in /dev /dev/pts /proc /run /sys; do mount -B $i /mnt$i; done
+</pre>
+      </li>
+      <li>
+          <p>
+          Zmieniamy katalog główny na <em>/mnt</em>.
+          </p>
+<pre class="code-block">
+# chroot /mnt
+</pre>
+      </li>
+      <li>
+          <p>
+          Wykonujemy kilka czynności instalacyjnych, takich jak ustawienie
+          hasła dla użytkownika <em>root</em>, utworzenie nowego użytkownika 
+          oraz nadanie mu uprawnień administratora.
+          </p>
+<pre class="code-block">
+# passwd
+# adduser user
+# vim /etc/sudoers
+
+user  ALL=(ALL) NOPASSWD:ALL
+</pre>
+      </li>
+      <li>
+          <p>
+          W środowisku zmienionego katalogu podstawowego, odświerzamy listy
+          pakietów dystrybucji oraz instalujemy pakiet <em>cryptsetup</em>.
+          Podczas instalacji pakietu możemy zignorować błędy związane z 
+          mkinitramfs oraz cryptroot. Polecenie oświerzenia list może się
+          zawieść, w tym przypadku należy przerwać to polecenie i pobrać
+          konfigurację sieci z serwera dhcp.
+          </p>
+<pre class="code-block">
+# dhclient
+# apt update
+# apt install cryptsetup
+</pre>
+      </li>
+      <li>
+          <p>
+          Utworzenie wpisu w pliku <em>/etc/crypttab</em>. Plik zawiera
+          wystąpienia szyfrowanych woluminów w systemie. Definiuje odzorowania
+          nazw w katalogu /dev/mapper, plik klucza oraz opcje
+          <em>cryptsetup</em>. Wpis użyty tym przykładzie
+          będzie opierać, się na totalnym minimum konfiguracji. Jest on 
+          niezbędny do
+          wygenerowania odpowiednich procedur w <em>initramfs</em>. W skrócie
+          jest potrzebny aby w ogóle dało się odszyfrować wolumin. Pierwsze
+          polecenie służy zapisaniu UUID urządzania blokowego z szyfrowanym
+          woluminem w pliku (oczywiście w tylko i wyłacznie w tym przykładzie).
+          </p>
+<pre class="code-block">
+# blkid | grep "LUKS" | awk '{printf $2}' &gt;&gt; /etc/crypttab
+# vim /etc/crypttab
+
+cryptroot UUID="..."  none  luks
+</pre>
+          <p>
+          Gdzie: <code class="code-inline">cryptroot</code> jest to nazwa
+          odwzrowania, <code class="code-inline">UUID</code> wskazuje na 
+          urządzenie blokowe przechowywujące zaszyfrowany wolumin, 
+          <code class="code-inline">none</code> jest to wskazanie pliku klucz
+          w przypadku tej opcji, zostaniemy poproszeni o wprowadzenie klucza
+          podczas uruchamiania systemu, ostatnia opcja
+          <code class="code-inline">luks</code> spowoduje wymuszenie użycia 
+          trybu LUKS, który jest standardem wśród 
+          szyfrowanych woluminów na dystrybucjach Linux-a. Ten standard został
+          użyty także przez nas.
+          </p>
+        </li>
+        <li>
+            <p>
+            Wygenerowanie nowego dysku początkowego. Zwróćmy uwagę na to, iż
+            po zapisaniu wpisu w pliku <em>/etc/crypttab</em> nie pojawiają
+            pojawiają się żadne błędy podczas jego generowania. Tak jak miało
+            to miejsce podczas instalacji <em>cryptsetup</em> przy zmienionym
+            katalogu głównym.
+            </p>
+<pre class="code-block">
+# mkinitramfs -o /boot/initrd.img-4.19.0-18-amd64
+</pre>
+        </li>
+        <li>
+            <p>
+            Instalacja rekordu rozruchowego na dysku
+            </p>
+<pre class="code-block">
+# grub-install /dev/sda
+</pre>
+        </li>
+        <li>
+            <p>
+            Wygenerowanie pliku konfiguracyjnego dla programu rozruchowego.
+            </p>
+<pre class="code-block">
+# update-grub
+</pre>
+        </li>
+        <li>
+            <p>
+            Opuszczenie środowiska zmienionego katalogu głównego.
+            </p>
+<pre class="code-block">
+# exit
+</pre>
+        </li>
+        <li>
+            <p>
+            Odmontowanie wszystkich wcześniej montowanych systemów plików.
+            </p>
+<pre class="code-block">
+# umount -R /mnt
+</pre>
+        </li>
+        <li>
+           <p>
+           Zamknięcie szyfrowanego woluminu.
+           </p>
+<pre class="code-block">
+# cryptsetup close cryptroot
+</pre>
+        </li>
+        <li>
+            <p>
+            Zakończenie instalacji, restart systemu.
+            </p>
+<pre class="code-block">
+# reboot
+</pre>
+        </li>
+    </ol>
+    <p>
+    ~xf0r3m
+    </p>
+       </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/linux/szyfrowany_rootfs_na_greenOSTe.html b/articles/linux/szyfrowany_rootfs_na_greenOSTe.html
new file mode 100755 (executable)
index 0000000..bfb0f01
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">Szyfrowany rootfs na greenOSTe</h1>
+    <p>
+      Chcąc przetestować <em>greenOSTe</em> na starym laptopie z Core2Duo 
+      stwierdziłem, że jeśli ma być to hackerska instalacja to dysk powinien 
+      być
+      szyfrowany. Z racji tego, że Trisquel jest oparty na Ubuntu, a Ubuntu na
+      Debianie, to może zadziała sposób wykorzystywany przy <em>greenOS</em>.
+      Niestety, nie. Podczas bootowania
+      właściwego systemu nie zostaliśmy zapytani o hasło, a system zatrzymywał
+      się przy próbie montowania głownego systemu plików, którego nie było bo 
+      dysk
+      nie został odszyfrowany. Program typu init przerwał ładowanie systemu
+      zrzucając tym samym powłokę <em>BusyBox</em> obrazu <em>initramfs</em>.
+    </p>
+    <p>
+      Problem leżał w tym, że do archiwum <em>initramfs</em>, nie został
+      skopiowany program <strong>cryptsetup</strong> mimo iż instalator pakietu
+      aktualizował to archiwum. Niezbędne jest również dopisanie
+      dwóch dodatkowych opcji w pliku <em>/etc/crypttab</em>. Najpierw musimy 
+      wymusić załadowanie programu <em>cryptsetup</em> do archiwum. W pliku
+      <em>/usr/share/initramfs-tools/conf-hooks.d/forcecryptsetup</em> 
+      zapisujemy poniższą linię:
+    </p>
+<pre class="code-block">
+export CRYPTSETUP=y
+</pre>
+    <p>
+      Teraz należy zaktualizować archiwum z <em>initramfs</em>, przy czym
+      zapiszemy zwracane przez polecenie informacje do pliku, dzięki czemu
+      będzie mogli się upewnić że program <em>cryptsetup</em> został
+      rzeczywiście dodany do archiwum.
+    </p>
+<pre class="code-block">
+# update-initramfs -c -k all -v &gt; ~/upd-initramfs.log
+# cat ~/upd-initramfs.log | grep "crypt"
+</pre>
+    <p>
+      Na wyściu drugiego polecenia należy szukać ścieżki
+      <strong>/sbin/cryptsetup</strong>, powinna być oznaczona komunikatem
+      <em>Adding binary</em>. Teraz możemy przejść do utworzenia
+      odpowiedniego wpisu w pliku <em>/etc/crypttab</em>. Podobnie jak w
+      materiale dotyczącym <em>greenOS</em>, jednak obecny wpis różni się od
+      poprzedniego materiału o podobnej tematyce. Ma dwie dodatkowe opcje 
+      oraz UUID nie może znajdować się między cudzysłowami. UUID najlepiej 
+      pobrać za pomocą powyższego polecenia:
+    </p>
+<pre class="code-block">
+# blkid | grep "LUKS" | awk '{printf $2}' &gt;&gt; /etc/crypttab
+</pre>
+    <p>
+      Z kolei wpis w pliku <em>/etc/crypttab</em> wygląda w następujący sposób
+    </p> 
+<pre class="code-block">
+cryptroot UUID=...  none  nofail,luks,initramfs
+</pre>
+    <p>
+      Po zapisaniu zmian, należy ponownie zaktualizować <em>initramfs</em> oraz
+      upewnić się <em>cryptsetup</em> nadal tam jest.
+    </p>
+<pre class="code-block">
+# update-initramfs -c -k all -v &gt; ~/upd-initramfs.log
+</pre>
+    <p>
+      Po wykonaniu tych czynności możemy powrócić do pozostałych standardowych
+      czynności instalacyjnych. <strong>Uwaga!</strong> po każdym
+      aktualizowaniu <em>initramfs</em>, należy jeszcze raz go zaktualizować
+      tak jak robiliśmy to w tym materiale, ponieważ może okazać się, że 
+      <em>cryptsetup</em> zostało usunięte z archiwum, co spowoduje
+      unieruchomienie systemu po restarcie.
+    </p>
+    <p>
+      Źródło:
+    </p>
+    <ol>
+      <li><a href="https://gist.github.com/gvtulder/881e9cce73758339bd25937c254f7960">Github Gist: gvtulder/encrypting-without-reinstalling-ubuntu.txt</a></li>
+    </ol>
+    <p>
+    ~xf0r3m
+    </p>
+       </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+
+       </body>
+</html>
diff --git a/articles/linux/tworzenie_RAID_programowych_w_systemach_GNU_Linux.html b/articles/linux/tworzenie_RAID_programowych_w_systemach_GNU_Linux.html
new file mode 100644 (file)
index 0000000..21014a4
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Tworzenie RAID programowych w systemach GNU/Linux</h1>
+    <p>
+      <strong>RAID programowe</strong> są innym sposóbem na zarządzanie dyskami na systemach GNU/Linux. Dzięki temu rozwiązaniu nie musimy już kupować drogich dedykowanych kontrolerów do naszego budżetowego serwera. Oprogramowanie odpowiedzialne za konfigurowanie RAID wspiera wszystkie powszechnie używane poziomy 0,1,5,6,0+1,1+0.
+    </p>
+    <p>
+      Każdy dysk musi mieć partycję typu <em>Linux raid autodetect</em>, więc za pomocą polecenia <em>fdisk</em>, utworzymy je, poniżej znajduje się kolejność wciskanych klawiszy podczas pracy z programem.
+    </p>
+<pre class="code-block">
+$ sudo fdisk /dev/sdb
+> o
+> n
+> p
+> [ENTER]
+> [ENTER]
+> [ENTER]
+> t
+> fd
+> w
+> quit
+</pre>
+    <p>
+      Powtarzamy to na wszystkich dyskach budujących tablicę. Kiedy skończymy przechodzimy do tworzenia tablicy RAID wykorzystujemy polecenie <em>mdadm</em>. Dla swoich dysków wybrałem RAID 1.
+    </p>
+<pre class="code-block">
+$ sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
+</pre>
+    <p>
+      <ul>
+        <li><code class="code-inline">--create</code> - nazwa urządzenia RAID identyfikująca je w systemie,</li>
+        <li><code class="code-inline">--level=1</code> - poziom RAID wykorzystany w tablicy,</li>
+        <li><code class="code-inline">--raid-devices</code> - liczba dysków użyta do stworzenia RAID</li>
+        <li><code class="code-inline">/dev/sdb1 /deb/sdc1</code> - partycje uzyte w RAID.</li>
+      </ul>
+      Po wykonaniu tego polecenia w systemie zostanie utworzone pusty dysk pod nazwa, którą podaliśmy w wartości opcji <code class="code-inline">--create</code>. Aby korzystać z RAID musimy utworzyć na nim partycję i ją sformatować.
+    </p>
+<pre class="code-block">
+$ sudo fdisk /dev/md0
+> o
+> n
+> p
+> [ENTER]
+> [ENTER]
+> [ENTER]
+> w
+> quit
+$ sudo mkfs.ext4 /dev/md0p1
+</pre>
+    <p>
+      Do utworzenia partycji, użyłem programu fdisk z tą samą sekwencją poleceń jakiej używam do tworzenia partycji na klasycznych dyskach. Za pomocą tego samego polecenia z przełącznikem <code class="code-inline">-l</code>, możemy sprawdzić numer naszej partycji, którą przygotowujemy do działania ostatnim poleceniem z powyższego przykładu. Teraz możemy nasze urządzenie RAID pod montować w systemie.
+    </p>
+<pre class="code-block">
+$ sudo mount /dev/md0p1 /mnt
+</pre>
+    <p>
+      Użycie programowych tablic RAID to dobre rozwiązanie kiedy potrzebujemy na zwykłej stacji roboczej RAID 1, a nie posiada ona żadnych fizycznych mechanizmów tworzenia takich tablic, a kontroler może być poza naszym zasięgiem z różnych przyczyn.
+    </p>
+    <p>
+        ~xf0r3m
+    </p>
+  </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+</body>
+</html>
diff --git a/articles/linux/tworzenie_logicznych_woluminów_LVM.html b/articles/linux/tworzenie_logicznych_woluminów_LVM.html
new file mode 100644 (file)
index 0000000..217c7c3
--- /dev/null
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Tworzenie woluminów logicznych - LVM</h1>
+    <p>
+      Czasami może zajść taka przeba że trzeba wykorzystać dwa fizyczne dyski, jednak nie w taki prosty sposób jakby się mogło wydawać. Na dyskach będzie przechowywane bardzo dużo danych i te dane muszą być w jednym katalogu ale nie zmieszczą się na jednym dysku. Opcje są dwie, oddać te zakupione dyski do sklepu i kupić większe o ile dyski są nowe lub podłączyć je do serwera i konfigurować na nich <strong>wolumin logiczny</strong>.
+    </p>
+    <p>
+      Tworzenie woluminu rozpoczniemy i klasycznego zainicjowania dysków utworzymy partycję na całej długości dysku. Do zaalokowania miejsca wykorzystamy narzędzie <em>fdisk</em>. Przedstawię poniżej kolejno wciskane klawisze podczas obsługi programu.
+    </p>
+<pre class="code-block">
+$ sudo fdisk /dev/sdb
+> o
+> n
+> p
+> [ENTER]
+> [ENTER]
+> [ENTER]
+> w
+> quit
+</pre>
+    <p>
+      Dla drugiego dysku wykonujemy identyczne czynności. Po zainicjowaniu dysków możemy przejść do programu <em>lvm</em> i rozpocząć inicjowanie woluminu logicznego.
+    </p>
+<pre class="code-block">
+$ sudo lvm
+lvm> pvcreate /dev/sdb1
+lvm> pvcreate /dev/sdc1
+</pre>
+    <p>
+      Po wydaniu tych poleceń, partycje na dyskach są gotowe do stworzenia <strong>grupy woluminów</strong>. Grupę tworzymy następującym poleceniem programu.
+    </p>
+<pre class="code-block">
+lvm> vgcreate vg0 /dev/sdb1 /dev/sdc1
+</pre>
+    <p>
+      Teraz dyski są połączone logicznie. Utworzymy na nich nasz wolumin logiczny.
+    </p>
+<pre class="code-block">
+lvm> lvcreate -L 931G vg0
+lvm> exit
+</pre>
+    <p>
+      Utworzyłem <strong>dysk logiczny</strong> składający się z dwóch dysków fizycznych, użyłem dwóch dysków o wielkości 500GB nominalnie co dało w rzeczywistości 465,5G miejsca na partycji. Dysk logiczny ma 931G rozmiaru rzeczywistego co nominalnie daje 1TB. Podczas działania lvm wszystkie polecenia są wykonywane na bierząco, więc po utworzeniu dysku możemy wpisać poprostu <code class="code-inline">exit</code>.
+    </p>
+    <p>
+      Po zamknięciu programu, kiedy wyświetlimy listę wszystkich dysków w systemie za pomoca polecenia <code class="code-inline">fdisk -l</code> nasz dysk logiczny będzie widoczny jako pusty dysk bez partycji o ścieżce wystąpienia takiej jak <code class="code-inline">/dev/mapper/vg0-lvol0</code>. Na tym dysku nie tworzymy partycji, od razu przechodzimy do formatowania.
+    </p>
+<pre class="code-block">
+$ sudo mkfs.ext4 /dev/mapper/vg0-lvol0
+</pre>
+    <p>
+      Teraz możemy montować nasz wolumin i rozpocząć z nim pracę.
+    </p>
+<pre class="code-block">
+$ sudo mount /dev/mapper/vg0-lvol0 /mnt
+</pre>
+    <p>
+       Woluminy logiczne są świetnym rozwiązaniem dla tych którzy mają mniejsze dyski fizyczne a potrzebują więcej miejsca niż te urządzenia mogą zaoferować.
+    </p>
+    <p>
+        ~xf0r3m
+    </p>
+  </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+</body>
+</html>
diff --git a/articles/linux/uruchomienie_skryptu_podczas_ładowania_systemu_-_jednostka_systemd.html b/articles/linux/uruchomienie_skryptu_podczas_ładowania_systemu_-_jednostka_systemd.html
new file mode 100644 (file)
index 0000000..2aa2e9a
--- /dev/null
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body style="font-family: monospace;" >
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+               <h1 class="title">Uruchominie skryptu podczas ładowania systemu - jednostka systemd</h1>
+    <p>
+      Wykonanie skryptu w trakcie uruchamiania systemu, do bardzo stary
+      problem wielu administratorów oraz entuzjastów systemu Linuks. Wraz ze
+      zmianianą <em>mainstreamowego</em> programu typu <em>init</em> problem
+      ten stał się wręcz trywialny, bo można użyć jednostki <em>systemd</em>,
+      jednak nie którzy nie więdzą jak się do tego zabrać.
+    </p>
+    <p>
+      Każda jednostka <em>systemd</em> to plik tekstowy składający się z
+      minimum dwóch sekcji. Pierwszą z nich jest sekcja <em>Unit</em> opisująca
+      jednostkę. W wewnątrz niej mogą znajdować się takie informacje jak opis,
+      kiedy ma zostać uruchomiona oraz jej ewentualne zależności. Druga
+      sekcja jest już zależna od jednostki. Wśród jedenastu typów jednostek
+      najbardziej odpowiednim jest jednostka usługi, ponieważ
+      odpowiada ona poniękąd za uruchomienie programu, a tym w mniejszym lub
+      większym stopniu jest nasz skrypt. W sekcji jednostki znajdują się
+      dyrektywy są specyficzne dla tego typu jednostki. Opcjonalnie w pliku
+      jednostki może znaleźć się sekcja <em>Install</em>, w której deklaruje
+      się zależności wsteczne (inna jednostka może wymagać lub chcieć aktywacji
+      tej jednostki podczas swojej aktywacji). Zależności wsteczne pozwalają
+      na włączenie lub wyłączenie aktywacji jednostki w systemie.
+    </p>
+    <p>
+      Po scharakteryzowaniu pliku jednostki możemy przejść ustalania 
+      potrzebnych
+      dyrektyw budując pliki jednostki. W sekcji <em>Unit</em> na pewno
+      powinna znaleźć się dyrektywa <em>Description</em>, w której zawierany
+      jest krótki opis jednostki. Jest on wyświetlany podczas uruchamiania
+      jednostki w trakcie uruchamiania systemu. Za pewne chcielibyśmy aby
+      skrypt był uruchamiany w takim samym środowisku jak byś uruchamiali go
+      z poziomu wiersza polecenia, zatem należy opóźnić aktywacje jak tylko się
+      da. Do tego posłuży nam dyrektywa <em>After</em>, która wskazuje
+      <em>systemd</em> aby aktywował jednostkę <strong>po</strong> aktywacji
+      jednostki zapisanej w tej dyrektywie. Najpóźniej aktywowaną jednostką
+      w dystrybucjach Linuksa opartych o <em>systemd</em> jest
+      <em>default.target</em>, po aktywacji której zazwyczaj uznaje się, że
+      system jest już gotowy do pracy. Ta jednostka jest dowiązaniem
+      symbolicznym do innej właściwej dla konfiguracji systemu jednostki.
+      Następnie już w sekcji <em>Service</em>, za pomocą
+      dyrektywy <em>ExecStart</em> wskazujemy ścieżkę do pliku skryptu, w tym
+      przypadku jest to jedyna dyrektywa w tej sekcji. Abyśmy mogli włączać i
+      wyłączać jednostkę powinniśmy dodać także sekcje <em>Install</em> a 
+      wewntąrz niej zależność zwrotną typu <em>WantedBy</em> wskazującą również
+      na <em>default.target</em>. Spowoduje to automatyczne uruchomienie
+      tej jednostki w momencie uruchomienia celu <em>default.target</em>, z
+      opóźnieniem wynikającym z dyrektywy <em>After</em>. Zależność typu
+      <em>WantedBy</em>, nie spowoduje problemów z jednostką 
+      <em>default.target</em> gdy uruchomienie jednostki ze skryptem
+      nie powiedzie się. Zawartość pliku jednostki powinna wyglądać mniej
+      więcej jak na poniższym przykładzie.
+    </p>
+<pre class="code-block">
+xf0r3m@wyse3040:~$ cat /etc/systemd/system/ssh_tunnel.service 
+[Unit]
+Description=SSH Tunnel for remote access
+After=default.target
+[Service]
+ExecStart=/home/xf0r3m/tunnel.sh
+[Install]
+WantedBy=default.target
+</pre>
+    <p>
+      W moim przypadku jest to skrypt który uruchamia tunel SSH z 
+      przekazywaniem
+      portów oraz zajmuję się jego utrzymaniem. Zwróćmy uwagę na lokalizacje
+      pliku jednostki. Jest ona jak najbardziej odpowiednia. Po utworzeniu
+      pliku możemy, przystąpić do włączenia jednostki w celu 
+      <em>default.target</em>.
+    </p>
+<pre class="code-block">
+xf0r3m@wyse3040:~$ sudo systemctl enable ssh_tunnel.service
+</pre>
+    <p>
+      Po jej włączeniu możemy ją aktywować.
+    </p>
+<pre class="code-block">
+xf0r3m@wyse3040:~$ sudo systemctl start ssh_tunnel.service
+</pre>
+    <p>
+      Za pomocą podpolecenia <em>status</em> polecenia <em>systemctl</em>
+      możemy sprawdzić stan uruchomionej jednostki.
+    </p>
+<pre class="code-block">
+      xf0r3m@wyse3040:~$ sudo systemctl status ssh_tunnel.service 
+● ssh_tunnel.service - SSH Tunnel for remote access
+     Loaded: loaded (/etc/systemd/system/ssh_tunnel.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-24 10:12:42 CEST; 2s ago
+   Main PID: 1246 (tunnel.sh)
+      Tasks: 2 (limit: 2235)
+     Memory: 1.2M
+        CPU: 164ms
+     CGroup: /system.slice/ssh_tunnel.service
+             ├─1246 /bin/bash /home/xf0r3m/tunnel.sh
+             └─1247 ssh -p 2022 -i /home/xf0r3m/.ssh/id_rsa -o StrictHostKeyChecking=no xf0r3m@... -R ...:127.0.0.1:22 while [ true ...
+
+lip 24 10:12:42 wyse3040 systemd[1]: Started SSH Tunnel for remote access.
+</pre>
+    <p>
+      Oczywiście statusy nie wszystkich jednostek, które uruchamiają skrypty
+      będą wyglądać tak samo, nie które z nich mogą się dezaktywować się po
+      zakończeniu działania skryptu. Moj skrypt działa ponieważ jego trzonem
+      jest nieskończona pętla, która sprawia, że jeśli dojdzie do zerwania
+      tunelu, zostanie on za 30 sekund zestawiony ponownie.
+    </p>
+    <p>
+      Źródła:
+    </p>
+    <ol>
+      <li><a href="https://linuxhint.com/run-script-debian-11-boot-up/">How to Run Script on Boot Up in Debian 11</a></li>
+    </ol>
+               <p>
+                       ~xf0r3m
+               </p>
+    </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+       </body>
+</html>
diff --git a/articles/linux/własne_LiveCD_z_Debianem.html b/articles/linux/własne_LiveCD_z_Debianem.html
new file mode 100644 (file)
index 0000000..55c3dd0
--- /dev/null
@@ -0,0 +1,349 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+<pre>
+  _____ _   _ _    _    ___      _
+ / ____| \ | | |  | |  / / |    (_)
+| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
+| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
+| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
+ \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\
+</pre>
+         <p class="header_link" >
+                 &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+         </p>
+         <div class="main">
+      <h1 class="title">Własne LiveCD z GNU/Linux Debian</h1>
+      <p>
+        Czasami może zadarzyć się taka sytuacja, że będziemy korzystać z wielu
+        różnych maszyn co jakiś czas. Jak pewnie zdajemy sobie sprawę z tego
+        ile czasu trzeba poświęcić na zainstalowanie systemu i przygotowanie go
+        do pracy, to w tym przypadku najlepiej jest przygotować LiveCD z
+        niezbędnymi programami oraz lekkim środowiskiem graficznym, aby
+        można było korzystać z niego nawet na starym sprzęcie. Jeśli chodzi o
+        dane, to najlepiej użyć SSHFS.
+      </p>
+      <p>
+        Wszystkie polecenia tutaj są wykonywane z poziomu użytkownika
+        <strong>root</strong> oraz w jego katalogu domowym, bezpośrednio z
+        terminala docelowego komputera. Jeśli mamy zamiar tworzyć obraz z
+        na serwerze to należy pamiętać aby robić to bezpośredio przez SSH
+        i nie używać programów typu <em>tmux</em> oraz <em>GNU Screen</em>,
+        ponieważ mogą wystąpić problemy podczas pobierania obrazu dystrybucji
+        z repozytorium.
+      </p>
+      <p>
+        Tworzenie LiveCD rozpoczniemy od zainstalowania odpowiedniego
+        oprogramowania.
+      </p>
+<pre class="code-block">
+# apt install debootstrap squashfs-tools xorriso isolinux syslinux-efi grub-pc-bin grub-efi-amd64-bin grub-efi-ia32-bin mtools
+</pre>
+      <p>
+        Po zainstalowaniu oprogramowania tworzymy katalog dla zachowania
+        porządku.
+      </p>
+<pre class="code-block">
+# mkdir debianCustomLiveCD
+</pre>
+      <p>
+        Teraz możemy pobrać obraz dystrybucji, dla zredukowania wielkości
+        należy wybrać wariant <strong>minbase</strong>.
+      </p>
+<pre class="code-block">
+# /sbin/debootstrap --arch=amd64 --variant=minbase bullseye /root/debianCustomLiveCD/chroot http://ftp.icm.edu.pl/debian
+</pre>
+      <p>
+        Następnie dokonujemy zmian na obrazie, nie które zmiany są niezbędny do
+        prawidłowego funkcjonowania systemu, inne są opcjonalne. Aby dokonać
+        zmian należy zmienić katalog główny na katalog obrazu.
+      </p> 
+<pre class="code-block">
+# chroot /root/debianCustomLiveCD/chroot /bin/bash
+</pre>
+      <p>
+        W tym momencie wszystkie czynności będą wykonywane wewnątrz obrazu nie
+        na prawdziwym systemie, dlatego też warto zaznaczyć sobie, że pracujemy
+        na zmienionym katalogu głównym.
+      </p>
+<pre class="code-block">
+# export PS1="(chroot) ${PS1}"
+</pre>
+      <p>
+        Odświerzamy listy pakietów na obrazie.
+      </p>
+<pre class="code-block">
+(chroot) # apt update
+</pre>
+      <p>
+        Instalujemy jądro, proces systemd oraz pakiet live-boot
+      </p>
+<pre class="code-block">
+(chroot) # apt install -y --no-install-recommends linux-image-amd64 live-boot systemd-sysv
+</pre>
+      <p>
+        Instalujemy wszystkie potrzebne nam programy. W tym podpunkcie zapisze
+        tylko te, które raczej powinny znaleźć się na obrazie aby można było
+        normalnie z niego korzystać.
+      </p>
+<pre class="code-block">
+(chroot) # apt install -y network-manager net-tools wireless-tools wpagui wget openssh-client blackbox xserver-xorg-core xserver-xorg xinit xterm vim
+</pre>
+      <p>
+        Po instalacji oprogramowania usuwamy pobrane pakiety, przez co obraz
+        będzie lżejszy.
+      </p>
+<pre class="code-block">
+# apt-get clean
+</pre>
+      <p>
+        Jak widać na powyższym przykładzie instalowany będzie menedżer okien
+        <em>BlackBox</em>, jednak nic nie stoi na przeszkodzie by zainstalować
+        dowolny inny. Po instalacji pakietów pozostanie jeszcze zmiana
+        hasła dla użytkownika <em>root</em>, aby można było się na jakiegoś
+        użytkownika zalogować.
+      </p>
+<pre class="code-block">
+(chroot) # passwd
+</pre>
+      <p>
+        <strong>Pozostałe konfiguracje są opcjonalne</strong>. Mają za zadanie 
+        jedynie
+        ustawienie polskiej lokalizacji. Nie będę opisywać każdej konfiguracji
+        krok po kroku, potrzebne opcję są dobrze opisane i łatwo jest się w 
+        nich połapać.
+      </p>
+<pre class="code-block">
+(chroot) # dpkg-reconfigure tzdata
+(chroot) # apt install locales
+(chroot) # dpkg-reconfigure locales
+(chroot) # apt install keyboard-configration console-setup 
+</pre>
+      <p>
+        Opuszczamy obraz.
+      </p>
+<pre class="code-block">
+(chroot) # exit
+</pre>
+      <p>
+        Tworzymy strukturę katalogową, która będzie potrzebna do utworzenia
+        obrazu. W zależności od tego dla jakiego systemu EFI (64 czy 32-bitowe)
+        będziemy tworzyć obraz wydajemy odpowiednie polecenie:
+      </p>
+      <p>
+        <u>64-bit EFI</u>
+      </p>
+<pre class="code-block">
+# mkdir -p /root/customDebianLiveCD/{staging/{EFI/boot,boot/grub/x86_64-efi,isolinux,live},tmp}
+</pre>
+      <p>
+        <u>32-bit EFI</u>
+      </p>
+<pre class="code-block">
+# mkdir -p /root/customDebianLiveCD/{staging/{EFI/boot,boot/grub/i386-efi,isolinux,live},tmp}
+</pre>
+      <p>
+        Na obrazach LiveCD, główny system plików znajduje się w pliku 
+        <em>squashfs</em>
+        i taki teraz utworzymy. Tworzenie pliku trochę trwa w zależności od
+        mocy obliczniowej maszyny.
+      </p>
+<pre class="code-block">
+# mksquashfs /root/customDebianLiveCD/chroot /root/customDebianLiveCD/staging/live/filesystem.squashfs -e boot
+</pre>
+      <p>
+        Do uruchomienia systemu potrzebne będzie jądro oraz plik ramdysku.
+        Możemy je przekopiować z pobranego wcześniej obrazu dystrybucji.
+      </p>
+<pre class="code-block">
+# cp /root/customDebianLiveCD/chroot/boot/vmlinuz-* /root/customDebianLiveCD/staging/live/vmlinuz
+# cp /root/customDebianLiveCD/chroot/boot/initrd.img-* /root/customDebianLiveCD/staging/live/initrd
+</pre>
+      <p>
+        System do bootowania w trybie BIOS, bedzie wykorzystywać program
+        <em>isolinux</em>, teraz stworzymy dla niego plik konfiguracyjny
+        <em>isolinux.cfg</em>.
+        Plik zapisujemy w katalogu
+         <em>/root/customDebianLiveCD/staging/isolinux</em>.
+      </p>
+<pre class="code-block">
+UI vesamenu.c32
+
+MENU TITLE Boot Menu
+DEFAULT linux
+TIMEOUT 600
+MENU RESOLUTION 640 480
+MENU COLOR border       30;44   #40ffffff #a0000000 std
+MENU COLOR title        1;36;44 #9033ccff #a0000000 std
+MENU COLOR sel          7;37;40 #e0ffffff #20ffffff all
+MENU COLOR unsel        37;44   #50ffffff #a0000000 std
+MENU COLOR help         37;40   #c0ffffff #a0000000 std
+MENU COLOR timeout_msg  37;40   #80ffffff #00000000 std
+MENU COLOR timeout      1;37;40 #c0ffffff #00000000 std
+MENU COLOR msg07        37;40   #90ffffff #a0000000 std
+MENU COLOR tabmsg       31;40   #30ffffff #00000000 std
+
+LABEL linux
+  MENU LABEL Custom Debian Live [BIOS/ISOLINUX]
+  MENU DEFAULT
+  KERNEL /live/vmlinuz
+  APPEND initrd=/live/initrd boot=live
+
+LABEL linux
+  MENU LABEL Custom Debian Live [BIOS/ISOLINUX] (nomodeset)
+  MENU DEFAULT
+  KERNEL /live/vmlinuz
+  APPEND initrd=/live/initrd boot=live nomodeset
+</pre>
+      <p>
+        Program ładującym dla EFI jest GRUB, poniżej znajduje się jego plik 
+        konfiguracyjny <em>grub.cfg</em>. Plik zapisujemy w katalogu
+        <em>/root/customDebianLiveCD/staging/boot/grub</em>. Aby GRUB
+        prawidłowo wyświetlał komunikaty jądra podczas ładowania systemu
+        potrzebny jest jeszcze jeden plik (<em>font.pf2</em>), który 
+        umieszczamy w tym samym katalogu. Plik możemy wyodrębnić z płyty
+        LiveCD Debiana lub z archiwum dostępnego pod tym linkiem:
+             <a href="https://github.com/xf0r3m/greenOS/icewm-era/blob/main/greenOS_boot-cfg.tgz">https://github.com/xf0r3m/greenOS/icewm-era/blob/main/greenOS_boot-cfg.tgz</a>
+     </p>   
+<pre class="code-block">
+if loadfont $prefix/font.pf2 ; then
+       set gfxmode=800x600
+       set gfxpayload=keep
+       insmod efi_gop
+       insmod efi_uga
+       insmod video_bochs
+       insmod video_cirrcus
+       insmod gfxterm
+       terminal_output gfxterm
+fi
+
+search --set=root --file /DEBIAN_CUSTOM
+
+set default="0"
+set timeout=30
+
+
+menuentry "Debian Live [EFI/GRUB]" {
+    linux ($root)/live/vmlinuz boot=live
+    initrd ($root)/live/initrd
+}
+
+menuentry "Debian Live [EFI/GRUB] (nomodeset)" {
+    linux ($root)/live/vmlinuz boot=live nomodeset
+    initrd ($root)/live/initrd
+}
+</pre>
+      <p>
+        Podczas instalacji GRUB-a, program instalujący będzie
+        potrzebował pliku, w którym zawarte są informacje o prefiksie
+        wykorzystywanym przez plik konfiguracji oraz o położeniu pliku
+        konfiguracyjnego. Plik <em>grub-standalone.cfg</em> zapisujemy w 
+        katalogu <em>/root/customDebianLiveCD/tmp</em>.
+      </p>
+<pre class="code-block">
+search --set=root --file /DEBIAN_CUSTOM
+set prefix=($root)/boot/grub/
+configfile /boot/grub/grub.cfg
+</pre>
+      <p>
+        Następnym krokiem jest utworzenie pliku, po którym GRUB uzna ten dysk
+        jako główny (<em>root</em>) dla ładowania tego systemu.
+      </p>
+<pre class="code-block">
+# touch /root/customDebianLiveCD/staging/DEBIAN_CUSTOM
+</pre>
+      <p>
+        Po utworzeniu pliku, należy przekopiować resztę plików <em>isolinux</em>.
+      </p>
+<pre class="code-block">
+# cp /usr/lib/ISOLINUX/isolinux.bin /root/customDebianLiveCD/staging/isolinux
+# cp /usr/lib/syslinux/modules/bios/* /root/greenOS/staging/isolinux
+</pre>
+      <p>
+        Pozostałe pliku GRUB, również należy przekopiować do katalogów obrazu.
+      </p>
+      <p><u>64-bit EFI</u></p>
+<pre class="code-block">
+# cp -r /usr/lib/grub/x86_64-efi/* /root/customDebianLiveCD/staging/boot/grub/x86_64-efi
+</pre>
+      <p><u>32-bit EFI</u></p>
+<pre class="code-block">
+# cp -r /usr/lib/grub/i386-efi/* /root/customDebianLiveCD/staging/boot/grub/i386-efi
+</pre>
+      <p>
+        Aby komputer wykorzystujący tryb UEFI mogł zbootować nasz obraz
+        potrzebny jest plik binarny programu ładującego, który teraz utworzymy
+      </p>
+      <p><u>64-bit EFI</u></p>
+<pre class="code-block">
+# grub-mkstandalone --format=x86_64-efi --output=/root/customDebianLiveCD/staging/EFI/boot/bootx64.efi --locales="" --fonts="" \ 
+"/boot/grub/boot.cfg=/root/customDebianLiveCD/tmp/grub-standalone.cfg"
+</pre>
+      <p><u>32-bit EFI</u></p>
+<pre class="code-block">
+# grub-mkstandalone --format=i386-efi --output=/root/customDebianLiveCD/staging/EFI/boot/bootia32.efi --locales="" --fonts="" \
+"/boot/grub/boot.cfg=/root/customDebianLiveCD/tmp/grub-standalone.cfg"
+</pre>
+      <p>
+        Wszystkie bootowalne obrazy LiveCD obsługujące UEFI posiadają
+        dodatkową partycję, to właśnie wniej będzie znajdować się utworzony
+        wcześniej plik bootloadera, i to jej będzie poszukiwać oprogramowanie
+        układowe podczas uruchamiania komputera z obrazu. Utworzenie i
+        skopiowanie danych będzie wymagać kilku czynności.
+      </p>
+      <p><u>64-bit EFI</u></p>
+<pre class="code-block">
+# cd /root/customDebianLiveCD/staging/boot/grub/
+# dd if=/dev/zero of=efiboot.img bs=1M count=20
+# mkfs.vfat efiboot.img
+# mmd -i efiboot.img efi efi/boot
+# mcopy -vi efiboot.img /root/customDebianLiveCD/staging/EFI/boot/bootx64.efi ::efi/boot
+</pre>
+      <p><u>32-bit EFI</u></p>
+<pre class="code-block">
+# cd /root/customDebianLiveCD/staging/boot/grub/
+# dd if=/dev/zero of=efiboot.img bs=1M count=20
+# mkfs.vfat efiboot.img
+# mmd -i efiboot.img efi efi/boot
+# mcopy -vi efiboot.img /root/customDebianLiveCD/staging/EFI/boot/bootia32.efi ::efi/boot
+</pre>
+      <p>
+        Kiedy mamy już utworzoną partycję. Przyszedł czas na wygenerowanie
+        właściwego obrazu płyty. W tym poleceniu będzie zawarte użycie 
+        <em>isolinux</em>, użycie alternatywnego bootloadera dla trybu EFI,
+        dołączona zostanie również partycja EFI.
+      </p>
+<pre class="code-block">
+# xorriso -as mkisofs -iso-level 3 -o "custom_debian.iso" -full-iso9660-filenames -volid "CUSTOM_DEBIAN" \ 
+-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-boot isolinux/isolinux.bin -no-emul-boot \
+-boot-load-size 4 -boot-info-table --eltorito-catalog isolinux/isolinux.cat-eltorito-alt-boot -e /boot/grub/efiboot.img -no-emul-boot \ 
+-isohybrid-gpt-basdat -append_partition 2 0xef /root/customDebianLiveCD/staging/boot/grub/efiboot.img "/root/customDebianLiveCD/staging"
+</pre>
+      <p>
+        Tak wygenerowany obraz możemy śmiało załadować na pendrive-a lub
+        wypalić na płycie i uruchomić na dowolnym (64-bitowym) komputerze. 
+        Mimo iż
+        przedstawiono tutaj wsparcie dla 32-bitowego EFI, to obraz jest będzie
+        64-bitowy. 32-bitowy obraz należało by wykonać na 32-bitowym systemie
+        operacyjnym, podczas pobierania obrazu trzeba by wybrać architekturę
+        32-bitową (<em>i386</em>), oraz podczas konfiguracji obrazu wybrać
+        odpowiedni pakiet jądra (<em>linux-image-686</em>).
+      </p>
+      <p>
+        Źródło: <a href="https://willhaley.com/blog/custom-debian-live-environment/">
+          https://willhaley.com/blog/custom-debian-live-environment/</a><br />
+      </p>
+      <p>
+         ~xf0r3m
+      </p>
+    </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+  </body>
+</html>
diff --git a/articles/raspberrypi/Raspberry_Pi_Zero_jako_router_3G.html b/articles/raspberrypi/Raspberry_Pi_Zero_jako_router_3G.html
new file mode 100644 (file)
index 0000000..15c63ad
--- /dev/null
@@ -0,0 +1,317 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Raspberry Pi Zero jako router 3G</h1>
+    <p>
+      Pomysł na to zrodził się w mojej głowie, kiedy szykowałem się do swojej pierwszej zagranicznej wycieczki, pandemia wszystko pokrzyżowała a projekt został. Jednak bez obudowy oraz schematu połączeń jest on jedynie systemem naczyń połączonych.
+    </p>
+    <ol>
+      <li><strong>Przygotowanie sprzętu.</strong>
+        <p>
+        <ul>
+          <li>Raspberry Pi Zero W,</li>
+          <li>Modem 3G (w moim przypadku użyłem Huawei E173s-2 [pełny model znajduje się pod klapką]),</li>
+          <li>Oficjalna klawiatura Raspberry Pi lub hub USB i zwykła klawiatura,</li>
+          <li>Karta sieciowa USB (JP1082 - niebieska, tania karta z allegro za 10 czy 20 zł),</li>
+          <li>Zasilacz,</li>
+          <li>Karta microSD z systemem (RasPiOS Lite),</li>
+          <li>Karta SIM z pakietem danych komórkowych, dedykowanego operatora dla modemu lub dowolnego jeśli modem nie posiada blokady simlock,</li>
+          <li>Adapter mini-HDMI,</li>
+          <li>Kabel OTG do podłączenia klawiatury lub huba,</li>
+          <li>Kabel do podłączenia RPI do Internetu.</li>
+        </ul>
+        </p>
+      </li>
+      <li><strong>Początkowa konfiguracja RPI oraz aktualizacja.</strong>
+        <p>
+          Uruchamiamy Raspberry Pi, następnie zmieniamy layout klawiatury na polski za pomocą narzędzia <code class="code-inline">raspi-config</code>. Wydajemy następujące polecenie:
+        </p>
+<pre class="code-block">
+$ sudo raspi-config
+</pre>
+        <p>
+          Z menu głównego programu wybieramy, kolejno <code class="code-inline">4. Localisation Options</code> -> <code class="code-inline">Change Keyboard Layout</code>, jeśli nie wyświetli nam się nic, skrypt poprostu wróci do menu, oznacza to że musimy przełączyć jeszcze <em>locale</em>, po ustawieniu ich na język polski, będziemy mogli zmienić layout klawiatury. <em>Locale</em> ustawia się z tej samej sekcji <code class="code-inline">4. Localisation Options</code> -> <code class="code-inline">Change Locale</code>, poźniej z długiej listy odznaczamy <code class="code-inline">en_GB</code> zaznaczamy <code class="code-inline">pl_PL</code> w wersji UTF-8.
+                                       Po ustawieniu <em>locale</em> oraz layoutu klawiatury należy zrestartować malinę, co sam będzie sugerować sam program. Po ponownym uruchomieniu urządzenia, możemy teraz przejść do aktualizacji wydajemy dwa następujące polecenia:
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+        <p>
+          Po zaktualizowaniu systemu możemy przejść do obsługi modemu 3G.
+        </p>
+      </li>
+      <li><strong>Modem.</strong>
+        <p>
+          Podpinamy modem do gniazda usb. Po wydaniu polecenia:
+        </p>
+<pre class="code-block">
+$ lsusb
+</pre>
+        <p>
+          (w moim przypadku) powinniśmy zobaczyć linię zawierającą napis <code class="code-inline">Huawei ...</code>, może on się nieco różnić. Przed przystąpieniem do konfiguracji należy upewnić się czy to urządzenie jest rzeczywiście rozpoznawany jako modem. Najprościej wydać polecenie:
+        </p>
+<pre class="code-block">
+$ ls /dev/ttyUSB*
+</pre>
+        <p>
+          Powinny pokazać nam się dwa urządzenia <em>/dev/ttyUSB0</em> oraz <em>/dev/ttyUSB1</em>, to teraz możemy być pewni (tak na 99%) że modem jest prawidłowo rozpoznawany w systemie. Jeśli chcemy być pewni na 100%, możemy doinstalować program, który pozwoli nam się połączyć z modemem za pomocą linii szeregowej. Wydajemy poniższe polecenia:
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt install picocom
+</pre>
+        <p>
+          Po zainstalowaniu programu możemy się z nim połączyć wydając polecenie:
+        </p>
+<pre class="code-block">
+$ picocom /dev/ttyUSB0 -b 115200
+</pre>
+        <p>
+          W nie których przypadkach mogą być wymagane uprawnienia administratora. Jeśli nie pojawiły się żadne błędy, powinniśmy mieć możliwość porozmawiania z modemem, wystarczy że się przywitamy. Wpisujemy poniższy ciąg znaków:
+        </p>
+<pre class="code-block">
+AT
+</pre>
+        <p>
+          W odpowiedzi powinniśmy dostać <code class="code-inline">OK</code>. Teraz już możemy być w 100% pewni że modem jest dobrze wykrywany przez RPI. Połączenie możemy zakończyć klikając po sobie kombinację klawiszy <code class="code-inline">ctrl+a</code> oraz <code class="code-inline">ctrl+x</code>.
+          <strong>Jeśli karta SIM jest zablokowana kodem PIN</strong>, przy przepięciu modemu lub przy wyłączeniu Raspberry będzie musieli ją aktywować. Połączenia jak i odblokowywania karty będziemy dokonywać za pomocą programu <em>vwdial</em>, należy go zainstalować wraz z pakietem <em>ppp</em>.
+        </p>
+<pre class="code-block">
+$ sudo apt install wvdial ppp
+</pre>
+        <p>
+          Po zainstalowaniu pakietów przechodzimy do pliku <em>/etc/vwdial.conf</em>. Plik w domyślnie wygląda następująco:
+        </p>
+<pre class="code-block">
+  [Dialer Defaults]
+  Init1 = ATZ
+  Init2 = ATQ0 V1 E1 S0=0 &C1 &D2
+  Modem Type = Analog Modem
+  Baud = 9600
+  New PPPD = yes
+  Modem = /dev/ttyUSB0
+  ISDN = 0
+  ; Phone = &lt;Target Phone Number&gt;
+  ; Password = &lt;Your Password&gt;
+  ; Username = &lt;Your Login Name&gt;
+</pre>
+        <p>
+          Dla nas interesującą linią jest pierwsza linia. Ona tworzy sekcje konfiguracyjno-uruchomieniowe dla vwdial. Równie ciekawymi liniami są <code class="code-inline">Init1</code> i <code class="code-inline">Init2</code>, zawierają bowiem one polecenia <strong>AT</strong> dla modemu. Aby odblokować modem (jeśli jest zablokowany kodem PIN) należy dodać nową sekcję pod nazwą np. <code class="code-inline">pin</code>.
+        </p>
+<pre class="code-block">
+[Dialer pin]
+Init3 = AT+CPIN=0123
+</pre>
+        <p>
+          W miejsce <code class="code-inline">0123</code> podajemy swój kod PIN. Odblokowanie modemu następuje po wydaniu polecenia.
+        </p>
+<pre class="code-block">
+$ sudo vwdial pin
+</pre>
+        <p>
+          Następna sekcja w pliku konfiguracyjnym powinna być już sekcją połączenia.
+        </p>
+<pre class="code-block">
+  [Dialer play]
+  Init3 = AT+CGDCONT=1,"IP","internet"
+  Username = "internet"
+  Password = "internet"
+  Phone = "*99#"
+  Dial Command = ATDTW
+  New PPPD = yes
+  Stupid Mode = yes
+  Dial Attemps = 0
+</pre>
+        <p>
+          W linii <code class="code-inline">Init3</code> ostatnią wartością jest <em>APN</em>. Do wypełnienia użytkownikowi pozostaje właśnie wspomniany <code class="code-inline">APN</code>, <code class="code-inline">Username</code>, <code>Password</code>, <code class="code-inline">Phone</code> oraz <strong>nazwa dialera</strong>, choć nie jest to obowiązkowe. Reszta pozostaje bez zmian. Teraz wystarczy tylko się podłączyć wydając polecenie:
+        </p>
+<pre class="code-block">
+wvdial play&
+</pre>
+        <p>
+          Warto pamiętać o tym aby uruchomić połączenie w tle. Możemy spotkać się z taką sytuacją że modem nie będzie chciał się połączyć z Internetem. W takiej sytuacji należy spróbować ze 2-3 razy, następnie zmienić urządzenie, w sekcji <code class="code-inline">[Dialer Defaults]</code> z <code class="code-inline">Modem = /dev/ttyUSB0</code> na <code class="code-inline">Modem = /dev/ttyUSB1</code>. i wtedy spróbować się połączyć jeśli się to również nie powiedzie, to należy wrócić do poprzedniego urządzenia. W tym momemcie modem powinien się połączyć.
+        </p>
+      </li>
+      <li>Usługa wvdial w systemd
+        <p>
+          Aby wvdial uruchamiał się i łączył w raz ze startem systemu, należy utworzyć <strong>jednostkę systemd</strong>. Oczywiście można skorzystać z poniższego pliku.
+        </p>
+<pre class="code-block">
+[Unit]
+BindsTo=dev-ttyUSB0.device
+After=dev-ttyUSB0.device
+Description=Wvdial Connection
+Before=network.target
+Wants=network.target
+
+[Service]
+type=oneshot
+ExecStart=/usr/bin/wvdial play
+
+[Install]
+WantedBy=multi-user.target
+</pre>
+        <p>
+          Jeśli kartę sim trzeba odblokować kodem PIN. Należy stworzyć drugą jednostkę podobną do tej. Powiedzmy że mamy jednostkę służącą do połączenia nazwiemy ją <em>vwdial-connect.service</em>, oraz jedostkę służącą do odblokowania karty <em>vwdial-unlock.service</em> musimy zmienić dwie opcje w sekcji <code class="code-inline">[Unit]</code> mianowicie <code class="code-inline">Before</code> oraz <code class="code-inline">Wants</code>. Zmienimy również opcje <code class="code-inline">Description</code> aby była bardziej adekwatna do czynności wykonywanych przez daną jednostkę.
+        </p>
+<pre class="code-block">
+[Unit]
+BindsTo=dev-ttyUSB0.device
+After=dev-ttyUSB0.device
+Description=Wvdial SIM Card Unlock
+Before=wvdial-connect.service
+Wants=wvdial-connect.service
+
+[Service]
+type=oneshot
+ExecStart=/usr/bin/wvdial pin
+[Install]
+WantedBy=multi-user.target
+</pre>
+      <p>
+        Jednostka <em>wvdial-connect.service</em> zostanie opóźniona do momentu uruchomienia jednostki <em>wvdial-unlock.service</em>.
+      </p>
+    </li>
+    <li><strong>Adres dla interfejsu bezprzewodowego.</strong>
+      <p>
+        Konfiguracji interfejsu bezprzewodowego dokonujemy w pliku <em>/etc/dhcpcd.conf</em>. Dopisując poniższe linie na samym końcu pliku.
+      </p>
+<pre class="code-block">
+interface wlan0
+static ip_address=192.168.4.1/24
+nohook wpa_supplicant
+</pre>
+      <p>
+        Oczywiście klasę adresów należy ustawić według własnych preferencji.
+      </p>
+    </li>
+    <li><strong>Konfiguracja serwera dhcp.</strong>
+      <p>
+        Do konfiguracji DHCP na RPI wykorzystamy pakiet <em>dnsmasq</em>. Instalujemy go poleceniem.
+      </p>
+<pre class="code-block">
+$ sudo apt install dnsmasq
+</pre>
+      <p>
+        Po zainstalowaniu pakietu, zmieniamy nazwę pliku konfiguracyjnego na <em>dnsmasq.conf.bak</em>, następnie tworzymy nowy plik <em>/etc/dnsmasq.conf</em> i umieszczamy w nim poniższą konfigurację.
+      </p>
+<pre class="code-block">
+interface=wlan0
+dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
+</pre>
+      <p>
+        Zakresy i czas dzierżawy należy ustawić według własnych preferencji.
+      </p>
+    </li>
+    <li><strong>Konfiguracja sieci bezprzewodowej.</strong>
+      <p>
+        Aby Raspberry Pi mogło rozgłaszać sygnał sieci bezprzewodowej należy zainstalować odpowiedni pakiet. <em>Hostapd</em> pobieramy z repozytorium:
+      </p>
+<pre class="code-block">
+$ sudo apt install hostapd
+</pre>
+      <p>
+        Konfiguracja znajduje się w pliku <em>/etc/hostapd/hostapd.conf</em>. Jednak to nie jedyny plik w którym należy coś zmienić, aby uruchomić 'hostapd', drugim plikiem jest <em>/etc/default/hostapd</em> tam usuwamy znak komentarza sprzed opcji <code class="code-inline">DAEMON_CONF</code>. Natomiast w <em>/etc/hostapd/hostapd.conf</em> możemy wpisać konfigurację bazującą na poniższej.
+      </p>
+<pre class="code-block">
+interface=wlan0
+driver=nl80211
+ssid=test123
+hw_mode=g
+channel=6
+ieee80211n=1
+wmm_enabled=0
+macaddr_acl=0
+auth_algs=1
+ignore_broadcast_ssid=0
+wpa=2
+wpa_passphrase=12344321
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+rsn_pairwise=CCMP
+</pre>
+      </li>
+      <li><strong>Przekazywanie pakietów</strong>
+        <p>
+          Aby sprzęt podłączony do naszej sieci bezprzewodowej miał dostęp do Internetu potrzebne są dwe rzeczy. NAT oraz <strong>przekazywanie pakietów</strong>. NAT-em zajmiemy się w następnym punkcie. Aby skonfigurować przekazywanie pakietów na RasPiOS wystarczy odkomentować opcje <code class="code-inline">net.ipv4.ip_forward=1</code> w pliku <em>/etc/sysctl.conf</em>.
+        </p>
+      </li>
+      <li><strong>NAT</strong>
+        <p>
+          W każdym RasPiOS pre-instalowane jest <em>iptables</em> czyli jeden z pakietów firewall-a dostępnych na GNU/Linux. Jednak pre-instalowane nie jest oprogramowanie, które pozwala zachować wpisane do tablic reguły, aby ustawienia NAT-u, w iptables zostało zapisane na stałe w plikach systemu potrzebujemy pakietu <em>iptables-persistent</em> instalowanego za pomocą polecenia.
+        </p>
+<pre class="code-inline">
+$ sudo apt install iptables-persistent
+</pre>
+        <p>
+          <strong>NAT</strong> w przypadku tego systemu uruchamiamy następującym poleceniem:
+        </p>
+<pre class="code-block">
+$ sudo iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
+</pre>
+        <p>
+          Teraz kiedy jest on włączony, pozostaje tylko zapisać naszą tablicę, aby to zrobić musimy wykonać polecenia z uprawnieniami użytkownika <em>root</em> więc albo:
+        </p>
+<pre class="code-block">
+$ sudo su
+# iptables-save > /etc/iptables.ipv4.nat
+</pre>
+        <p>
+          lub:
+        </p>
+<pre class="code-block">
+$ sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
+</pre>
+        <p>
+          Reguła NAT-u jest już trwała. Teraz kolejnym problem jest <strong>przywrócenie tej reguły podczas ładowania systemu</strong>. Najłatwiejszym sposobem jest dopisanie polecenia do pliku, który wyświetla nam adres IP zaraz przez logowaniem. Jest to plik <em>/etc/rc.local</em>, przed linią <code class="code-inline">exit 0;</code> dopisujemy następujące polecenie:
+        </p>
+<pre class="code-block">
+$ iptables-restore < /etc/iptables.ipv4.nat
+</pre>
+      </li>
+      <li><strong>Restart</strong>
+        <p>
+          Restarujemy malinke:
+        </p>
+<pre class="code-block">
+$ sudo reboot
+</pre>
+      </li>
+    </ol>
+    <p>
+      Jak możemy się przekonać to wszystko działa. Patrząc na to z perspektywy czasu to zmienił bym modem 3G na LTE i przylutował go pod gniazdo USB, wszystko zasilił bym modułem z powerbank-a z wymiennymi akumlatorami 3,7V. Na koniec zaprojektowałbym obudowę i wydrukował za pomocą drukarki 3D.
+    </p>
+    <p>
+      ~xf0r3m
+    </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/Raspberry_Pi_jako_przekaźnik_bluetooth.html b/articles/raspberrypi/Raspberry_Pi_jako_przekaźnik_bluetooth.html
new file mode 100644 (file)
index 0000000..58e25e3
--- /dev/null
@@ -0,0 +1,297 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Raspberry Pi jako przekaźnik bluetooth</h1>
+      <p>
+        Kiedyś potrzebowałem przekaźnika bluetooth, takiego który mogłem
+        podłączyć do wieży czy głośników od komputera i puszczać muzykę
+        bezprzewodowo z telefonu. Nie chciałem używać czegoś takiego jak
+        "Balena Sound", towrzyć jakieś konta, logować się. To nie w moim
+        stylu, przeglądając co wyniki wyszukiwania wujka Google trafiłem na
+        jeden lub dwa poradniki, które okazały sie klapą. Jednym z wyników
+        wyszukiwania były wątek na forum i on okazał się strzałem w 10
+        (powiedzmy, bo jakość dzwięku może srogo rozczarować). Nie owiajając w
+        bawełnę konfiguracje Raspberry Pi zaczniemy od zainstalowania systemu
+        na karcie i umożliwienia zalogowania się przez SSH.
+      </p>
+      <p>
+        Po zalogowaniu się do systemu, każdą konfigurację rozpoczynamy od
+        aktualizacji.
+      </p>
+<pre class="code-block">
+$ sudo apt update
+$ sduo apt upgrade
+</pre>
+      <p>
+        Następnie instalujemy niezbędne oprogramowanie.
+      </p>
+<pre class="code-block">
+$ sudo apt install pulseaudio pulseaudio-module-bluetooth
+</pre>
+      <p>
+        Teraz musimy dodać naszego użytkownika do grupy <em>bluetooth</em>.
+      </p>
+<pre class="code-block">
+$ sudo usermod -aG bluetooth pi
+</pre>
+      <p>
+        Aby zmiany dotyczące grupy lub użytkownika zaczęły działać należy się
+        wylogować i zalogować ponownie.
+      </p>
+      <p>
+        Kolejną czynnością jest przestawienie RPI aby było widziane jako
+        "Odpływ wysokiej jakość (A2DP)". W pliku 
+        <em>/etc/bluetooth/main.conf</em> usuwamy znak komentarza z opcji
+        <code class="code-inline">Class</code> i nadajemy jej wartość
+        <em>0x41C</em> oraz usuwamy znak komentarza z opcji
+        <code class="code-inline">DiscoverableTimeout</code>
+      </p>
+<pre class="code-block">
+...
+Class = 0x41C
+...
+DiscoverableTimeout = 0
+...
+</pre>
+      <p>
+        Po zapisaniu zmian w pliku, restartujemy usługę.
+      </p>
+<pre class="code-block">
+$ sudo systemctl restart bluetooth
+</pre>
+      <p>
+        Następnie musimy uruchomić bluetooth na RPI, po wydaniu polecenia
+        <code class="code-inline">bluetoothctl</code>, wydajemy kolejno
+        przedstawione poniżej polecenia.
+      </p>
+      <p>
+        Za nim to jednak zrobimy może być tak, że nasz kontroler bluetooth
+        będzie wyłączony za pomocą <em>rfkill</em>. W tym przypadku musimy
+        wydać polecenie <code class="code-inline">raspi-config</code> następnie
+        wybrać:
+      </p>
+<pre class="code-block">
+Localisation Options -&gt; WLAN Country -&gt; [kraj, którym znajduje się urządzenie] -&gt; Finish
+#Wyrażamy zgodę na restart RPI.
+</pre>
+<pre class="code-block">
+$ bluetoothctl
+Agent registered
+[bluetooth]# power on
+Changing power on succeeded
+[bluetooth]# discoverable on
+Changing discoverable on succeeded
+[CHG] Controler XX:XX:XX:XX:XX:XX Discoverable: yes
+[bluetooth]# pairable on
+Changing pairable on succeeded
+[bluetooth]# agent on
+Agent is already registered
+[bluetooth]# default-agent
+Default agent request successful
+[bluetooth]# quit
+</pre>
+      <p>
+        Uruchamiamy <em>pulseaudio</em>
+      </p>
+<pre class="code-block">
+$ pulseaudio --start
+</pre>
+      <p>
+        Następnie sprawdzamy czy usługa bluetooth zarejestrowała odpływ A2DP.
+      </p>
+<pre class="code-block">
+$ sudo systemctl status bluetooth
+</pre>
+      <p>
+        Jeśli zauważyliśmy jakieś linie <em>Endpoint registered</em>
+        zawierające napis "A2DP" oznacza to, że odpływ został zarejestrowany.
+        Teraz dokonamy testowego połączenia. Warto zaznaczyć, że abyśmy 
+        mogli się połączyć z RPI to będziemy musieli "zaufać" naszemu 
+        urządzeniu. Na malinie uruchamiamy polecenie
+        <code class="code-inline">bluetoothctl</code>, a na telefonie
+        wyszukujemy urządzeń bluetooth, nazwa urządzenia będzie identyczna jak
+        nazwa hosta RPI. Próbuje my się z nim połączyć. 
+      </p>
+<pre class="code-block">
+$ bluetoothctl
+</pre>
+      <p>
+        Przy próbie podłączenia zostanie na wyświetlona masa komunikatów
+        związanych z naszym telefonem, w tych komunikatch po słowie
+        <em>Device</em>, znajdować się będzie adres MAC modułu bluetooth w
+        telefonie. Nie należy zrazić się komunikatem "Błąd połączenia". Teraz
+        na RPI wpisujemy polecenie bluetooth 
+        <code class="code-inline">trust</code> oraz
+        MAC naszego bluetooth.
+      </p>
+<pre class="code-block">
+[bluetooth]# trust AA:BB:CC:DD:EE:FF
+</pre>
+      <p>
+        Powinniśmy się prawidłowo połączyć.
+        Dzwięk również już pownien działać. Dla testu warto włączyć jakąś
+        muzykę lub film na YT.
+      </p>
+      <p>
+        Mogło by się okazać, że już gotowe. Jednak to nie wszystko, teraz
+        póki co uruchamialiśmy <em>pulseaudio</em> z ręki, jednak nie bedziemy 
+        się
+        za każdym razem po włączeniu RPI logować i włączać usługę. Tu jest
+        również pewien haczyk, otóż żeby <em>pulseaudio</em> mogło działać 
+        niezbędny
+        jest zalogowany użytkownik, z poziomu którego <em>systemd</em> będzie
+        ten program uruchamiać więc poza autostartem pulseaudio do ustawienia
+        zostało jeszcze autologowanie na użytkownika <em>pi</em>.
+      <p>
+      <p>
+        Uruchomie <em>pulseaudio</em> wraz z systemem.
+      </p>
+<pre class="code-block">
+$ systemctl --user enable pulseaudio.service
+</pre>
+      <p>
+        Włączenie autologowania się na użytkownika <em>pi</em>.
+      </p>
+<pre class="code-block">
+$ sudo raspi-config
+System Options -&gt; Boot / Auto Login -&gt; Console Autologin -&gt; Ok
+</pre>
+      <p>
+        Po ustawieniu autologowania, być może będzie trzeba zrestartować
+        urządzenie.
+      </p>
+      <p>
+        Teraz formalnie to wszystko. Jednak pozostała jeszcze jedna kwestia,
+        podłączanie się urządzeń do RPI. Można to zrobić na 3 sposoby.
+      </p>
+      <p>
+         Pierwszy najprostszy, pozostawienie tego tak jak jest. Każdeme nowemu
+         urządzeniu będzie trzeba "zaufać", tak jak podczas testu.
+      </p>
+      <p>
+          Drugi pozwalający na połączenie z każdemu urządzeniu bez żadnych
+          mechanizmów kontroli.
+      </p>
+      <p>
+          Trzeci wprowadzający klasyczny "PIN". Drugi i trzeci sposób opisze
+          poniżej, każdy zdecyduje co jemu najbardziej odpowiada. 
+      </p>
+      <p>
+        W tym jak i w trzecim sposobie musimy zainstalować dodatkowy pakiet.
+        Sposoby różni tylko konfiguracja usługi <em>bt-agent</em> oraz
+        jeden dodatkowy plik w trzecim. Usługa ta
+        wchodzi w skład pakietu <em>bluez-tools</em>.
+      </p>
+<pre class="code-block">
+$ sudo apt install bluez-tools
+</pre>
+      <p><u>Sposób 2: Pozwala na podłaczenie się każdego urządzenia</u></p>
+      <p>
+        Po zainstalowaniu pakietu, musimy utworzyc plik usługi
+        <em>bt-agent.service</em> w katalogu <em>/etc/systemd/system</em>.
+      </p>
+<pre class="code-block">
+[Unit]
+Description=Bluetooth Auth Agent
+After=bluetooth.service
+PartOf=bluetooth.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/bt-agent -c NoInputNoOutput
+
+[Install]
+WantedBy=bluetooth.target
+</pre>
+      <p>
+        Zapisujemy plik, włączamy go aby uruchamiał się zgodnie zapisaną w nim
+        sekwencją. I możemy startować usługę. Teraz każde nowe urządzenie
+        podłączy się do RPI bez żadnych przeszkód.
+      </p>
+<pre class="code-block">
+$ sudo systemctl enable bt-agent.service
+$ sudo systemctl start bt-agent.service
+$ sudo systemctl status bt-agent.service
+</pre>
+      <p><u>Sposób 3: Pozwala na podłączenie się tylko dla znających PIN</u></p>
+      <p>
+        Ten sposób rózni się konfiguracją usługi oraz
+        dodatkowym plikiem, w którym zdefiniowany jest PIN. Utworzy my teraz plik
+        z PIN-em, w pliku <em>pin.conf</em> w katalogu <em>/etc/bluetooth/</em>
+        zapisujemy poniższą linię.
+      </p>
+<pre class="code-block">
+*   12345
+</pre>
+      <p>
+        Oczywiście PIN, możemy podać własny. Nadajemy odpowienie uprawnienia
+        dla pliku.
+      </p>
+<pre class="code-block">
+$ sudo chmod 600 /etc/bluetooth/pin.conf
+</pre>
+      <p>
+        Teraz dokonujemy zmian w pliku usługi, tak aby <em>bt-agent</em>,
+        wykorzystywał PIN do uwierzytelnienia połączeń z RPI. 
+      </p>
+<pre class="code-block">
+[Unit]
+Description=Bluetooth Auth Agent
+After=bluetooth.service
+PartOf=bluetooth.service
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/bt-agent -c NoInputNoOutput -p /etc/bluetooth/pin.conf
+ExecStartPost=/bin/sleep 1
+ExecStartPost=/bin/hciconfig hci0 sspmode 0
+
+[Install]
+WantedBy=bluetooth.target
+</pre>
+      <p>
+        Po zatwierdzeniu zmian, włączamy i uruchamiamy usługę.
+      </p>
+<pre class="code-block">
+$ sudo systemctl enable bt-agent.service
+$ sudo systemctl start bt-agent.service
+$ sudo systemctl status bt-agent.service
+</pre>
+      <p>
+        Nasz przekaźnik jest już gotowy. Możemy podłaczyć do niego zarówno
+        głośnik jak i zestaw kina domowego, wszystko czego połączenie opiera
+        się na złączu Jack 3,5mm.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/Raspberry_Pi_jako_serwer_poczty.html b/articles/raspberrypi/Raspberry_Pi_jako_serwer_poczty.html
new file mode 100644 (file)
index 0000000..e161de0
--- /dev/null
@@ -0,0 +1,480 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Raspberry Pi jako serwer poczty</h1>
+    <p>
+      Był już serwer wydruku, a teraz przyszedł czas na serwer poczty.
+      Materiał ten jest podobny, do tego z wykorzystaniem BSD i bardzo
+      starego serwera. Wykorzystałem go jako bazę, jednak nie wszystko zostało
+      przeniesione 1:1 na Raspberry Pi. 
+    </p>
+    <p>
+      Jak każdą pracę z wykorzystaniem RPI jako serwera czegoś, należy 
+      zacząć od przygotowania sobie czystego środowiska. Na kartę microSD
+      nagrywamy obraz z systemem. Jeśli korzystamy z Linux-a to możemy
+      użyć do tego polecenia <em>dd</em>.
+    </p>
+<pre class="code-block">
+$ sudo dd if=~/Downloads/2021-05-07-raspios-buster-armhf-lite.img bs=1M of=/dev/mmcblk0 status=progress
+</pre>
+    <p>
+      Instalowany system operacyjny to klasycznie RasPiOS. Po przegraniu
+      systemu na kartę warto ustawić sobie możliwość zdalnego połączenia się
+      przez SSH. Jeśli mamy już urządzenie gotowe do pracy to zaczynamy od:
+    </p>
+    <ol>
+      <li>
+        <strong>
+          Usunięcie domyślnego użytkownika i dodanie nowego, swojego
+        </strong>
+        <p>
+          W systemach RasPiOS domyślnym użytkownikiem jest <em>pi</em>, a jego
+          hasło <em>raspberry</em> do najtrudniejszych nie należy i najlepiej
+          ze względów bezpieczeństwa pozbyć się tego użytkownika. Użytkownicy
+          w przypadku przedstawionej tutaj konfiguracji serwera będą mapowani
+          na użytkowników usług pocztowych, a pozostawienie niewykorzystanego
+          konta z możliwością logowania, może stanowić potencjalną furtkę do
+          systemu. Użytkownika pozbywamy się za pomocą
+          polecenia <em>deluser</em>. Jednak przed jego usunięciem musimy 
+          stworzyć nowego użytkownika i nadać mu uprawnienia administracyjne,
+          w przeciwnym wypadku zostalibyśmy bez zwykłego użytkownika, a co 
+          za tym idzie bez możliwości zdalnego logowania się na serwerze, chyba
+          że pozwolimy na logowanie przez SSH użytkownika <em>root</em>, co
+          jest jeszcze bardziej niebezpieczne niż pozostawienie użytkownika 
+          <em>pi</em>
+        </p>
+<pre class="code-block">
+pi@raspberrypi:~ $ sudo adduser xf0r3m
+...
+pi@raspberrypi: $ sudo usermod -aG sudo xf0r3m
+# Przelogowanie się na nowego użytkownika.
+xf0r3m@raspberrypi: $ sudo deluser pi
+</pre>
+      </li>
+      <li>
+        <strong>Aktualizacja systemu</strong>
+        <p>
+          Po pozbyciu się użytkownika <em>pi</em>, możemy przejeść do
+          aktualizacji systemu.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+      </li>
+      <li>
+        <strong>Opcjonalnie: zmiana nazwy hosta</strong>
+        <p>
+          Wypadałoby, aby host będący w domenie serwerem mailowym miał
+          odpowienią nazwę, chociaż nie jest to wymagane.
+        </p>
+<pre class="code-block">
+$ sudo raspi-config
+1 System Options -&gt; S4 Hostname -&gt; OK
+</pre>
+      </li>
+      <li>
+        <strong>Instalacja Postfix-a</strong>
+        <p>
+          Naszym serwerem protokołu SMTP będzie 
+          <em>Postfix</em>. Jest to chyba jedyny rzetelny, open sourcowy 
+          serwer SMTP, dostępny na UNIX-y, którego konfiguracja nie jest
+          jakąś czarną magią.
+        </p>
+<pre class="code-block">
+$ sudo apt install postfix
+</pre>
+      </li>
+      <li>
+        <strong>Monit o konfiguracji Postfix-a w trakcie instalacji</strong>
+        <p>
+          Podczas instalacji <em>Postfix</em>-a, zostanie nam wyświetlone
+          okno <em>dialog</em>-u na temat konfiguracji, wybieramy
+          <em>Strona internetowa/Internet site</em> w polu do uzupełnienia
+          wpisujemy nazwę swojej domeny.
+        </p>
+      </li>
+      <li>
+        <strong>Ustawienie opcji
+          <code class="code-inline">mydestination</code> na nazwwę domeny
+        </strong>
+        <p>
+          Niestety wybór opcji w oknie dialogowym i podanie odpowiedniej
+          wartość nie załatwią poprawnej konfiguracji (takiej, która
+          działa). Żeby serwer SMTP obsługiwał pocztę wewnątrz naszej
+          organizacji, musimy ustawić w odpowiedniej opcji, że ten
+          serwer jest jednym z serwerów obsługujących tą domenę.
+        </p>
+<pre class="code-block">
+$ sudo postconf -e "mydestination=example.com"
+</pre> 
+      </li>
+      <li>
+        <strong>Sprawdzenie możliwości użycia Dovecot SASL</strong>
+        <p>
+          Przed wdrożeniem konkretnej implementacji mechanizmów
+          uwierzytelniania musimy sprawdzić czy zainstalowana wersja 
+          <em>Postfix</em>-a jest z nią kompatybilna.
+          Przedstawione tutaj czynności (całość materiału, konfiguracji) są 
+          tylko jednym ze sposobów. Możemy
+          je dostosować do własnych potrzeb. Poniższe polecenie zwróci nam
+          listę obsługiwanych implementacji uwierzytelniania. 
+        </p>
+<pre class="code-block">
+$ sudo postconf -a
+</pre>
+        <p>
+          Polecenie na 99,9% zwróci <code class="code-inline">dovecot</code>,
+          i to jest implementacja, która zostanie tutaj przedstawiona.
+        </p>
+      </li>
+      <li>
+        <strong>Instalacja dovecot</strong>
+        <p>
+          Instalacja <em>dovecot</em>, akurat w przypadku dystrybucji opartych 
+          na GNU/Linux Debian, nie jest wcale taka oczywista. <em>Dovecot</em>
+          to kombajn, który zawiera masę usług, więc postanowiono go podzielić
+          na pomniejsze pakiety zawierające tylko tą usługę, której nazwa jest
+          zawarta w nazwie pakietu. Tak więc aby na RPI zainstalować
+          <em>dovecot</em> mogący świadczyć usługi w organizacji potrzebujemy
+          dwóch pakietów. 
+        </p>
+<pre class="code-block">
+$ sudo apt dovecot-imapd dovecot-pop3d 
+</pre>  
+        <p>
+          System uwierzytelniania SASL, zostanie zainstalowany wraz z pakietem
+          <em>dovecot-core</em>, który jest zależnością dla powyższych
+          pakietów, a te pakiety i tak będą nam potrzebne.
+        </p>
+      </li>
+      <li>
+        <strong>Uruchomienie uwierzytelniania dla Postfix-a</strong>
+        <p>
+          Tę czynność rozpoczniemy od konfiguracji <em>dovecot</em>-a, w pliku
+          <em>/etc/dovecot/conf.d/10-master.conf</em>, w sekcji
+          <code class="code-inline">service auth</code> włączamy -
+          usuwając znaki komentarza, sekcję 
+          <code class="code-inline">
+            unix_listener /var/spool/postfix/private/auth
+          </code>
+          wewnątrz tej sekcji zmieniamy wartość opcji
+          <code class="code-inline">mode</code> na <em>0660</em> oraz dodajemy 
+          dwie opcje: <em>user</em> oraz <em>group</em> ustawione na wartość 
+          <em>postfix</em>. Już poza sekcją 
+          <code class="code-inline">auth</code> określamy rodzaje mechanizmów
+          uwierzytelniania. Poniżej znajduje się listing przedstawiający poprawnie
+          skonfigurowaną sekcję.
+        </p>
+<pre class="code-block">
+service auth {
+...
+  unix_listener /var/spool/postfix/private/auth {
+    mode = 0660
+    user = postfix
+    group = postfix
+  }
+...
+}
+
+auth_mechanisms = plain login
+</pre>
+        <p>
+          Po zapisaniu zmian, w kolejnym pliku
+          <em>/etc/postfix/main.cf</em> dopisujemy poniższe opcje:
+        </p>
+<pre class="code-block">
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+smtpd_sasl_auth_enable = yes
+smtpd_relay_restrictions = permit mynetworks, permit_sasl_authenticated, reject_unauth_destination
+</pre>
+        <p>
+          Te opcje wprowadzają restrykcje dla serwera SMTP nasłuchującego na
+          porcie TCP/25. Tak, ten port musi być otwarty, w przeciwynym wypadku
+          żaden mail z zewnątrz do nas nie dotrze. Użytkownicy poczty będą
+          używać portu <em>submission</em> czyli TCP/587, ale maile przesyłane
+          są między domenami (serwerami SMTP) przy użyciu portu TCP/25. Warto
+          też dodać, że maile pomiędzy domenami przesyłane są zwykłym tekstem,
+          dlatego też wiele osób stosuje szyfrowanie od końca do końca  
+          (ang. <em>End-to-end encryption</em>). Po
+          zapisaniu tych ustawień możemy przejść do uruchomienia
+          <em>submission</em>.
+        </p>
+      </li>
+      <li>
+        <strong>
+          Uruchomienie submission dla połączeń klient-serwer SMTP
+        </strong>
+        <p>
+          W pliku <em>/etc/postfix/master.cf</em> odnajdujemy wiersz tabeli
+          zawierający napis <em>submission</em>, usuwamy poprzedzający go znak
+          komentarza, następnie pod tym wierszem zapisujemy opcje z jakimi ma
+          zostać uruchomiony.
+        <p>
+<pre class="code-block">
+submission  inet  n - y - - smtpd
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_sasl_type=dovecot
+ -o smtpd_sasl_path=private/auth
+ -o smtpd_sasl_security_options=noanonymous
+ -o smtpd_sasl_local_domain=example.com
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+ -o smtpd_sender_login_maps=hash:/etc/postfix/virtual
+ -o smtpd_sender_restrictions=reject_sender_login_mismatch
+ -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
+</pre>
+      </li>
+      <li>
+        <strong>
+          Restart Postfix-a
+        </strong>
+        <p>
+          Teraz przyszedł czas na sprawdzenie poprawności wprowadzonych
+          ustawień. Na początek uruchomimy ponownie <em>Postfix</em>-a.
+        </p>
+<pre class="code-block">
+$ sudo postfix reload
+</pre>
+        <p>
+          Jeśli teraz daemon nie zwróci żadnych komunikatów, to 
+          wszystko jest na dobrej drodze. Warto jeszcze zajrzeć do pliku
+          <em>/var/log/syslog</em>.
+        </p>
+      </li>
+      <li>
+        <strong>
+          Instalacja certyfikatów SSL organizacji dla SMTP
+        </strong>
+        <p>
+          W pliku <em>/etc/postfix/main.cf</em>, odnajdujemy dwie opcje
+          <code class="code-inline">smtpd_tls_cert_file</code> oraz
+          <code class="code-inline">smtpd_tls_cert_key</code>. Tej pierwszej,
+          jako wartość ustawiamy ścieżkę do pliku certyfikatu, a drugiej
+          ścieżkę do pliku klucza certyfikatu.
+        </p>
+<pre class="code-block">
+smtpd_tls_cert_file=/etc/openssl/certs/fullchain1.pem
+smtpd_tls_cert_key=/etc/openssl/private/privkey1.pem
+</pre>
+      </li>
+      <li>
+        <strong>
+          Utworzenie bazy użytkowników usług pocztowych
+        </strong>
+        <p>
+          Baza użytkowników jest zwykłym plikem tekstowym, w którym występują
+          mapowania adresów e-mail organizacji na nazwy użytkowników systemu.
+          W pliku każda linia to jedno mapowanie, a bazą użytkowników dla
+          <em>Postfix</em>-a jest <em>/etc/postfix/virtual</em>. Po zapisaniu
+          zmian plik ten należy dostosować za pomocą polecnia dostarczanego 
+          wraz z <em>Postfix</em>-em, aby był dla niego czytelny. Za każdym
+          dodanie mapowania baza będzie wymagała konwersji. 
+        </p>
+<pre class="code-block">
+/etc/postfix/virtual:
+root@example.com  root
+xf0r3m@example.com  xf0r3m
+
+$ sudo postmap /etc/postfix/virtual
+</pre>
+        <p>
+          Po skonwertowaniu bazy, należy zrestartować <em>Postfix</em>-a.
+        </p>
+<pre class="code-block">
+$ sudo postfix reload
+</pre>
+      </li>
+      <li>
+        <strong>
+          Włączenie SSL w Dovecot
+        </strong>
+        <p>
+          Za pomocą protokołów IMAP oraz POP3 użytkownicy będą pobierać maile
+          z serwera, aby zabezpieczyć komunikację pomiędzy klientem a serwerem
+          tak jak zrobiliśmy to z protkołem SMTP tu również użyjemy 
+          certyfikatów
+          SSL. W <em>/etc/dovecot/ssl/10-ssl.conf</em> ustawiamy ścieżki
+          do plików certyfikatu.
+        </p>
+        <p>
+          Jeśli przed opcją <code class="code-inline">ssl</code> znajduje się
+          znak komentarza, to należy go usunąć.
+        </p>
+        <p>
+          A pliki certyfikatu ustawiane są w opcjach
+          <code class="code-inline">ssl_cert</code> - dla pliku certyfikatu i
+          <code class="code-inline">ssl_key</code> - dla pliku klucza
+          prywatnego certyfikatu.
+        </p>
+<pre class="code-block">
+ssl_cert=&lt;/etc/openssl/certs/fullchain1.pem
+ssl_key=&lt;/etc/openssl/private/privkey1.pem
+</pre>
+        <p>
+          <strong>Uwaga!</strong> Ostre nawiasy są cześcią składni wartości
+          opcji.
+        </p>
+      </li>
+      <li>
+          <strong>
+            Uruchomienie IMAPS i POP3S
+          </strong>
+          <p>
+            Po ustawieniu SSL dla usług <em>dovecot</em>, przyszedł czas aby
+            je włączyć. W pliku <em>/etc/dovecot/conf.d/10-master.conf</em>
+            musimy odnaleźć dwie sekcje: 
+            <code class="code-inline">inet_listener imaps</code> oraz
+            <code class="code-inline">inet_listener pop3s</code>, w tych
+            sekcjach dopisujemy dwie opcje: <em>port</em> wskazującą na numer
+            portu usługi oraz opcje <em>ssl</em> uruchamiającą szyfrowaną
+            transmisję dla połączeń z tym serwerem. Te opcje oczywiście o
+            innych portach ustawiamy w obu wymienionych sekcjach.
+          </p>
+<pre class="code-block">
+...
+inet_listener imaps {
+  port = 993
+  ssl = yes
+}
+
+...
+inet_listener pop3s {
+  port = 995
+  ssl = yes
+}
+</pre>
+      </li>
+      <li>
+        <strong>
+          Restart dovecot
+        </strong>
+        <p>
+          Po wdrożeniu ostatnich zmian, trzeba zrestartować usługę aby zmiany
+          zostały uzwględnione przez działającego daemona.
+        </p>
+<pre class="code-inline">
+$ sudo dovecot reload
+</pre>
+      </li>
+      <li>
+        <strong>
+          Sprawdzenie poprawności działania serwera za pomocą Thunderbirda
+        </strong>
+        <p>
+          W internecie jest bardzo dużo dostępnych klientów pocztowych różnej
+          maści. Jednak tutaj będzie zależało nam na prostocie konfiguracji,
+          dlatego do celów testowych wybierzemy Thunderbirda.
+        </p>
+        <p>
+          Tworząc nowe konto pocztowe, w początkowych polach podajemy nazwę,
+          adres e-mail oraz hasło. Na dole okna klikamy przycisk ręcznej
+          konfiguracji. Następnie uzupełniamy pola, tak jak opisano to poniżej 
+        </p>
+        <p>
+          <u>Konfiguracja serwera poczty wychodzącej:</u>
+          <ul>
+            <li>
+              <strong>Protokół:</strong> SMTP
+            </li>
+            <li>
+              <strong>Serwer:</strong> mail.example.com
+            </li>
+            <li>
+              <strong>Port:</strong> 587
+            </li>
+            <li>
+              <strong>SSL:</strong> STARTTLS
+            </li>
+            <li>
+              <strong>Uwierzytelnianie:</strong> Normalne hasło
+            </li>
+            <li>
+              <strong>Nazwa użytkownika:</strong>  
+              <em>Nazwa użytkownika (systemowa z serwera mailowego)</em>
+            </li>
+          </ul>
+        </p>
+        <p>
+          <u>Konfiguracja serwera poczty przychodzącej:</u>
+          <ul>
+            <li>
+              <strong>Protokół:</strong> IMAP/POP3
+            </li>
+            <li>
+              <strong>Serwer:</strong> mail.example.com
+            </li>
+            <li>
+              <strong>Port:</strong> 993/995
+            </li>
+            <li>
+              <strong>SSL:</strong> SSL/TLS
+            </li>
+            <li>
+              <strong>Uwierzytelnianie:</strong> Normalne hasło
+            </li>
+            <li>
+              <strong>Nazwa użytkownika:</strong>  
+              <em>Nazwa użytkownika (systemowa z serwera mailowego)</em>
+            </li>
+          </ul>
+        </p>
+        <p>
+          Po zatwierdzeniu będziemy mieć już gotową skrzynkę. W celach
+          testowych wyślijmy maila z załącznikiem (serwer nie przepuści
+          wiadomości większej niż 10MB) do siebie. Powinna wysłać się
+          bez problemu i od razu pojawić się w skrzynce.
+        </p>
+      </li>
+    </ol>
+    <p>
+      Jeśli chodzi o pracę tego typu rozwiązania w jakieś konkretnej 
+      organizacji, to zostało jeszcze wiele pracy. Większość skrzynek
+      pocztowych będzie traktować maile wysłane z tego serwera jako SPAM.
+      Jeśli odpowiemy na maila, to trafi on automatycznie do skrzynki 
+      odbiorczej jako kontynuacja wątku. To rozwiązanie w takiej postaci
+      może sprawdzić się w korespondencji wewnętrznej. 
+    </p>
+    <p>
+      Jeśli ktoś jest spragniony testowania tego rozwiązania, to w materiale
+      na podbny temat w sekcji "bsd" znajduje się więcej informacji. W tym
+      materiale znajduje się konfiguracja programu <em>MUTT</em> dla
+      usług pocztowych tego typu. Link poniżej:
+    </p>
+    <p>
+      <a href="https://morketsmerke.net/site/articles/bsd/20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html">https://morketsmerke.net/site/articles/bsd/20_letni_Sun_Netra_T1_jako_serwer_mailowy_z_wykorzystaniem_NetBSD.html</a>
+    </p>
+    <p>
+    ~xf0r3m
+    </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/Raspberry_Pi_jako_serwer_wydruku.html b/articles/raspberrypi/Raspberry_Pi_jako_serwer_wydruku.html
new file mode 100644 (file)
index 0000000..68e6c5c
--- /dev/null
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Raspberry Pi jako serwer wydruku</h1>
+    <p>
+      Jak to się mówi... Potrzeba jest matką wynalazków. W moim przypadku był to problem takiego rodzaju że na dwa komputery w biurze miałem jedną drukarkę. Dość starą drukarkę bo to <em>HP LaserJet 1010</em> wydana w wrześniu 2003. Drukarka nie ma żadnych innych portów niż USB type B, i stała daleko od komputera a ja nie miałem tak długiego kabla żeby ją podłączyć. Więc wpadłem na pomysł aby podłączyć ją do Raspberry i zrobić z RPI serwer wydruku. Poniżej znajdują się czynność, które wykonywałem aby to skonfigurować.
+    </p>
+    <ol>
+      <li>Instalacja aktualizacji oraz niezbednych pakietów.
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt install cups
+</pre>
+      </li>
+      <li>Umożliwienie dostępu z sieci do <strong>CUPS</strong> Raspberry Pi, w normalnych warunkach CUPS nasłuchuje tylko i wyłącznie na pętli zwrotnej.
+<pre class="code-block">
+$ sudo cupsctl --remote-admin --remote-any --share-printers
+</pre>
+      </li>
+      <li>Dodawnie uprawnień użytkownikom do zarządzania drukarkami.
+        <p>
+          W pliku <em>/etc/cups/cupsd.conf</em> odszukujemy sekcję <code class="code-inline">Limit CUPS-Add-Modify-Printer</code> <strong>pierwszą napotkaną, może ich być wiele</strong>, następnie w opcji <code class="code-inline">Require user</code> po <code class="code-inline">@SYSTEM</code> dopisujemy użytkownika, w tym przypadku będzie to <em>pi</em>. Zapisujemy plik i restartujemy usługę.
+        </p>
+<pre class="code-block">
+$ sudo systemctl restart cups
+</pre>
+      </li>
+      <li>Dodawnie drukarki w systemie CUPS
+        <p>
+          W przeglądarce w pasku adresu, wpisujemy <em>http://&lt;adres_ip raspberry_pi&gt;:631</em>, klikamy na zakładkę <code class="code-inline">Administration</code>, następnie wybieramy opcje <code class="code-inline">Add printer</code>. Zostanie poproszeni o dane logowania, używamy danych logowania z użytkownika <em>pi</em>. W sekcji <code class="code-inline">Local printers</code> powinniśmy dostrzec naszą drukarkę. Jeśli tak to wybieramy ją i klikamy <code class="code-inline">continue</code>.
+                                       Następnie zaznaczamy opcję <code class="code-inline">Share this printer</code> i klikamy <code class="code-inline">continue</code>. W opcji <code class="code-inline">Model</code>, wyszukujemy model podłączonej drukarki, jeśli nie możemy go znaleźć oznacza to że nie ma sterowników zainstalowanych do naszego urządzenia. Jeśli znaleźlismy naszą drukarkę możemy teraz przejść do punktu nr. 6.
+        </p>
+      </li>
+      <li>Instalacja sterowników drukarki w systemie Linux.
+        <p>
+          Jeśli CUPS nie obsługuje naszej drukarki domyślnie, to pierwszą rzeczą jaką powinniśmy zrobić to odwiedzić stronę <a href="http://openprinting.org/printers">http://openprinting.org/printers</a>. Znajdują się na niej otwarte sterowniki drukarek. Jeśli nie znaleźliśmy na niej nic odpowiedniego dla naszego urządzenia pozostaje, nam tylko strona producenta. Po zainstalowaniu sterownika, wracamy z powrotem do punktu 4. <strong>Uwaga! Drukarki HP przy wyborze sterownika HPLIP (sterownik własnościowy), należy instalować z poziomu oprogramowania sterownika.</strong> Po zainstalowaniu sterownika za pomocą polecenia:
+        </p>
+<pre class="code-block">
+$ sudo apt install hplip
+</pre>
+        <p>
+          Uruchamiamy kreator dodawania drukarek poleceniem:
+        </p>
+<pre class="code-block">
+$ sudo hp-setup -i
+</pre>
+        <p>
+          Kreator zapyta o typ połączania (usb, lan, lpt), a następnie automtycznie wykryje podłączoną drukarkę, lub poprosi o wybór urządzenia jeśli podłączyliśmy więcej niż jedno. Po tym kreator zapyta o instalację pluginu, jest on niezbędny do obsługi naszego urządzenia. Plugin zostanie pobrany ze strony HP, w trakcie możemy otrzymać błąd <code class="code-inline">Unable to receive key from keyserver</code>, nie jest to błąd krytyczny, musimy po prostu potwierdzić że chcemy pobrać wtyczkę bez weryfikacji źródła. Po zainstalowaniu wtyczki zostanie zapytanie o dodanie kolejki wydruku, opis oraz lokalizację drukarki. Na koniec zostaniemy zapytani o stronę testową. Warto to zrobić ponieważ od razu będzie wiadomo czy drukarka współpracuje z zainstalownym właśnie sterownikiem.
+        </p>
+        <p>
+          Po wydrukowaniu strony testowej, drukarka powinna automatycznie pojawić się w panelu CUPS.
+        </p>
+      </li>
+      <li>Dodawanie drukarki w systemie Windows
+        <p>
+          Możliwe są dwa dojścia. Zauważyłem że np. drukarka <em>HP LaserJet 1020</em>, nie chcę drukować po zainstalowaniu za pomocą protokołu Bonjour firmy Apple. Mimo pojawiących się rzeczy w kolejce wydruku w panelu CUPS.
+          <ul>
+          <li>Dojście nr. 1 - protokoł Bonjour:
+              <p>
+              Na naszym Windowsie instalujemy program <a href="https://support.apple.com/kb/DL999?viewlocale=en_US&locale=en_US">Kreator drukarek Bonjour</a> Po uruchomieniu powinien automatycznie odszukać drukarę, widniejącą pod: <em>&lt;nazwa_drukarki&gt;@&lt;nazwa_hosta_raspberry&gt;</em>. Następnie wybieramy sterownik, jeśli nie znaleźliśmy naszego możemy go załadować z dysku. Na razie wybierzmy jakiś generyczny sterownik, ponieważ program lub się tu wykrzaczyć i po prostu nieoczekiwanie zamknąć. Po dodaniu drukarki, przechodzimy do jej właściwości w <code class="code-inline">Panelu sterowania</code> czy w <code class="code-inline">Ustawieniach</code>, wybieramy drukarkę klikamy na nią PPM z menu kontekstowego wybieramy opcję <code class="code-inline">Właściwości drukarki</code> następnie
+                                                       zakładkę <code class="code-inline">Zaawansowane</code> w sekcji <code class="code-inline">Sterownik</code>, kilkamy <code class="code-inline">Nowy sterownik</code> i dopiero tutaj ładujemy nasz sterownik. Dla pewności drukujemy stronę testową. To dojście działa między innymi dla HP LaserJet 1010 na Windows 10.
+              </p>
+          </li>
+          <li>Dojście nr. 2 - ręczna konfiguracja IPP:
+              <p>
+              Sposób może brzmieć skomplikowanie, jedak jest prostszy niż poprzedni... W aplecie <code class="code-inline">Urządzenia i drukarki</code>' panelu sterowania wybieramy <code class="code-inline">Dodaj drukarkę</code> następnie odnośnik <code class="code-inline">Drukarki, której szukam nie ma na liście'</code> zaznaczamy opcje <code class="code-inline">Wybierz drukarkę udostępnioną według nazwy</code> w poniższym okienku wpisujemy:
+              </p>
+<pre class="code-block">
+http://&lt;adres_ip_raspberry&gt;:631/printers/&lt;nazwa_drukarki_w_CUPS&gt;
+</pre>
+              <p>
+              Potem klikamy przycisk <code class="code-inline">Dalej</code>, system powinien się skomunikować z drukarką i wyświetlić nam okienko wyboru sterowników. Wybieramy odpowiedni dla naszego urządzenia sterownik lub ładujemy go z dysku. Po zainstalowniu, drukujemy stronę testową.
+              </p>
+          </li>
+          </ul>
+          Tutaj możemy zakończyć naszą instalację, jednak przedstawię poniżej jeszcze jeden punkt, lekko poprawiający korzystanie z CUPS.
+        </p>
+      </li>
+      <li>Dostrajanie CUPS. (Opcjonalnie)
+          <p>
+          Nie będzie tu tego wiele. Ale dwie rzeczy rzucają się w oczy przy wykorzystywaniu serwera wydruku z RPI np. w firmie. Pierwsza z nich to korzystanie z nazwy <em>FQDN</em> zamiast z adresu IP, oraz logowanie do samego panelu administracyjnego, a nie tylko do funkcji zarządzania drukarkami.
+          </p>
+          <ul>
+          <li>Przyjazna nazwa serwera wydruku.
+              <p>
+              W pliku konfiguracyjnym <em>/etc/cups/cupsd.conf</em>, edytujemy opcję <code class="code-inline">Listen</code>, ustawiając ją na <code class="code-inline">*:631</code> następnie pod nią dopisujemy opcję <code class="code-inline">ServerAlias</code> ustawiając ją na FQDN naszego serwera wydruku. Plik zapisujemy i restartujemy usługę.
+              </p>
+<pre class="code-block">
+$ sudo systemctl restart cups
+</pre>
+          </li>
+          <li>Blokada nieautoryzowanego dostępu do panelu administracyjnego CUPS.
+            <p>
+              W pliku konfiguracyjnym, odnajdujemy sekcję <code class="code-inline">&lt;Location /admin&gt;</code> dopisujemy wewnątrz niej opcję <code class="code-inline">Require user @SYSTEM pi</code>. Plik zapisujemy i restartujemy usługę.
+            </p>
+          </li>
+          </ul>
+      </li>
+      </ol>
+      <p>
+        To rozwiązanie działa... Do czasu. Po kilku miesiącach drukarka na każdą stronę wydruku, drukowała Stronę z napisem "Unsupported Personality: PCL". Pomogła zmiana sterownika z HPLIP na CUPS+Gutenprint, ale co ciekawe tylko na Debianie. Na innych systemach drukarka nie chciała w ogóle drukować na tym sterowniku. Po tych doświadczeniach stwierdzam że nie ma się co bawić w takie rozwiązania, lepiej kupić jakąś porządną drukarkę sieciową ze wsparciem zarówno dla systemów GNU/Linux jak MS Windows.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/index.html b/articles/raspberrypi/index.html
new file mode 100755 (executable)
index 0000000..78cc2f6
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+               <ul class="special_list">
+      <li><a href="mini_serwer_LXD_z_łącznością_bezprzewodową_na_Raspberry_Pi.html">Mini serwer LXD z łącznościa bezprzewodową na Raspberry Pi</a></li>
+      <li><a href="podłączanie_modułu_RDM_6300_do_Raspberry_Pi_oraz_odczyt_tagu_RFID.html">Podłączanie modułu RDM 6300 do Raspberry Pi oraz odczyt tagu_RFID</a></li>
+      <li><a href="połączenie_z_Raspberry_Pi_Zero_przez_USB.html">Połączenie z Raspberry Pi Zero przez USB</a></li>
+      <li><a href="Raspberry_Pi_jako_przekaźnik_bluetooth.html">Raspberry Pi jako przekaźnik bluetooth</a></li>
+      <li><a href="Raspberry_Pi_jako_serwer_poczty.html">Raspberry Pi jako serwer poczty</a></li>
+      <li><a href="Raspberry_Pi_jako_serwer_wydruku.html">Raspberry Pi jako serwer wydruku</a></li>
+      <li><a href="Raspberry_Pi_Zero_jako_router_3G.html">Raspberry Pi Zero jako router 3G.html</a></li>
+      <li><a href="podłączanie_7-calowego_ekranu_dotykowego_do_Raspberry_Pi.html">Podłączanie 7-calowego ekranu dotykowego (1024x600) do Raspberry Pi</a></li>
+               </ul>
+       </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/mini_serwer_LXD_z_łącznością_bezprzewodową_na_Raspberry_Pi.html b/articles/raspberrypi/mini_serwer_LXD_z_łącznością_bezprzewodową_na_Raspberry_Pi.html
new file mode 100644 (file)
index 0000000..fcb31cd
--- /dev/null
@@ -0,0 +1,320 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+       <div class="main">
+    <h1 class="title">Mini serwer LXD z łącznością bezprzewodową na Raspberry Pi</h1>
+    <p>
+      Kiedy nie mamy miejsca w domu na prawdziwy serwer, a chcemy pobawić się kontenerami, to jako alternatywy możemy użyć <strong>Raspberry Pi</strong>. Po poza samą usługą <strong>LXD/LXC</strong> do dałem jeszcze funkcję <em>AP</em>, aby można było podłączyć się do niego bez kabli.
+    </p>
+    <ol>
+      <li><strong>Dysk twardy</strong>
+        <p>
+          Do realizacji tego zadania, przyda nam się dysk twardy czy to HDD 2,5 czy 3,5" czy SSD. Obecnie Raspberry od wersji 2 drugie wspiera bootowanie z USB, przy wersji 4 należy na początku uruchomić komputer z karty następnie z aktualizować <em>bootloader</em> i również będzie taka możliwość.
+        </p>
+      </li>
+      <li><strong>Pierwsze czynności po załadowaniu nowego systemu</strong>
+        <p>
+          Zaraz po zalogowaniu do świeżego systemu, należało by zmienić domyślne hasło.
+        </p>
+<pre class="code-block">
+$ passwd
+</pre>
+        <p>
+          Podajemy obecne hasło: <em>raspberry</em>, oraz ustalamy nowe. Następną czynnością jest ustawienie lokalizacji działania sieci bezprzewodowej. <strong>Każdy kraj na własne regulacje prawne odnośnie wykorzystania pasma ISM (2,4GHz)</strong>, dlatego też interfejs sieci bezprzewodowej w RPI jest zablokowany przez rfkill, dopóki nie ustawimy kraju, w którym będziemy z niej korzystać. Uruchamiamy <code class="code-inline">$ sudo raspi-config</code>, następnie wybieramy <code class="code-inline">4 Localisation Options</code> -> <code class="code-inline">I4 Change Wi-Fi Country</code> -> <code class="code-inline">PL Poland</code> potwierdzamy <code class="code-inline">OK</code>. Zostaniemy poinformowani o ustawieniu lokalizacji.
+        </p>
+      </li>
+      <li><strong>Aktualizacja systemu</strong>
+        <p>
+          Teraz zainstalujemy aktualizacje systemu i przejdziemy do konfiguracji połączenia z Internetem.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+      </li>
+      <li><strong>Konfigurowanie dostępu do internetu.</strong>
+        <p>
+          Możemy pozostawić to takie jakie jest, czyli dostęp realizowany po kablu. Jednak traci to trochę na mobilności. Dlatego proponuje dołożyć drugą kartę bezprzewodową, aby również połączenie z internetem odbywało się za pomocą sieci bezprzewodowej. W moim przypadku użyłem <em>TP-Link Archer T2U</em>. Karta jest dwuzakresowa jednak nie działa <em>out of box</em> z RasPiOS, jeśli chcemy jej użyć musimy wykonać poniższe czynności.
+        </p>
+        <ol>
+          <li>Pobieramy paczke oficjalnego firmware-u i przechodzimy do pobranego katalogu (jeśli nie ma <em>git</em>, to instalujemy go z repozytorium <code class="code-inline">$ sudo apt instal git</code>).
+<pre class="code-block">
+  $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
+
+  $ cd linux-firmware
+</pre></li>
+        <li>Tworzymy katalog 'mediatek' na <em>/lib/firmware</em>.
+<pre class="code-block">
+$ sudo mkdir /lib/firmware/mediatek
+</pre>
+        </li>
+        <li>Kopiujemy sterownik do naszego nowo utworzonego katalogu.
+<pre class="code-block">
+$ sudo cp mediatek/mt7610u.bin /lib/firmware/mediatek/
+</pre>
+        </li>
+        <li>Usuwamy niekompatybilny moduł z jądra systemu.
+<pre class="code-block">
+$ sudo rmmod mt76x0
+</pre>
+        <p>
+          Gdyby pojawił się taki komunikat o błedzie:
+        <p>
+<pre class="code-block">
+rmmod: ERROR: ../libkmod/libkmod.c:514 lookup_builtin_file() could not open builtin file '/lib/modules/4.19.97-v7+/modules.builtin.bin'
+</pre>
+        <p>
+          To należy zresetować malinkę: <code class="code-inline">$ sudo reboot</code>
+        </p>
+        </li>
+        <li>Dodajemy nowy moduł do jądra.
+<pre class="code-block">
+$ sudo modprobe mt76x0
+</pre>
+        </li>
+        </ol>
+        <p>
+          Po wprowadzeniu powyższych czynności karta powinna już działać, można to przetestować skanując sieci bezprzewodowe.
+        </p>
+<pre class="code-block">
+$ sudo iwlist wlan1 scan
+</pre>
+      </li>
+                       <li><strong>Konfiguracja interfejsu AP</strong>
+                               <p>
+                                       Aby wybudowany interfejs sieci bezprzewodowej mógł być punktem dostępu musi mieć adress ip, które jednocześnie będzie bramą dla jego sieci. Aby nadać mu adres IP w pliku <em>/etc/dhcpcd.conf</em> na samym dole dopisujemy poniższe opcje:
+                               </p>
+<pre class="code-block">
+interface wlan0
+static ip_address=192.168.4.1/24
+nohook wpa_supplicant
+</pre>
+                       </li>
+                       <li><strong>Instalacja i konfiguracja serwera dhcp oraz demona punktu dostępu</strong>
+                               <p>
+                                       Do stworzenia sieci bezprzewodowej potrzebny jest serwer odpowiedzialny za przydział adresów IP oraz program który tak skonfiguruje wbudowaną kartę by rozgłaszała sygnał sieci. Instalujemy dwa pakiety:
+                               </p>
+<pre class="code-block">
+$ sudo apt install hostapd dnsmasq
+</pre>
+                               <p>
+                                       Zmieniamy nazwę pliku konfiguracyjnego <em>dnsmasq</em> dostarczonego wraz z pakietem, ponieważ nie będzie on nam potrzebny jednak warto go zachować gdyż może być bazą wiedzy na temat konfiguracji usługi.
+                               </p>
+<pre class="code-block">
+$ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.init
+</pre>
+                               <p>
+                                       Tworzymy nowy plik i zapisujemy w nim poniższe linie, oczywiście adresy zakresu należy dobrać do adresu ustawionego na wlan0.
+                               </p>
+<pre class="code-block">
+interface=wlan0
+dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
+</pre>
+                               <p>
+                                       Teraz należy zrestartować usługę.
+                               </p>
+<pre class="code-block">
+$ sudo systemctl restart dnsmasq
+</pre>
+                               <p>
+                                       Następnie przechodzimy do pliku konfiguracyjnego daemon <em>hostapd</em>. Plik ten najprawdopodobniej nie istnieje, więc do nowego pliku <em>/etc/hostapd/hostapd.conf</em> wpisujemy poniższą konfiguracje.
+                               </p>
+<pre class="code-block">
+interface=wlan0
+driver=nl80211
+ssid=rpilxdsrv
+hw_mode=g
+channel=6
+wmm_enabled=1
+ieee80211n=1
+macaddr_acl=0
+auth_algs=1
+ignore_broadcast_ssid=1
+wpa=2
+wpa_passphrase=123_LxD_123
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+rsn_pairwise=CCMP
+</pre>
+                               <p>
+                                       To nie koniec konfiguracji, otóż daemonowi należy jeszcze wskazać ścieżkę do pliku konfiguracjnego w pliku <em>/etc/default/hostapd</em>. Otwieramy plik, odszukujemy linie zawierajacą <code class="code-inline">DAEMON_CONF=""</code>, usuwamy znajdujący się na początku znak komentarza, pomiędzy podwójnymi apostrofami umieszczamy ścieżkę do pliku.
+                               </p>
+<pre class="code-block">
+DAEMON_CONF="/etc/hostapd/hostapd.conf"
+</pre>
+                               <p>
+                                       Aby uruchmić usługę należy wydać poniższe polecenia.
+                               </p>
+<pre class="code-block">
+$ sudo systemctl unmask hostapd
+$ sudo systemctl enable hostapd
+$ sudo systemctl start hostapd
+</pre>
+                       </li>
+                       <li><strong>NAT i przekazywanie pakietów</strong>
+                               <p>
+                                       Włączenie przekazywania pakietów na Raspberry Pi jest dziecinnie proste sprowadza się do usunięcia znaku komentarza z linii <code class="code-inline">#net.ipv4.ip_forwarding=1</code> w pliku <em>/etc/sysctl.conf</em>. Uruchomienie NAT-u, to w sumie też jedno polecenie.
+                               </p>
+<pre class="code-block">
+$ sudo iptables -t nat -A POSTROUTING -o &lt;interfejs połączenia z internetem&gt; -j MASQUERADE
+</pre>
+                               <p>
+                                       Jednak kiedy uruchomimy ponownie nasze RPI, reguła NAT-u zniknie. Aby reguły <em>iptables</em> były stałe są zapisywane do pliku, a przy uruchomieniu systemu odtwarzane, aby to zrealizować musimy  zainstalować pakiet <em>iptables-persistent</em>.
+                               </p>
+<pre class="code-block">
+$ sudo apt install iptables-persistent
+</pre>
+                               <p>
+                                       Podczas instalacji, zostaniemy zapytani o to czy zapisać istniejące już reguły. Możemy to zrobić. Przy każdym zapisie plik jest nadpisywany obecnie załdowanymi do iptables regułami. Reguły najlepiej zapisywać po każdej zmianie, poniżej znajduje się polecenie odpowiedzialne za ich przywrócenie, należy umieścić je w pliku <em>/etc/rc.local</em> przed linią <code class="code-inline">exit 0</code>.
+                               </p>
+<pre class="code-block">
+iptables-restore < /etc/iptables/rules.v4
+</pre>
+                       </li>
+                       <li><strong>Połączenie z internetem</strong>
+                               <p>
+                                       Kiedy mamy już gotową bramkę pozostaje nam tylko połączyć się z Internetem, połączenie to będzie udostępniane przez nasz mikroserwer za pomocą sieci bezprzewodowej. Jeśli łączymy się po kablu, to tak naprawdę wystarczy go wpiąć i możemy przejść do kolejnego punktu. Jeśli połączenie będziemy realizować za pomocą sieci bezprzewodowej, to teraz się z taką siecią połączymy. Zestawianie połaczenia rozpoczynamy od znalezienia naszej sieci docelowej, skanowania dokonujemy za pomocą polecenia:
+                               </p>
+<pre class="code-block">
+$ sudo iwlist wlan1 scan
+</pre>
+                               <p>
+                                       Odszukujemy sieć do której chcemy się podłączyć następnie na podstawie zabezpieczeń sieci wybieramy z jedną z metod sparowania się.
+                               </p>
+                               <ul>
+                                       <li>sieć otwarta -
+<pre class="code-block">
+$ sudo iwconfig wlan1 essid "ssid"
+</pre>
+                                       </li>
+                                       <li>WEP -
+<pre class="code-block">
+$ sudo iwconfig wlan1 essid "ssid" key "kluczWEP"
+</pre>
+                                       </li>
+                                       <li>WPA/WPA2 -
+<pre class="code-block">
+$ sudo wpa_passphrase "ssid" "psk" | sudo tee /etc/wpa_supplicant/wpa_supplicant.conf
+
+$ sudo wpa_supplicant -B -c /etc/wpa_supplicant/wpa_supplicant.conf -i wlan1
+</pre>
+                                       </li>
+                               </ul>
+                               <p>
+                                       Bez względu na wybrany typ sieci, musimy pobrać z niej adres IP, co jest realizowane przez poniższe polecenie.
+                               </p>
+<pre class="code-block">
+$ sudo dhclient wlan1
+</pre>
+                               <p>
+                                       Z racji tego iż ta czynność będzie wykonywana za każdym razem gdy użytkownik będzie podłączał się do Internetu. <em>Dnsmasq</em> nie posiada adresu, na który mógłby przekazywać pakiety. Dnsmasq nie jest serwerem DNS sam w sobie. Jest tylko przekaźnikiem co nawet tłumaczy jego nazwa. Po pobraniu adresu IP z docelowej sieci, należy  zrestartować dnsmasq, aby mógł wczytać ten adres i zapewnić swobodny dostęp do Internetu.
+                               </p>
+<pre class="code-block">
+$ sudo systemctl restart dnsmasq
+</pre>
+                               <p>
+                                       Powyższy sposób można zautomatyzować, o ile będziemy się łączyć przez cały czas z tą samą siecią. Dodajemy polecenie sparowania z siecią oraz polecenie pobrania adresu ip do pliku <em>/etc/rc.local</em> nad przywróceniem reguł iptables.
+                               </p>
+                       </li>
+                       <li><strong>Instalacja LXD</strong>
+                               <p>
+                                       Aby zainstalować <em>LXD</em>, potrzebujemy znanego z Ubuntu managera pakietów snap oraz oprogramowania to tworzenia mostów. Instalujemy wymagane oprogramowanie.
+                               </p>
+<pre class="code-block">
+$ sudo apt install snapd bridge-utils
+</pre>
+                               <p>
+                                       Następnie instalujemy <em>lxd</em> oraz inny wymagany do uruchomienia czego kolwiek z <em>snap</em> pakiet.
+                               </p>
+<pre class="code-block">
+$ sudo snap install core
+$ sudo snap install lxd --channel=3.0/stable
+</pre>
+                               <p>
+                                       Po zainstalowaniu dodajemy użytkownika <code class="code-inline">pi</code> do grupy <code class="code-inline">lxd</code>, za pomocą poniższego polecenia.
+                               </p>
+<pre class="code-block">
+$ sudo usermod -aG lxd pi
+</pre>
+                               <p>
+                                       Przelogowywujemy się na użytkownika <em>root</em>.
+                               </p>
+<pre class="code-block">
+$ sudo su
+</pre>
+                               <p>
+                                       Dodajemy tymczasowo <em>/snap/bin</em> do zmiennej <code class="code-inline">PATH</code>.
+                               </p>
+<pre class="code-block">
+# export PATH=${PATH}:/snap/bin
+</pre>
+                               <p>
+                                       Zatrzymujemy usługę 'dnsmasq'.
+                               </p>
+<pre class="code-block">
+# systemctl stop dnsmasq
+</pre>
+                               <p>
+                                       Inicjujemy LXD.
+                               </p>
+<pre class="code-block">
+# lxd init
+</pre>
+                               <p>
+                                       Opis poszczególnych pytań znajdziemy <a href="../linux/instalacja_konterów_lxd.html">https://morketsmerke.net/articles/linux/instalacja_konterów_lxd.html</a>.
+                               </p>
+                               <p>
+                                       Po zainicjowaniu LXD musimy dokonać małych zmian w konfiguracji naszego dnsmasq, otwieramy plik <em>/etc/dnsmasq.conf</em>, po opcji <code class="code-inline">interface=wlan0</code> dopisujemy poniższe opcje.
+                               </p>
+<pre class="code-block">
+except-interface=lxdbr0
+bind-interfaces
+</pre>
+                               <p>
+                                        Teraz możemy ponownie uruchomić dnsmasq.
+                               </p>
+<pre class="code-block">
+# systemctl restart dnsmasq
+</pre>
+                               <p>
+                                        Wylogowujemy się zupełnie z Raspberry, po to aby zmienna <code class="code-inline">PATH</code> się przeładowała. Po ponownym zalogowaniu możemy uruchomić nasz pierwszy kontener.
+                               </p>
+<pre class="code-block">
+$ lxc launch ubuntu:18.04 &lt;nazwa kontenera&gt;
+</pre>
+                       </li>
+    </ol>
+               <p>
+                       Jak widać powyżej nie trzeba władać potężnymi serwera, aby móc korzystać z usług konteneryzacji. W tym przypadku jest LXD, ale równie dobrze może być np. <em>Docker</em>.
+               </p>
+               <p>
+                       ~xf0r3m
+               </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/podłączanie_7-calowego_ekranu_dotykowego_do_Raspberry_Pi.html b/articles/raspberrypi/podłączanie_7-calowego_ekranu_dotykowego_do_Raspberry_Pi.html
new file mode 100644 (file)
index 0000000..9008f76
--- /dev/null
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Podłączanie 7-calowego ekranu dotykowego (1024x600) do Raspberry Pi</h1>
+    <p>
+      W długi weekend majowy, kolega poprosił mnie podłączenie 7-calowego
+      wyświetlacza do Raspberry Pi. Oczywiście przez podłączenie należy
+      rozumieć fizczne podłączenie oraz skonfigurowanie systemu w taki sposób,
+      aby wyświetlał obraz, dopasowany do właściwości ekranu.
+      Mój zleceniodawca utknął przy ładowaniu środowiska
+      graficznego. Po powrocie do pracy, wziąłem od niego wyświetlacz i
+      przystąpiłem do działania, nie brałem jego maliny ponieważ chciałem
+      na początku sam dowiedzieć się jak to się podłącza. Na naprawę jego
+      konfiguracji przyjdzie jeszcze czas...
+    </p>
+    <p>
+      Jak każdą świeżą zabawę z malinką, rozpoczynam od pobrania najnowszego
+      obrazu i załadowania go na kartę microSD. Dla celów testowych, najlepiej
+      użyć obrazu z preinstalowanym środowiskiem graficznym, najlepiej bez
+      zbędnego (rekomendowanego) oprogramowania.
+    </p>
+<pre class="code-block">
+  $ wget https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2022-04-07/2022-04-04-raspios-bullseye-armhf.img.xz
+  $ unxz 2022-04-04-raspios-bullseye-armhf.img.xz
+  $ sudo dd if=2022-04-04-raspios-bullseye-armhf.img bs=1M of=/dev/sdX status=progress
+</pre>
+    <p>
+      Na powyższym listingu <code class="code-inline">/dev/sdX</code> jest 
+      plikiem urządzenia
+      reprezentującym podłączoną kartę microSD. Obraz po rozpakowaniu ma lekko
+      powyżej 4 gigabajtów. Po nagraniu obrazu, zanim włóżymy kartę do 
+      urządzenia
+      możemy dokonać niezbędnych modyfikacji, tak aby nie trzeba było się
+      przełączać między ekranami.
+    </p>
+    <p>
+      Zmian dokonujemy
+      w pliku <em>config.txt</em> na partycji <em>boot</em>. Na samym końcu 
+      pliku zapisujemy poniższe linie.
+    </p>
+<pre class="code-block">
+max_usb_current=1
+hdmi_group=2
+hdmi_mode=87
+hdmi_cvt=1024 600 60 6 0 0 0
+hdmi_ignore_edid=0xa5000080
+config_hdmi_boost=2
+</pre>
+    <ul>
+      <li><code class="code-inline">max_usb_current</code> - załączenie
+        maksymalnego możliwego natężenia prądu na USB. Normalnie jest 600 mA,
+        jednak przy użyciu tej opcji, prąd wzrasata do 1,2 A.</li>
+      <li><code class="code-inline">hdmi_group</code> - określa grupę
+        wyświetlaczy korzystających z HDMI. Na przykład telewizory oraz
+        monitory korzystają zupełnie innych standardów. Monitory podłączane
+        do komputerów jak i omawiany tutaj wyświetlacz należą do grupy
+        oznaczonej przez cyfrę <code class="code-inline">2</code>.</li>
+      <li><code class="code-inline">hdmi_mode</code> - definiuje domyślną
+        rodzielczość, odświeżanie oraz aspekt ekranu. Na stronie podanej
+        w źródłach znajduje się tabela z trybami HDMI dla grupy 2, nie ma tam 
+        trybu 87.
+        Nadanie tej opcji takiej wartości, pozwoli użyć stworzonego przez opcję
+        <code class="code-inline">hdmi_cvt</code> tryby w drugiej grupie.</li>
+      <li><code class="code-inline">hdmi_cvt</code> - umożliwia wpisanie
+        własnych ustawień standardu <em>VESA CVT</em>, dając możliwość 
+        zdefiniowania rozdzielczości,
+        częstotliwości obrazu oraz jego formatu. Pozostałe trzy zera odnoszą
+        się głównie do cech ekranów kineskopowych i mogą zostać pominięte,
+        ponieważ w naszym przypadku są to domyślne wartości. Użycie tej opcji
+        wiąże się ze wskazaniem nowego trybu z pomocą opcji
+        <code class="code-inline">hdmi_group</code> oraz
+        <code class="code-inline">hdmi_mode</code>.</li>
+      <li><code class="code-inline">hdmi_ignore_edid</code> - opcją załącza
+        ignorowanie danych identyfikacyjnych wyświetlacza, jeśli wyświetlacz
+        ich nie posiada. Użycie wartości <code class="code-inline">0xa5000080</code>
+        chroni tę opcję przed omyłkowym przełączeniem.</li>
+      <li><code class="code-inline">config_hdmi_boost</code> - złacza
+        wzmocnienie sygnału HDMI. Ta wartość jest ignorowana przez Raspberry
+        Pi 4. W źródle podano konkretne przypadki, który należy użyć
+        odpowiednich wartości tej opcji.</li>
+    </ul>
+    <p>
+      Zapisujemy zmiany w pliku. Teraz możemy włożyć kartę do maliny a
+      następnie podłączyć nasz wyświetlacz.
+    </p>
+    <p>
+      7-calowych wyświetlaczy do RPi jest
+      dostępnych na rynku bardzo wiele, różnią się one rodzielczością oraz 
+      ilością dostępnych złączy. Część z nich to po prostu chińskie klony
+      oryginalnego produktu marki <em>WaveShare</em>, i ja również otrzymałem
+      taki klon. Głowną różnicą są chyba złącza znajdujące się z tyłu
+      wyświetlacza. Wyświetlacz, który ja otrzymałem wyglądał mniej więcej 
+      tak:
+    </p>
+    <p>
+      <img src="https://i.ibb.co/h7RDQLh/7-inch-display.jpg" alt="7-inch-display" border="0" style="width: 100%;">
+    </p>
+    <p>
+      Mniej więcej, ponieważ zdjęcia nie zrobiłem, a obrazek powyżej jest tylko
+      zdjęciem poglądowym. Oryginalny wyświetlacz 7-calowy firmy
+      <em>WaveShare</em> został przedstawiony poniżej (przynajmniej jego tył).
+    </p>
+    <p>
+      <img src="https://i.ibb.co/tmPPRr0/7-inch-waveshare.jpg" alt="7-inch-waveshare" border="0" style="width: 100%;">
+    </p>
+    <p>
+      Istotną w naszym przypadku różnicą są złącza. W oryginalny wyświetlacz
+      mamy tylko jedno złącze USB, natomiast w klonie dwa i oba podpisane jako
+      "<em>touch</em>". Więc jeśli dysonujemy klonem <strong>Kabel USB 
+      podłączamy po <u>drugiego</u> portu USB, nad przełącznikiem 
+      "<em>Backlight</em>"</strong>. Z HDMI to chyba wiadomo. Po podłączeniu
+      możemy uruchomić Raspberry. Po nieco dłuższym procesie uruchamiania,
+      na wyświetlaczu pojawi się fragment obrazu. Obraz wyświetlany przez
+      system operacyjny jest w znaczanie większej rozdzielczości niż
+      obsługiwana przez wyświetlacz. Serwer X Window, nie był wstanie dobrać
+      odpowiedniej rozdzielczości dlatego też musimy ją wymusić. Aby to zrobić
+      tworzymy mały skrypt powłoki z poniższych poleceń. Jednak przed
+      przystąpieniem do pisania skryptu należy jeszcze poznać nazwę wyjścia
+      wideo jaka figuruje na serwerze X Window, za pomocą polecenia
+      <strong>xrandr</strong> jesteśmy w stanie wypisać dostępne w systemie
+      wyjścia wideo, nazwy znajdują się na początku linii nad listą dostępnych
+      rozdzielczości dla danego wyświetlacza. W moim przypadku było to 
+      <code class="code-inline">HDMI-2</code>.
+    </p>
+<pre class="code-block">
+#!/bin/bash
+
+xrandr --newmode "1024x600_60.00" 49.00 1024 1072 1168 1312 600 603 613 624 -hsync +vsync
+xrandr --addmode HDMI-2 1024x600_60.00
+xrandr --output HDMI-2 --mode 1024x60_60.00
+</pre>
+    <p>
+      Wartości użyte w poleceniu <code class="code-inline">xrandr --newmode</code>
+      zostały uzyskane za pomocą poniższego polecenia:
+    </p>
+<pre class="code-block">
+$ cvt 1024 600 60
+</pre>
+    <p>
+      Polecenie to generuje ustawienia obrazu w standardzie <em>VESA CVT</em>,
+      które są niezbędne przy tworzeniu niestandardowych trybów wyświetlania.
+      Niestety aby wyjaśnić kolejne wartości zwracane przez to polecenie,
+      trzeby by zagłegić się w lekturę standardu, co wykracza poza ramy tego
+      materiału. Najlepiej jest poprostu skopiować fragment wyjścia polecenia
+      <code class="code-inline">cvt</code>, do argumentu polecenia
+      <code class="code-inline">xrandr --newmode</code>.
+    </p>
+    <p>
+      Skrypt zapisujemy pod wygodną dla nas nazwą, w miejscu gdzie nie zostanie
+      przypadkowo usunięty. Następnie, musimy zmusić system do tego aby
+      uruchomił on ten skrypt przed wyświetleniem użytkownikowi pulpitu. Do
+      tego posłużymy się plikiem <em>/etc/xdg/lxsession/LXDE-pi/autostart</em>.
+      Nad linią <em>@xscreensaver -no-splash</em> zapisujemy poniższą linię:
+    </p> 
+<pre class="code-block">
+@lxterminal -e "&lt;ścieżka_do_skryptu&gt;"
+</pre>
+    <p>
+      Następnie zapisujemy zmiany, dla pewności możemy przekopiować również
+      ten plik do katalogu <em>/etc/xdg/lxsession/LXDE</em>, aby mieć pewność,
+      że na pewno się uruchomi.
+    </p>
+    <p>
+      Teraz moży uruchomić ponownie Raspberry. Po uruchomieniu pulpit powinien
+      być idealnie dopasowany do używanego przez nas wyświetlacza.
+    </p>
+    <p>
+      Źródła:
+      <ol>
+        <li><a href="https://www.youtube.com/watch?v=TYzOhgUmZcw">Konfiguracja wyświetlania obrazu w pliku config.txt</a></li>
+        <li><a href="https://www.raspberrypi.com/documentation/computers/config_txt.html">Dokumentacja opcji w pliku /boot/config.txt</a></li>
+        <li><a href="https://ronboelectronics.en.made-in-china.com/product/usynxqbMlFkW/China-Capacitive-Touch-7-0-Inch-1024X600-HDMI-LCD-Monitor-Panel-with-Driver-Board-for-Raspberry-Pi-PC-Monitor.html">Zdjęcie chińskiego klona wyświetlacza WaveShare</a></li>
+        <li><a href="https://allegro.pl/oferta/lcd-raspberry-pi-tft-7-c-ver-3-1-hdmi-7707088006">Zdjęcie przedstawiające tył oryginalnego wyświetlacza</a></li>
+        <li><a href="https://raspberrypi.stackexchange.com/questions/106569/where-to-put-pi-users-startup-scripts-raspbian-x11">Scieżka do pliku autostartu</a></li>
+        <li><a href="https://www.wikihow.com/Execute-a-Script-at-Startup-on-the-Raspberry-Pi#Using-the-Autostart-File">Co należy wpisać w pliku autostartu</a></li>
+      </ol>
+    </p>
+    <p>
+      ~xf0r3m
+    </p>
+       </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/podłączanie_modułu_RDM_6300_do_Raspberry_Pi_oraz_odczyt_tagu_RFID.html b/articles/raspberrypi/podłączanie_modułu_RDM_6300_do_Raspberry_Pi_oraz_odczyt_tagu_RFID.html
new file mode 100644 (file)
index 0000000..d96c99f
--- /dev/null
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+       </p>
+
+       <div class="main">
+    <h1 class="title">Podłączanie modułu RDM 6300 do Raspberry Pi oraz odczyt tagu RFID</h1>
+    <p>
+      Jedną z ciekawszych rzeczy jakie możemy podłączyć do Raspberry Pi jest <strong>moduł RDM6300 - RFID</strong>. Za jego pomocą możemy odczytać tag RFID ukryty na kartach lub brelokach, poźniej możemy go wykorzystać w innych programach. Przygotowałem materiał jak podłączyć czytnik i odczytać RFID tag.
+    </p>
+    <ol>
+      <li>Nagrywamy obraz z <em>RasPiOS</em> na kartę microSD.</li>
+      <li>Wkładamy kartę do urządzenia, podłaczamy i logujemy się czy to lokalnie czy przez SSH.</li>
+      <li>Uruchamiamy program konfiguracji Raspberry Pi za pomocą poniższego polecenia:
+<pre class="code-block">
+$ sudo rasp-config
+</pre>
+        <p>
+          Z opcji wybieramy kolejno <code class="code-inline">Interfacing Options</code> -> <code class="code-inline">P6 Serial</code> -> <code class="code-inline">TAK/Yes</code>. Na koniec potwierdzamy że chcemy zrestartować system.
+        </p>
+      </li>
+      <li>Podłączamy nasz moduł wg. poniższego schematu:<br />
+        <img src="https://i.ibb.co/cTw7KzW/Pod-czanie-RDM6300-do-RPI.png" alt="Schemat podłączenia RDM6300 do Raspberry Pi"/>
+      </li>
+      <li>Jeśli mamy zainstalowany pakiet <em>picocom</em>, możemy sprawdzić czy nasz moduł działa poprawnie. Wydajmy polecenie:
+<pre class="code-block">
+$ sudo picocom /dev/serial0 -b 9600
+</pre>
+      <p>
+        Kiedy przyłożymy kartę czy brelok do anteny, powinniśmy na ekranie zobaczyć ciągi cyfr. Jeśli się wyświetlają oznacza to, że nasz moduł jest poprawnie podłączony i gotowy do pracy.
+      </p>
+      </li>
+      <li>Zanim przejdziemy do odczytu tagu z karty/breloka musimy zainstalować bibliotekę <em>python-serial</em>, która umożliwi użycie kodu Pythona do komunikacji z linią szeregową.
+<pre class="code-block">
+$ sudo apt install python-serial
+</pre>
+      </li>
+      <li>Aby odczytać jednokrotnie tag z naszej karty, potrzeby będzie nam kod napisany w Pythonie, ja znalazłem bardzo podbny skrypt na jedej ze stron poświęconych właśnie podłączeniu <em>RDM6300</em> do RPI. Lekko go przerobiłem, po to aby program oczekiwał na przyłożenie karty/breloka, odczytał <em>RFID</em> tag i zakończył działanie. Później taki możemy go wysłać np. potokiem do innego programu, w celu dalszego przetwarzania.
+<pre class="code-block">
+import time
+import serial
+import RPi.GPIO as GPIO
+GPIO.setmode(GPIO.BCM)
+
+PortRF = serial.Serial('/dev/serial0',9600)
+ID = ""
+read_byte = PortRF.read()
+if read_byte=="\x02":
+  for Counter in range(12):
+    read_byte=PortRF.read()
+    ID = ID + str(read_byte)
+
+print ID
+</pre>
+        <p>
+          Dla przykładu zapiszemy plik pod nazwą: <em>RFID.py</em>. Wywołanie programu jest banalnie proste wystarczy wydać polecenie.
+        </p>
+<pre class="code-block">
+$ sudo python RFID.py
+</pre>
+        <p>
+          Po przyłożeniu karty/breloka do anteny, powinniśmy zobaczyć tag RFID i program powinien zakończyć swoje działanie.
+        </p>
+      </li>
+    </ol>
+    <p>
+      Pomysł na RFID miał swój początek w pomyśle na manager haseł zbudowany na Raspberry Pi, hasła trzymałbym za pomocą programu pass, zaszyfrowane kluczem GPG. Hasłem do klucza byłby RFID TAG z breloka na przykład. Porzuciłem projekt, ale może kiedyś do niego wrócę.
+    </p>
+    <p>
+      ~xf0r3m
+    </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/raspberrypi/połączenie_z_Raspberry_Pi_Zero_przez_USB.html b/articles/raspberrypi/połączenie_z_Raspberry_Pi_Zero_przez_USB.html
new file mode 100644 (file)
index 0000000..57e4e39
--- /dev/null
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+               <meta charset="utf-8" />
+       </head>
+       <body>
+               <pre>
+               <span style="color: green;">     .~~.   .~~.
+                   '. \ ' ' / .'</span>
+               <span style="color: red;">     .~ .~~~..~.</span>                       _                          _
+               <span style="color: red;">    : .~.'~'.~. :</span>      ___ ___ ___ ___| |_ ___ ___ ___ _ _    ___|_|
+               <span style="color: red;">   ~ (   ) (   ) ~</span>    |  _| .'|_ -| . | . | -_|  _|  _| | |  | . | |
+               <span style="color: red;">  ( : '~'.~.'~' : )</span>   |_| |__,|___|  _|___|___|_| |_| |_  |  |  _|_|
+               <span style="color: red;">   ~ .~ (   ) ~. ~</span>                |_|                 |___|  |_|
+               <span style="color: red">    (  : '~' :  )</span>
+               <span style="color: red;">     '~ .~~~. ~'
+                        '~'</span>
+               </pre>
+
+       <p class="header_link">
+               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+
+       </p>
+
+       <div class="main">
+    <h1 class="title">Połączenie z Raspberry Pi Zero przez USB</h1>
+               <p>
+                       <strong>Raspberry Pi Zero</strong>, to dziwny komputerek... Pozbawiony łączności, ze złączem mini-HDMI, oraz jednym portem micro-USB, jest nieco większy niż od listka gumy do żucia i kosztuje ok. 20 zł oczywiście w przeliczeniu $5 na złotówki, bo chyba w żadnym sklepie nie znajdziemy w tej cenie. Jeśli ktoś zaczyna swoją przygodę z tego rodzaju zabawkami, to może sobie sprawić coś takiego. I własnie tym materiałem udowodnie że poza kablem micro-USB (takim do przesyłania danych, nie tylko ładowania), kartą microSD i komputerem z GNU/Linux-em nie potrzebujemy innych akcesoriów, aby móc z niego korzystać.
+               </p>
+               <ol>
+                       <li>Wgrywamy system operacyjny na kartę możemy uzyć do tego programu Balena Etcher, lub klasycznego polecenia <code class="code-inline">dd</code>.</li>
+                       <li>Po nagraniu systemu na kartę, pojawią nam się w systemie dwie dodatkowe partycje. Przechodzimy do partycji oznaczonej
+                       jako <em>boot</em>.</li>
+                       <li>Otwieramy plik <em>config.txt</em> i na samym dole dopisujemy <code class="code-inline">dtoverlay=dwc2</code>. Plik zapisujemy i zamykamy.</li>
+                       <li>Otwieramy plik <em>cmdline.txt</em> i po słowie <code class="code-inline">rootwait</code> dopisujemy <code class="code-inline">modules-load=dwc2,g_ether</code>.</li>
+                       <li>Bezpośrednio na partycji <em>boot</em> tworzymy nowy pusty plik o nazwie <em>ssh</em>.</li>
+                       <li>Wyciągamy kartę, wkładamy ją do naszego RPI. Następnie <strong>kabel podłączamy do komputera i do portu USB Raspberry (to bardzo ważne)</strong>!</li>
+                       <li>W systemie (Ubuntu 20.04 amd64), powinna pojawić się kolejna karta sieciowa. Jeśli pojawia się łaczenie oraz dostajemy
+       powiadomienie że <code class="code-inline">Włączenie sieci nie powiodło się</code>", musimy ustawić nasz interfejs na <em>local-link</em>. Jeśli używamy środowiska <em>Gnome</em>, to przechodzimy do <code class="code-inline">Ustawienia</code> -> <code class="code-inline">Sieć</code> -> przycisk opcji przy <code class="code-inline">Ethernet (USB)</code> -> zakładkę <code class="code-inline">IPv4</code> -> <code class="code-inline">Metoda IPv4: Tylko Local-Link</code> ->
+                       <code class="code-inline">Zastosuj</code>, następnie wyłączamy włączamy interfejs, klikając na przełącznik obok przycisku opcji. Teraz powinniśmy dostać jeden z adresów z tej klasy 169.254.X.Y/16 i moć się połączyć z RPI.</li>
+                       <li>Łączymy sie z Raspberry przez SSH:
+<pre class="code-block">
+$ ssh pi@raspberrypi.local
+</pre></li>
+                       <li>Po zalogowaniu, powinniśmy od razu zmienić hasło. Zatem <code class="code-inline">passwd</code>. Po zmienia hasła przydałoby się połączenie z Internetem. Żeby chociaż zaktualizować system. Na nowej karcie terminala, na naszym komputerze uruchamiamy przekazywanie pakietów oraz za pomocą <em>iptables</em> załączamy NAT. Jeśli martwimy się o bałagan, to po zabawie z RPI, robimy <code class="code-inline">reboot</code> i wszystko wraca do normy. Załączenie przekazywania pakietów:<br />
+                       <br />
+<pre class="code-block">
+$ sudo sysctl net.ipv4.ip_forward=1
+</pre>
+                               <p>
+                       Włączenie NAT-u:
+                               </p>
+<pre class="code-block">
+$ sudo iptables -t nat -I POSTROUTING -o &lt;interfejs sieciowy naszego komputera&gt; -j MASQUERADE
+</pre>
+                               <p>
+                       To jeszcze nie wszystkie czynności, aby RPI 0 miało dostęp do Internetu. Wydając polecenie <code class="code-inline">ip a</code> odszukujemy intefejsu 'usb0', zapamiętujemy, lub zapisujemy gdzieś przypisany mu adres. Następnie na Raspberry dodaje trasę bramy domyślnej wskazując właśnie ten adres.
+                               </p>
+<pre class="code-block">
+$ sudo ip route add default via &lt;adres interfejsu USB0 na naszym komputerze&gt;
+</pre>
+                               <p>
+                       Po dodaniu bramy, możemy smiało wydawać polecenia: <code class="code-inline">apt update</code> oraz <code class="code-inline">apt upgrade</code>
+                               </p>
+                       </li>
+               </ol>
+               <p>
+                       Jak widać na powyższych czynnościach nie potrzeba masy akcesoriów jakby się mogło wydawać patrząc na to jak niepozorne jest to urządzenie. Gdyby nie to że trzeba wlutować pinów do GPIO, to korzytał bym RPI Zero przy swoich projektach.
+               </p>
+               <p>
+                       ~xf0r3m
+               </p>
+       </div>
+               <p class="footer">
+                       2021; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+       </body>
+       </html>
diff --git a/articles/terminallog/BASH_bushido.html b/articles/terminallog/BASH_bushido.html
new file mode 100755 (executable)
index 0000000..f31ace4
--- /dev/null
@@ -0,0 +1,1295 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+      <style>
+        body {
+          width: 99%;
+          height: 100vh;
+        }
+        .main {
+          width: 100%;
+        }
+      </style>
+               </head>
+               <body>
+       <div class="main">
+    <div id="tableOfContent">
+               <h1>BASH Bushido</h1>
+                               <ol>
+                       <li><a href="#1.keyboardshortcuts">Skróty klawiszowe</a></li>
+                       <li><a href="#2.vim">Edytor Vi(m)</a></li>
+                       <li><a href="#3.config">Konfiguracja BASH</a></li>
+                       <li><a href="#4.history">Historia</a></li>
+                       <li><a href="#5.indicators">Desygnatory oraz modyfikatory</a></li>
+                       <li><a href="#6.aliases">Aliasy</a></li>
+                       <li><a href="#7.top">Menadżer zadań w UNIX-ach</a></li>
+                       <li><a href="#8.printf">Fancy napisy w terminalu</a></li>
+                       <li><a href="#9.network">Obsługa sieci</a></li>
+                       <li><a href="#10.tipsntricks">Porady i sztuczki</a></li>
+                       <li><a href="#11.terminator">Emulatory terminala</a></li>
+                       <li><a href="#12.end">Koniec</a></li>
+               </ol>
+               
+               <p>
+      Źródła:
+    </p>
+               <ol>
+                       <li><strong>Bash Bushido - Aleksander Baranowski</strong> - <a href="https://alexbaranowski.github.io/bash-bushido-book/">https://alexbaranowski.github.io/bash-bushido-book/</a></li>
+               </ol>
+<p class="footer">
+~xf0r3m<br />
+2021; COPYLEFT; ALL RIGHTS REVERSED
+</p>
+    </div>
+    <div id="content">
+    <div id="contentHeader">
+<pre id="divisionBaner">
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p id="contentHeaderLink" class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+    </div>
+    <p>
+                       Artykuł ten przedstawia bardziej z optymalizowane wykorzystnie powłoki, a konkretnie BASH. Dzięki czemu możemy wykonać wiele czynności, które do tej pory wykonywaliśmy mozolnie klepiąc polecenia znacznie szybciej co pozwoli zaoszczędzić czas, który możemy przeznaczyć na cokolwiek innego niż zarządzanie maszynami z UNIX-em.
+               </p>
+               <h2 id="1.keyboardshortcuts">1. Skróty klawiszowe</h2>
+               <p>
+                       Kiedy zastanawiamy się nad skrótami klawiszowymi powłoki, to na myśl przychodzi nam jedno pytanie. Czy skróty nie są realizowane przez konkretny emulator terminala, z którego obecnie korzystamy? Otóż część skrótów, które zostaną tutaj przedstawione mogą zostać przechwycone przez środowisko graficzne a następnie/lub przez emulator terminala. W tym wypadku należy upewnić się, że te skróty w ww. programach są nam potrzebne i w przeciwnym razie je wyłączyć. Natomiast za obsługę skrótów, które działają nawet w konsoli serwera bez środowiska graficznego odpowiedzialna jest biblioteka <em>GNU Readline</em>.
+               </p>
+               <p>
+                       Kiedy mamy jakieś dziwne klawiatury lub często korzystamy z różnych komputerów lub konsol a mimo to chcemy zachować podobną prędkość obsługi powłoki poniżej znajdują się skróty klawiszowe, dzięki którym nie będziemy już potrzebować strzałek, entera, backspace-u oraz klawiszy home end i innych. Jedyne potrzebne nam klawisze to ctrl, poźniej ewentualnie alt.
+               </p>
+               <ul>
+                       <li><strong>ctrl + p</strong> - zamiennik strzałki w górę,</li>
+                       <li><strong>ctrl + n</strong> - zamiennik strzałki w dół,</li>
+                       <li><strong>ctrl + f</strong> - zamiennik strzałki w prawo,</li>
+                       <li><strong>ctrl + b</strong> - zamiennik strzałki w lewo,</li>
+                       <li><strong>ctrl + a</strong> - zamiennik klawisza home,</li>
+                       <li><strong>ctrl + e</strong> - zamiennik klawisza end,</li>
+                       <li><strong>ctrl + d</strong> - zamiennik klawisza delete,</li>
+                       <li><strong>ctrl + h</strong> - zamiennik klawisza backspace,</li>
+                       <li><strong>ctrl + j</strong>,
+                               <strong>ctrl + m</strong> - zamiennik klawisza enter.</li>
+               </ul>
+               <p>
+                       Za pomocą innych skrótów klawiszowych możemy przesuwać kursor wyraz po wyrazie, usuwać całe słowa a nawet część linii polecenia.
+               </p>
+               <ul>
+                       <li><strong>alt + f</strong> - przesunięcie kursora o jedno słowo w przód,</li>
+                       <li><strong>alt + b</strong> - przesunięcie kursora o jedno słowo w tył,</li>
+                       <li><strong>alt + d</strong> - usunięcie znaków od pozycji kursora do końca wyrazu,</li>
+                       <li><strong>ctrl + k</strong> - usunięcie tekstu od pozycji kursora do końca wiersza</li>
+                       <li><strong>ctrl + u</strong> - usunięcie tekstu od pozycji kursora do początku wiersza</li>
+               </ul>
+               <p>
+                       GNU Readline obsługuje również inne skróty, które nie tylko polegają na poruszaniu się po linii polecenia.
+               </p>
+               <ul>
+                       <li><strong>ctrl + l</strong> - czyści ekran, działanie podobne do polecenia <code class="code-inline">clear</code>,</li>
+                       <li><strong>ctrl + r</strong> - wsteczne przeszukiwanie historii (klasyczne),</li>
+                       <li><strong>ctrl + x, ctrl + v</strong> - wyświetlenie wersji powłoki, musimy nacisnąć dwa skróty po kolei,</li>
+                       <li><strong>ctrl + 7 / ctrl + _</strong> - wycofanie wpisywanego polecenia</li>
+                       <li><strong>ctrl + x, ctrl + e</strong> - wywołanie programu wskazanego w zmiennej środowiskowej <em>EDITOR</em>,</li>
+                       <li><strong>ctrl + alt + e</strong> - rozwiązanie podstawienia powłoki wykonanie oraz wstawienie wartość zwracanej przez podstawienia powłoki czyli polecnia umieszczone pomięzy ukośnymi apostrofami (<strong>``</strong>) lub nawiasami ze znakie dolara na początku (<strong>$()</strong>),</li>
+                       <li><strong>ctrl + x, *</strong> - rozwiązanie masek plików wewnątrz linii polecenia.</li>
+               </ul>
+               <p>
+                       Wszystkie te skróty jest dostępne po wydaniu polecenia <code class="code-inline">bind -P</code>, jak czytać opisane tam skróty, otóż:
+               </p>
+               <ul>
+                       <li><code class="code-inline">\C-</code> = klawisz CTRL</li>
+                       <li><code class="code-inline">\e</code> = klawisz ESC</li>
+               </ul>
+               <p>&nbsp;</p>
+               <h2 id="2.vim">2. Edytor Vi(m)</h2>
+               <p>
+                       Każdy edytor jest najlepszy, ale co odróżnia je od <strong>vi(m)</strong>? Nie są preinstalowane w każdym możliwym UNIX-ie o jakim pomyślimy. Wyjątkiem stanowi tu dystrybucja <em>Gentoo</em>, która na swoim ISO nie posiada <em>vi(m)</em>. Implementacje <em>vi</em> mogą się różnić od siebie, np. na GNU/Linux-ach <em>vi</em> nie obsługuje poruszania kursorem w podczas edycji, z kolei w <em>OpenBSD</em> już tak, i to jest <em>vi</em> a nie <em>vim</em>. Poniżej umieszcze kilka poleceń <em>vi(m)</em>. W tryb poleceń wchodzimy po przez naciśnięcie klawisza ESC, teraz możemy wydawać polecenia.
+               </p>
+               <ul>
+                       <li><code class="code-inline">:q</code> - wyście bez zapisu. Jeśli dokonaliśmy jakiś zmian w pliku, będziemy musieli potwierdzić wyjście wykrzyknikiem (<code class="code-inline">:q!</code>)</li>
+                       <li><code class="code-inline">:wq / :x</code> - wyjście i zapis</li>
+                       <li><code class="code-inline">:w</code> - zapis</li>
+                       <li><code class="code-inline">:o ~/ścieżka_do_pliku</code> - otworzenie pliku</li>
+               </ul>
+               <p>
+                       Te polecenia działają niezależnie czy jest <em>vi</em> czy <em>vim</em>. Poniżej rzeczy, które działają tylko w <em>vim</em>.
+               </p>
+               <ul>
+                       <li><code class="code-inline">:e ~/ścieżka_do_katalogu</code> - uruchamia <strong>netrw</strong> (wtyczka) jest czymś w rodzaju bardzo skromnego manedżera plików.</li>
+                       <li><code class="code-inline">:o [protokół]://użytkownik@host[:port]/ścieżka_do_pliku</code> - otwiera plik zdalny, podczas stosowania tego rozwiązania, należy wspomnieć, że jeśli podajemy ścieżkę bezwzględną to trzeba poprzedzić ją jeszcze jednym ukośnikiem (proto://user@host//etc/ssh/sshd_config).</li>
+               </ul>
+               <p>
+                       Uruchomienie <em>netrw</em>, można wywołać podając w linii polecenia <em>vim</em> katalog. Znacznie więcej informacji nt. <em>vim</em> oraz samouczek możemy uzyskać za pomocą polecenia <code class="code-inline">vimtutor</code>, jak i również wydając polecenie <em>vi</em> <code class="code-inline">:help</code>.
+               </p>
+               <p>&nbsp;</p>
+               <h2 id="3.config">3. Konfiguracja BASH-a</h2>
+                       <h3>Znak zachęty (prompt)</h3>
+                       <p>
+                       Znak zachęty naszej powłoki jest ustalany za pomocą wzorca zapisanego w zmiennej <strong><em>PS1</em></strong> zdefiniowanej w pliku <em>.bashrc</em> w naszym katalogu domowym, inny znak możemy zdefiniować dla nowych użytkowników edytując plik <em>/etc/skel/.bashrc</em> lub domyślny znak zachęty dla całego systemu w pliku <em>/etc/bash.bashrc</em>. Jak już wcześniej wspomniałem znak zachęty ustalamy przy pomocy wzorca. Poniżej znajduje się lista elementów z jakich możemy taki wzorzec stworzyć.
+                       </p>
+                       <ul>
+                               <li><strong>\u</strong> - nazwa użytkownika</li>
+                               <li><strong>\h</strong> - hostname</li>
+                               <li><strong>\H</strong> - FQDN</li>
+                               <li><strong>\s</strong> - nazwa powłoki</li>
+                               <li><strong>\v</strong> - wersja powłoki</li>
+                               <li><strong>\V</strong> - bardziej szczegółowa wersja powłoki</li>
+                               <li><strong>\w</strong> - scieżka do obecnego katalogu</li>
+                               <li><strong>\W</strong> - nazwa obecnego katalogu</li>
+                       </ul>
+                       <p>
+                       Podczas tworzenia wzorca możemy wybrane przez nas elementy możemy wyróżnić, za pomocą 8 kolorów. Te kolory możemy mieszać ze sobą wykorzystując jeden na pierwszym planie a drugi natomiast umieścić w tle. Poniżej znajdują się kody kolorów.
+                       </p>
+                       <ul>
+                               <li>czerwony - pierwszy plan: <strong>31</strong>,
+                                       tło: <strong>41</strong></li>
+                               <li>zielony - pierwszy plan: <strong>32</strong>,
+                                       tło: <strong>42</strong></li>
+                               <li>niebieski - pierwszy plan: <strong>34</strong>,
+                                       tło: <strong>44</strong></li>
+                               <li>żółty - pierwszy plan:<strong>33</strong>,
+                                       tło: <strong>43</strong></li>
+                               <li>cyjan - pierwszy plan: <strong>36</strong>,
+                                       tło: <strong>46</strong></li>
+                               <li>magenta - pierwszy plan: <strong>35</strong>,
+                                       tło: <strong>45</strong></li>
+                               <li>czarny - pierwszy plan: <strong>30</strong>,
+                                       tło: <strong>40</strong></li>
+                               <li>biały - pierwszy plan: <strong>37</strong>,
+                                       tło: <strong>47</strong></li>
+                       </ul>
+                       <p>
+                               Natomiast sam wzorzec znaku zachęty wygląda następująco,
+                       </p>
+<pre class="code-block">
+\[\e[&lt;kolor_pierwszego_planu&gt;;&lt;kolor_tła&gt;m\]&lt;element&gt;\[\e[m\]
+</pre>
+                       <p>
+                               Warto zaznaczyć że kolor tła jest opcjonalny.
+                       </p>
+                       <br />
+                       <h3>Polecenie zachęty</h3>
+                       <p>
+                               <strong>BASH</strong> daje nam do konfiguracji ciekawą rzecz. Możemy za pomocą jednej zmiennej zdefiniować polecenie, które będzie wykonywane zawsze przed pojawieniem się znaku zachęty. Zmienną <em>PROMPT_COMMAND</em> możemy zadeklarować w pliku <em>.bashrc</em> lub co w tym przypadku może okazać się lepszym rozwiązaniem, wyeksportować zmienną aby można było z niej korzystać w tej samej powłoce.
+                       </p>
+<pre class="code-block">
+$ export PROMPT_COMMAND='date +%F-%T | tr -d "\n"'
+</pre>
+                       <p>
+                               Użycie tego polecenia spowoduje wyświetlenie pełnej daty wraz z czasem przed każdym znakiem zachęty.
+                       </p>
+                       <br />
+                       <h3>Własne skróty klawiszowe GNU Readline</h3>
+                       <p>
+                               Pamietając ze wcześniejszych akapitów o poleceniu <strong>bind</strong>, które wraz z przełącznikiem <code class="code-inline">-P</code> wyświetli nam wszystkie dostępne już skróty, to za jego pomocą możemy utworzyć również własne mapowania kombinacji klawiszy nakonkretne polecenia. Znając wartości cytowane dla klawiszy CTRL oraz ESC/ALT, zadanie jest banalne. Wystarczy wydać konkretne polecenie. Jednak przed tym warto jednak upewnić się czy dany skrót nie jest już wykorzystywany. Jeśli rzeczywiście tak jest to dopisanie do skrótu kolejniej czynności spowoduje wywołanie tych dwóch akcji jednocześnie, co może mieć niekorzystne skutki. Aby upewnić się czy rzeczywiście dany skrót jest nie używany wydamy polecnie <code class="code-inline">bind -P</code> wraz z przekierowaniem wyjścia za pomocą potoku do polecenia <em>grep</em> wraz ze wzorcem przestawiającym dany skrót np. <em>ctrl + v</em>: <code class="code-inline">'\C-v'</code>. Dzieki temu zostaną nam wyświeltlone wszystkie akcje, które wykorzytują ten skrót.
+                       </p>
+                       <p>
+                               Same skróty tworzymy rownież za pomocą polecenia <em>bind</em>.
+                       </p>
+<pre class="code-block">
+$ bind '"\006":"mc\n"'
+</pre>
+                       <p>
+                               To polecnie spowoduje dodanie do skrótów w naszym systemie, skrótu klawiszowego <em>ctrl + f</em> wywołującego polecenie uruchamiające program <em>Midnight Commander</em>.
+                       </p>
+                       <p>
+                               Polecenie bind przyjmuje jeden argument. Jest to ciąg znaków, który jest podzielony na dwie częsci, jedną częścią jest symbol cytowania danej kombinacji klawiszy, może on być trochę dziwny, jak ten wymieniony w przykładzie <code class="code-inline">\006</code> jest niczym innym jak <em>ctrl + f</em>. Drugą częścia jest czynność jaka ma zostać wykonana po wciśnieciu danej kombinacji klawiszy. Warto zwrócić uwagę na to, że za poleceniem stoi znak przejścia do nowej linii (<strong>\n</strong>), powoduje on zatwierdzenie tego polecenia zaraz po jego podstawieniu w linii polecenia po naciśnięciu odpowiedniej sekwencji klawiszy. Wróćmy jednak do tego niezrozumiałego symbolu z pierwszej części argumentu polecenia. Taki symbol możemy uzyskać naciskąjac wybraną sekwencje klawiszy w trybie cytowania. Tryb cytowania możemy wywołać skrótem <em>ctrl + v</em>.
+                               Po wciśnięciu kombinacji <em>ctrl + v</em>, naciskamy odpowiednią sekwencje klawiszy, zatwierdzamy linię polecenia. Powłoka powinna zwrócić: <code class="code-inline">bash: $'\006': nie znaleziono polecenia</code> pomiędzy pojedyńczymi apostrofami znajduje się nasz symbol cytowania. W trybie cytowania możemy odnajdować symbole dla sekwencji z klawiszem alt/esc (użycie tych klawiszy w sekwencjach daje takie same symbole cytowania) lub ctrl. Użycie polecenia bind w danej powłoce utrzymuje skróty do momentu jej zamknięcia, aby nasze skróty zostały utrwalone musimy dodać ich definicje do pliku <em>.bashrc</em>. Definicje są identyczne jak wydawane polecenia <em>bind</em> w powłoce, po prostu wpisuje do pliku polecenie <em>bind</em> następnie definicje skrótu. Odnośnie skrótów, to jest pewna uwaga. Otóż nie wszystkie sekwencje z klawiszem ctrl chcą działać. Wiele znich jest na stałe przypisanych do funkcji systemowych, dlatego też bezpieczeniej korzystać z klawisza alt.
+                       </p>
+                       <br />
+                       <h3>Powrót do poprzedniego katalogu</h3>
+                       <p>
+                               Powrót od poprzedniego katalog jest łatwy. O ile te katalogi występują po sobie. Wówczas wykorzystujemy polecenie <code class="code-inline">cd ścieżka_do_katlogu</code> oraz <code class="code-inline">cd -</code>, gdzie minus (<strong>-</strong>) oznacza poprzedni katalog, w którym się znajdowaliśmy. W wiekszości przypadków to wystarcza. Co jeśli chcemy się przenieść do katalogu, który był przed poprzednim? Z pomocą przychodzą nam polecenia <strong>pushd</strong> oraz <strong>popd</strong>. Te polecenia powodują odłożenie lub usunięcie ścieżki z konstrukcji stosu. Dzieki czemu możemy skakać z jednego miejsca w systemie na drugie i z powrotem, jednym poleceniem. To samo można zrealizować za pomocą polecenia <code class="code-inline">cd</code> z minusem.
+                               Jednak to polecenie nie pozwala na odłożenie innych ścieżek na później, jeśli przestajemy pracować z jedną ścieżką możemy ją wyrzucić poleceniem <em>popd</em> (po wykonaniu tego polecenia zostaniemy przeniesieni na poprzednią ścieżkę na stosie), i następnie swobodnie przenościć się pomiędzy dwoma pozostałymi ścieżkami za pomocą polecenia <em>pushd</em>.
+                       </p>
+                       <p>
+                               Poleceń pushd, popd, można używać zamiennie do cd oraz <code class="code-inline">cd -</code>, z tą różnią że możemy cofnąć się znacznie dalej niż tylko na poprzednią ściężkę, ale również na poprzednią poprzedniej itd. Inny poleceniem związanym z stosem katalogów jest <em>dirs</em>, które zwraca nam katalogi, które znajdują się na stosie.
+                       </p>
+                       <br />
+                       <h3>Dodatkowe ustawienia powłoki</h3>
+                       <p>
+                               Bash posiada dość niepozorne wbudowane polecenie, którym możemy zmienić zachowanie naszej powłoki. Tym poleceniem jest <strong>shopt</strong>. Wydając to polecenie bez żadnych argumentów możemy dowiedzieć się co możemy zmienić za jego pomocą w powłoce. Jedną z ciekawszych opcji jest <em>autocd</em>, dzięki któremu możemy podawać same ścieżki w linii polecenia, w ten czas zostaniemy przeniesieni na tą ścieżke. Ustawienia opcji obywa się poprzez wydanie polecenia <em>shopt</em> wraz z przełącznikiem <code class="code-inline">-s</code> oraz nazwą opcji. Wyłącznie opcji jest analogiczne tylko zamiast <code class="code-inline">-s</code> jest <code class="code-inline">-u</code>. Aby dowiedzieć się więcej o <em>shopt</em> warto odwiedzić poświęconą mu sekcję na stronie podręcznika powłoki BASH wrozdziale "Wbudowane polecenia powłoki".
+                       </p>
+               </p>
+               <p>&nbsp;</p>
+               <h2 id="4.history">4. Historia</h2>
+               <p>
+                       <strong>Historią w powłoce BASH</strong> (ale nie i tylko), nazywamy listę poleceń, która zawiera wszyskie do tej pory wprowadzone w powłoce polecenia. Ta lista jest przechowywamna w specjalnym pliku, w katalogu głównym użytkownika. Historia może przyspieszyć nasze codzienne rutynowe zadania wykonywane w powłoce. Ponieważ zamiast klepać na nowo te same polecenia, możemy cofnąć się za pomocą <s>strzałki w górę</s> kombinacji klawiszy <em>ctrl + p</em> <s>i tak długo naciskać ten skrót aż dostaniemy nasze polecenie</s> oraz skrótu <em>ctrl + n</em> przeszukać historię choć jest znacznie bardzie efektywny sposób na wyszukiwanie poleceń mianowicie przeszukanie historii w tył, niestety wadą tego rozwiązania jest to że musimy znać fragment polecenia lub kojarzyć czego mogło dotyczyć, potrzebna jest jakaś fraza aby je wyszukać. Za wyświetlenie całej historii odpowiedzialne jest polecenie <strong>history</strong>.
+               </p>
+               <p>
+                       Wykonajmy teraz mały eksperyment, uruchom powłokę i wydajmy jakieś nieszkodliwe polecenie np. <code class="code-inline">pwd</code>, teraz uruchomimy drugie okno z połoką, kiedy naciśniemy <em>ctrl + p</em>, okazuje się że nie ma polecenie, którego użyliśmy w poprzeniej powłoce. Historia danej sesji terminala (bo tak możemy nazwać czas spędzony przed pojedyńczym procesem powłoki), trafa do czegoś w rodzaju pamięci powłoki, dopóki nie zakończymy sesji nie zostanie ona utrwalona. Co może być nieco irytujące kiedy korzystamy z wielu połączeń z tym samym serwerem. Jednak tym zajmiemy się za chwilę.
+                       Kiedy na danej powłoce historia jest włączona, a my chcemy zatrzeć ślady obecności w systemie, możemy wyczyścić pamięć tej sesji wydając polecenie history z przełącznikiem <code class="code-inline">-c</code> i jeśli będziemy dalej pracować możemy przywrócić pamięć z pliku historii a jeśli nie to możemy się po prostu wylogować, jedyne co pozostanie w historii z tej sesji to polecenie <em>exit</em>.
+               </p>
+               <p>
+                       Historia musi być gdzieś przechowywana skoro można ją bez problemu przywrócić, i owszem historia przechowywana jest w pliku, plik ten jest wskazywany przez zmienną środowiskową <strong>HISTFILE</strong>. Najczęściej wskazuje na <em>/home/&lt;username&gt;/.bash_history</em>. Przekierowanie do niego pustego polecenia echo usunie dotychczasową historię całkowicie. Plik ten jest również ograniczony liczbą wierszy jakie może przechowywać, po osiągnięciu tej wartości najstarsze wpisy są usuwane, aby zrobić miejsce najnowszym. Ilość wierszy jest przechowywana w zmiennej środowiskowej <strong>HISTSIZE</strong>. <strong>Jak permanentnie wyłączyć historię? Otóż w bardzo prosty sposób. Ustawiając HISTFILE na <em>/dev/null</em> natomiast ilość wpisów historii w pamięci sesji (zmienna HISTSIZE) na 0.</strong>
+               </p>
+               <p>
+                       Wróćmy do przypadku wielu połączeń z serwerem z jednego komputera. Polecenie <em>history</em> posiada jeszcze jeden ważny przełącznik, mianowicie <code class="code-inline">-a</code>. Wydanie polecenia <em>history</em> z tym przełącznikiem powoduje dopisanie poleceń zebranych w pamięci do pliku historii. Jednak użycie tego przełącznika aby zadziałało wymaga zmiany zachowania powłoki, musimy przełączyć za pomocą polecenia <em>shopt</em> opcję <em>histappend</em>, na oby dwu oknach.
+               </p>
+<pre class="code-block">
+$ shopt -s histappend
+</pre>
+               <p>
+                       Wykonując sekwencje poleceń w obu oknach, w postaci: dopisania zawartości pamięci do pliku; wyczyszczenia pamięci z historii oraz jej przywrócenia możemy w ten sposób zsynchronizować w historię w pamięci między różnymi sesjami terminala. Proces ten można zautomatyzować, umieszczając jego wykonanie przed pojawieniem się znaku zachęty, czyli umieszczeniu trzech poleceń oddzielonych średnikami w zmiennej <em>PROMPT_COMMAND</em>, tak jak poniżej:
+               </p>
+<pre class="code-block">
+$ export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"
+</pre>
+               <p>
+                       Odwołanie się do <em>PROMPT_COMMAND</em> spowoduje że jeśli coś do tej pory znajdowało się w <em>PROMPT_COMMAND</em> pozostanie ono na swoim miejscu. Użycie w tym wypadku polecenia <em>export</em> oznacza że zmiany w <em>PROMPT_COMMAND</em> są tylko tymczasowe. Aby zapisać to że historia się synchronizuje między sesjami, należy na stałe zmienić wartość zmiennej <em>PROMPT_COMMAND</em> w pliku <em>~/.bashrc</em> (tylda, oznacza katalog domowy).
+               </p>
+               <p>
+               Wróćmy teraz do wylistowania historii za pomocą polecenia <em>history</em>. Listing składa się z dwóch kolumn. Tak jakby z identyfikatora z wystąpienia zdarzenia (polecenia) oraz z samego polecenia. Do pełnej historii brakuje jednak informacji na temat tego kiedy dane polecenie zostało wydane, nie wiem jak to jest w innych dystrybucjach to w GNU/Linux Debian zmienna środowiskowa <strong>HISTTIMEFORMAT</strong> jest pusta. Nadając jej wartość podobną formatem do tego jak podajemy argument poleceniu <em>date</em>.
+<pre class="code-block">
+$ export HISTTIMEFORMAT="%Y-%m-%d %T"
+</pre>
+               <p>
+                       Ustawienie tej opcji może wprowadzić nas w małe zakłopotanie, kiedy po jej ustawieniu wprowadzimy kilka poleceń, wylistujemy sobie historię i wszystko wydaje się na pierwszy rzut oka w porządku, zapiszemy sobie więc to polecenie do pliku <em>~/.bashrc</em>, kiedy wylogujemy się i zalogujemy się ponownie, następnie znów wylistujemy historię czasy/daty przestaną się zgadzać, okaże się że czas poleceń wydanych przed uruchomieniem opcji formatu czasu jest zbliżony do czasu wydanie polecenia <em>history</em> w tej powłoce, a zatem jest on późniejszy od czasu poleceń wydanych w poprzedniej sesji po uruchomieniu formatu czasu. Skąd to się wzięło? Otóż jeśli w pliku historii nie znacznika czasu to powłoka ładując go pamięci jako znacznika dla tych poleceń użycje czasu własnego startu.
+               </p>
+               <p>
+                       Przyjrzymy się teraz przechowywaniu historii. W <em>BASH</em> możemy łatwo określić ilość przechowywanych przez powłokę (czy to w pamięci, czy w pliku historii) wpisów historii. Za ilość w wpisów przechowywanych w pamięci sesji odpowiada poznana już przez nas zmienna środowiskowa <em>HISTSIZE</em>. Z kolei za wielkość pliku historii odpowiada zmienna <strong>HISTFILESIZE</strong>. Za ich pomocą możemy kontrolować ilość zapisywanej przez sesje historii.
+               </p>
+               <p>
+                       To co ma trafić do historii może być kontrolowane, służy do tego zmienna środowiskowa <strong>HISTCONTROL</strong>, przeważnie posiada ona wartość <em>ignoreboth</em>. Oznacza ona że do historii <u>nie trafią</u> polecenie powielone (występujące po sobie), które znajdują się już historii oraz te polecenia rozpoczynające się od spacji. Poniżej znajduje się lista możliwych wartości:
+               </p>
+               <ul>
+                       <li><strong>Brak wartości lub wartość niepoprawna</strong> - brak ograniczeń w historii.</li>
+                       <li><strong>ignorespace</strong> - polecenie rozpoczynające się od spacji nie zostaną zapisane
+                               w historii</li>
+                       <li><strong>ignoredups</strong> - polecenie powielone (występujące po sobie) nie będą zapisywane
+                               w historii</li>
+                       <li><strong>erasedups</strong> - usuwa wszystkie wpisy pasujące do poprzedniego polecenia</li>
+                       <li><strong>ignoreboth</strong> - <strong>ignorespace</strong> + <strong>ignoreboth</strong></li>
+               </ul>
+               <p>
+                       Warto wspomnieć że wartość tej zmiennej jest listą, której elementy są rozdzielane dwukropekiem (<strong>:</strong>), więc wartości możemy łączyć ze sobą. Zatem zamiast używać "<em>ignoreboth</em>" możemy użyć "<em>ignorespace:ignoreboth</em>".
+               </p>
+               <p>
+                       Ostatnią rzeczą z historii pozostało poniekąd również zgadnienie odnośnie kontroli - co ma zostać zapisane w historii. Tą rzeczą jest zmienna <strong>HISTIGNORE</strong>. W jej wartości możem podać najczęściej używane polecenia, aby nie zaśmiecać sobie historii poleceniam typu <em>cd</em> lub <em>ls</em>. Rzeczą o której należy pamiętać jest to aby podać symbol wieloznaczności (<strong>*</strong>) zaraz po poleceniu, spowoduje to przypasowanie poleceń, które zawierają jakiekolwiek argumenty a nie tylko samych poleceń, u niektórych użytkowników <em>HISTIGNORE</em> może wyglądać tak:
+               </p>
+<pre class="code-block">
+$ export HISTIGNORE="cd*:history:htop:ls*:ll*:la:l:popd:pushd*:top"
+</pre>
+               <p>&nbsp;</p>
+               <h2 id="5.indicators">5. Desygnatory słów i zdarzeń oraz modyfikatory</h2>
+               <p>
+                       Pierwszym opisanym tutaj zagadnieniem będzie <strong>desygnator zdarzenia</strong>, który składa się wykrzyknika (<strong>!</strong>) oraz numeru linii z historii. Można stwierdzić że jest to jeden ze sposobów na wywołanie polecenia z historii, należy jednak znać numery linii interesujących nas poleceń, można sobie wylistować historię a następnie odfiltrować część informacji zwrotnych za pomocą polecenia <em>grep</em>. Z desygnatorem zdarzeń wiąże się również pewna sztuczka, otóż <strong>desygnator ostatniego zdarzenia</strong> wygląda następująco: <code class="code-inline">!!</code> - dwa wykrzykniki. Czasmi musimy wykonać w powłoce pewne zadania administracyjne. Wymagają one zazwyczaj podniesienia uprawnień. Jak wiemy uprawnienia jednorazowo podnosimy za pomoca polecenia <em>sudo</em>. Często jest jednak tak że wydajemy polecenia administracyjne bez <em>sudo</em> wtedy otrzymujemy komunikaty od systemu o braku dostępu.
+                       Możemy oczywiście wybrać ponownie to polecenie z historii następnie za pomocą skrótu przenieść się na początek linii, następnie dopisać <em>sudo</em> i zatwierdzić je jeszcze raz. Jest jednak prostszy sposób:<br />
+               </p>
+<pre class="code-block">
+$ sudo !!
+</pre>
+               <p>
+                       Powyższy zapis jest równoznaczny z wyżej wymienioną czynnościa, prawda że łatwiejszy? Chociaż bez wprawy w powyższej sztucze nasz mózg będzie i tak podpowiadał nam aby dopisać to <em>sudo</em> na początku linii. Wracając jeszcze do desygnatora zdarzenia to jego wartością nie jest tylko numer linii w historii może on przyjąć w sumie 4 wartości:
+               </p>
+               <ul>
+                       <li><strong>!1(liczba dodatnia)</strong> - numer linii w historii liczony od jej początku.</li>
+                       <li><strong>!-1(liczba ujemna)</strong> -  numer linii w historii liczony od jej końca.</li>
+                       <li><strong>!ciąg_znaków</strong> - ciąg znaków rozpoczynający polecenie.</li>
+                       <li><strong>!?ciąg_znaków?</strong> - ciąg znaków zawarty w poleceniu.</li>
+               </ul>
+               <p>
+                       Patrząc na polecenie zapisane w linii poleceń, widzimy nazwę programu oraz przekazywane mu argumenty jednak z poziomu przetwarzania tekstów jest to lista słów <u>rozpoczynająca się od 0</u>, które możemy dowolnie wybierać z konkretnych wpisów z historii i co lepsze umieszczać tak zwane <strong>desygnatory słów</strong> jako elementy składowe nowej linii polecenia. Na desygnator słowa składa się desygnator zdarzenia oraz odzielony dwukropkiem (<strong>:</strong>) selektor konkretnego słowa, selektorów <em>BASH</em> oferuje wiele.
+               </p>
+               <ul>
+                       <li><strong>0</strong> - zerowe słowo przeważnie wywoływany program (polecenie)</li>
+                       <li><strong>n</strong> - n-te słowo</li>
+                       <li><strong>^</strong> - pierwszy argument polecenia</li>
+                       <li><strong>$</strong> - ostatni argument polecenia</li>
+                       <li><strong>x-y</strong> - zakres słów, <strong>x</strong> można pominąć (<strong>-y</strong>) w ten czas
+                               jest interpretowane jako <strong>\0-y</strong>.</li>
+                       <li><strong>*</strong> - wszystkie słowa poza zerowym, jest zamiennikiem <strong>1-$</strong>,
+                               jeśli zdarzenie zawiera tylko nazwę polecenia (programu) zostanie
+                               zwrócony pusty ciąg znaków</li>
+                       <li><strong>x*</strong> - od konkretnego słowa do końca linii.</li>
+                       <li><strong>x-</strong> - od konkretnego słowa do przedostatniego włącznie</li>
+               </ul>
+               <p>
+                       Wśród desygnatorów słów panuje taka zasada że jeśli przy desygnatorze zdarzenia nie zostanie podany numer linii w historii, to zostanie użyty ostatnio dodany wpis do historii.
+               </p>
+               <p>
+                       Oprócz desygnatorów słów lub wraz z, do jeszcze lepszego dostosowania linii pobranej z historii dzięki desygnatorowi zdarzenia, możemy użyć <strong>modyfikatorów</strong>. Są to dodatkowe czynności wykonywane przez powłokę aby jeszcze bardzie móc wykorzystać już raz wpisane polecenia. Modyfikatorów używa się tak samo jak desygnatorów słów, po dwukropku, po albo samym desygnatora zdarzenia albo desygnatora słowa albo po innym modyfikatorze. Poniżej znajduje się model składni podczas używania desygnatorów zdarzenia:
+               </p>
+<pre class="code-block">
+![numer,ciąg_znaków,!]:[desygnator_słów]:[modyfikator1]:[modyfikator2]...
+</pre>
+               <p>
+               Lista dostępnych modyfikatorów:
+               </p>
+               <ul>
+                       <li><strong>h</strong> - ze ścieżki do pliku usuwa nazwę pliku pozostawiając tylko samą ścieżkę dostępu,</li>
+                       <li><strong>t</strong> - ze ścieżki do pliku usuwa ścieżkę dostępu pozostawiając samą nazwę pliku,</li>
+                       <li><strong>r</strong> - z nazwy pliku usuwa rozszerzenie pozostawiając tylko nazwę właściwą,</li>
+                       <li><strong>e</strong> - usuwa z nazwy pliku nazwę właściwą pozostawiając tylko rozszerzenie,</li>
+                       <li><strong>p</strong> - wyświetla gotowe polecenie, ale go nie wykonuje,</li>
+                       <li><strong>q</strong> - umieszcza gotowe słowa w pojedyńczych cudzysłowach,</li>
+                       <li><strong>x</strong> - umieszcza gotowe słowa w pojedyńczych cudzysłowach, rozdzielając je na kolejne słowa przy spacjach oraz znakach nowego wiersza,</li>
+                       <li><strong>s/old/new</strong> - zamiana <em>old</em> na <em>new</em>,</li>
+                       <li><strong>&</strong> - powtarza zmianę dokonaną przez <strong>s/old/new</strong>, ile <strong>&</strong>tyle razy zostanie powtórzona zmiana,</li>
+                       <li><strong>g</strong> - (stosowane wraz z <em>s/old/new</em>) stosuje zamianę <em>s/old/new</em>
+                               każdego wystąpienie wartości <em>old</em> na wartość <em>new</em>. Zastosowanie: <code class="code-inline">:gs/old/new</code>,</li>
+                       <li><strong>G</strong> - (stosowanie wraz z <strong>s/old/new/</strong>) stosuje zamianę <strong>s/old/new</strong> każdego wystąpienia wartości <em>old</em> na <em>new</em> przynajmniej raz w każdym słowie.</li>
+               </ul>
+               <p>
+                       <strong>
+                               Odnośnie opcji <em>G</em>, to jeśli zostanie ona skierowana wraz z <em>s/old/new</em>, do pracy na jednym słowie, to wyniki może być nie co dziwny. Ponieważ jeśli zostanie odnalezionych więcej niż jeden elementów <em>old</em>, w słowie to tylko dwa zostaną zmienione. Wynika z tego że jeden z samego modyfikatora <em>s</em> a drugi z <em>G</em>.
+                       </strong>
+               </p>
+               <p>
+                       Jeśli musimy na szybko zmienić coś w poprzednim poleceniu, to <em>BASH</em> wprowadza skrót: <strong>^old^new^</strong>, działa jak modyfikator <em>s</em> wraz z desygnatorem zdarzenia, ale bez zbędnego desygnatora zdarzenia oraz konstrukcji modyfikatora. Wystarczy wpisać w linii polecenia np. <code class="code-inline">^sduo^sudo^</code>. Warto zaznaczyć, że wraz tą konstrukcją możemy używać innych modyfikatorów takich jak np. <em>:&</em>, aby powtórzyć zamianę wartości.
+               </p>
+               <p>
+                       Wróćmy do historii, to zagadnienie nie było by dokońca zrozumiałe bez wcześniejszego opisu desygnatorów oraz modyfikatorów. W <em>BASH</em> istnieje zmienna <em>histchars</em> (<u>nie jest ona zmienną środowiskową</u>, jest po prostu zmienną powłoki, zapisaną małymi literami bez potrzeby poprzedzania jej definicji poleceniem <em>export</em>), w której to możemy zdefiniować znaki używane w historii. <em>Histchars</em> składa się z trzech znaków i każdy z nich coś oznacza.
+               </p>
+               <ul>
+                       <li>znak desygnatora zdarzenia - <strong>!</strong>(wykrzyknik)</li>
+                       <li>znak szybkiej zmiany - <strong>^</strong>(kareta/daszek)</li>
+                       <li>znak komentarza - <strong>#</strong>(kratka/krzyżyk)</li>
+               </ul>
+               <p>
+                       Te symbole możemy zmieniać właśnie dzięki <em>histchars</em>. Podając je razem jako wartość zmiennej <em>histchars</em>, np.
+               </p>
+<pre class="code-block">
+$ histchars="+=@"
+$ echo test
+test
+$ ++
+echo test
+test
+$ =t=1
+echo 1est
+1est
+</pre>
+               <p>
+                       Przy stosowaniu tej zmiennej warto pamiętać o innych znaczeniach użwanych przez nas znaków w powłoce.
+               </p>
+               <p>
+                       Podstawienie historii (inaczej desygnator zdarzeń) możemy wyłączyć na dwa sposoby. Pierwszy sposób to nadanie pustej wartości zmiennej <em>histchars</em>:
+               </p>
+<pre class="code-block">
+$ histchars=
+</pre>
+               <p>
+               lub zmienić zachowanie powłoki za pomocą polecenia <em>set</em>:
+               </p>
+<pre class="code-block">
+/* Wyłączając */
+$ set +o histexpand
+/* Włączając z powrotem */
+$ set -o histexpand
+</pre>
+               <p>
+               Jednak w wiekszości przypadków, nie potrzeba tego robić ponieważ <em>!</em> (wykrzyknik) nie jest rozpoznawany w ciągach jako desygnator zdarzeń (przynajmniej w GNU/Linux Debian).
+               </p>
+               <p>
+               Biorąc pod uwagę to ile jest tu materiału, wypisze poniżej to co jest najczęściej stosowane i czego
+               warto sie nauczyć:
+               </p>
+               <ul>
+                       <li>sztuczka z sudo: <em>sudo !!</em>,</li>
+                       <li>szybkie podstawienia: <em>^old^new^</em></li>
+                       <li>desygnatory zdarzeń: <em>![liczba]</em>, <em>!-[liczba]</em>, <em>!ciąg_znaków</em>, <em>!?ciag_znakow?</em></li>
+               </ul>
+               <p>&nbsp;</p>
+               <h2 id="6.aliases">6. Aliasy</h2>
+               <p>
+                       Aliasy inaczej nazwy zamienne stosowane najczęściej gdy chcemy zawrzeć długie polecenie w krótkiej przyjaznej nazwie. Aliasy są umieszczane w plikach konfiguracyjnych powłoki aby miały jakiś sens. Tworzenie aliasów w sesji powłoki raczej nie ma sensu. Czemu miało by go mieć. Skoro i tak musimy zapisać nasze bardzo długie polecenie, to już można je wykonać potem ewentualnie użyć historii.
+               </p>
+               <p>
+                       Nie mniej jednak, definicja aliasu w <em>BASH</em> rozpoczyna się wbudowanego polecenia <em>alias</em> gdzie następnie podaje się nazwę aliasu, znak równości (<strong>=</strong>) oraz w pojedynczych apostrofach polecenie, dla którego tworzony jest alias. Najprostszy alias jak przychodzi mi do głowy to ten poniżej:
+               </p>
+<pre class="code-block">
+$ alias diceroll='echo $(((RANDOM % 6) + 1))'
+$ diceroll
+6
+</pre>
+               <p>
+                       Obecnie używane w systemie aliasy możemy wylistować za pomocą tego samego polecenia tylko że z przełącznikiem <code class="code-inline">-p</code>.
+               </p>
+               <p>
+                       Aliasy to takie krótkie zagadnienie że zostały jeszcze tylko dwie rzecz do omówienia. Jak sprawdzić czy dane polecenie jest aliasem? Do sprawdzenia tego typu rzeczy służy polecenie <em>type</em>.
+               </p>
+<pre class="code-block">
+$ type diceroll
+diceroll jest aliasem do echo $(((RANDOM % 6) + 1))'
+$ type pushd
+pushd jest wewnętrznym poleceniem powłoki
+</pre>
+               <p>
+                       Warto używać tego polecenia aby sprawdzić czy dana nazwa jest wolna, bo co jeśli stworzymy alias pod nazwą programu, który już istnieje? W sumie nic takiego. Binaria albo skrypt pozostaną nietknięte. Jedynie nie będzie dostępu z poziomu powłoki w tej konfiguracja, a że konfiguracja często jest określana przez użytkowników w ich katalogach domowych, to użytkownik, który posiada taki alias nie będzie miał dostępu do tego programu. Twórcy powłoki przewidzieli taką sytuacje implementując aliasy, więc dali możliwość dostępu do programu przesłoniętego przez alias. Przed nazwą takiego programu daje się backslash czy tam wsteczy ukośnik (<strong>\</strong>), gdy powłoka natrafi na takie polecenie zacznie przeszukiwać <em>PATH</em> w poszukiwaniu programu lub skryptu o takiej nazwie a nie podstawiać polecenie z aliasu.
+               </p>
+               <p>&nbsp;</p>
+               <h2 id="7.top">7. Menedżer zadań w UNIX-ach</h2>
+               <p>
+                       W tych systemach, w których możemy używać powłoki takiej jaką jest <em>BASH</em> na pewno mamy do dyspozycji programy dzięki, którym możemy śledź procesy jakie są wykonywane w naszym systemie. Możemy robić w trybie nieinteraktywnym używając polecenia <strong>ps</strong> z odpowiednimi przełącznikami oraz odfiltrowując jego dane wyjściowe za pomocą potoków i takich poleceń jak <em>sort</em> oraz <em>uniq</em>. Jednak co przyjęło się wśród użytkowników używanie znacznie lepszych programów, które są nieco bardzie rozmowne z nimi niż polecenie <em>ps</em> mowa tu poleceniach <strong>top</strong> oraz <strong>htop</strong>. <em>Top</em> jest to program, który chyba został wpisany w kanon podstawowych narzędzi dostarczanych wraz systemami UNIX-opodbnymi i to na nim skupimy się na początku, póżniej poznamy bardzie kolorowy <em>htop</em>.
+               </p>
+               <p>
+                       Po uruchomieniu programu każdy widzi co dostaje. Najprościej rzecz ujmując statystki zużycia zasobów komputera z listą procesów, które te zasoby używają aby realizować swoje zadania. Wartą wyjaśnienia informacją, która jest nie tylko wyświetlana przez <em>top</em> czy <em>htop</em> ale również przez polecenie <em>uptime</em> jest <strong>load average</strong>. Interpretuje się w bardzo prosty sposób, na początku ustalamy ile nasz komputer (CPU) ma wątków. To <em>load average</em> nie powinien przekroczyć tej wartości w pierwszym z tych pomiarów. Pomiary są ustalane w odstępach czasu 1 minuty, 5 minut oraz 15. Na podstawie wartości jaką jest <em>load average</em> możemy oszacować w jakim stopniu nasz komputer jest zajęty przez procesy. Ta wartość to najmnieszy monitor zasobów jaki możemy spotkać w UNIX-ach. Co może oznaczać wysokie <em>load average</em>? W zależności od tego do czego używamy danego UNIX-a, to jeśli na naszym PC uruchomiliśmy np konwersję plików multimedialnych to wartości mogą skoczyć.
+                       Jak również podczas kompilacji. Ta wartość ma nam przekazać informacje, czy możemy swobodnie pracować po mimo uruchomienia jakiś programów, czy też wstrzymać się do zakończenia zasobożernego zadania. Mimo iż <em>load average</em> wskazuje nam wartości równoważne z ilością naszych wątków, to system i tak wydaje się całkiem responsywny. Wtedy system jest w pełni załadowany (obciążony), ale nie przeciążony dlatego też pełne załadowanie systemu jest mniej odczuwalne niż jego przeładowanie gdzie te wartości mają naprawdę ogromne wartości. Nie ma górnego limitu dla <em>load average</em>, więc liczby mogą być na prawdę duże.
+               </p>
+               <p>
+                       Po uruchomieniu programu na pierwszej linii, <strong>znajduje się wynik polecenia <em>uptime</em></strong>, wraz z opisaną wcześniej wartością <em>load average</em>. Poniżej znajdują się <strong>sumaryczna ilość uruchomionych procesów</strong>, z podziałem na poszczególne grupy w zależności od stanu w jakim się one znajdują, jednak nie wszystkie grupy są wyświetlane. Nie ma procesów, które znajdują się w stanie bezczynności. Następną linią jest <strong>wskaźnik z użycia procesora przez procesy</strong>. Zużycie procesora jest podzielone na kilka grup, w zależności od tego czego dotyczą procesy. Opisy grup znajdują się na liście poniżej:
+               </p>
+               <ul>
+                       <li><strong>us</strong>(er) - bez priorytetowe procesy użytkownika</li>
+                       <li><strong>sy</strong>(stem) - procesy jądra systemu</li>
+                       <li><strong>ni</strong>(ce) - procesy priorytetowe</li>
+                       <li><strong>id</strong>(le) - stan bezczynności</li>
+                       <li><strong>wa</strong>(it for IO) - oczekiwanie na operacje wejscia/wyjście</li>
+                       <li><strong>hi</strong>[przerwanie sprzętowe] - obsługa przerwań sprzętowych</li>
+                       <li><strong>si</strong>[przerwanie programowe] - obsługa przerwań programowych</li>
+                       <li><strong>st</strong>(olen) - pobranie zasobu przez nadzorce (w przypadku maszyn
+                               wirtualnych)</li>
+               </ul>
+               <p>
+               <strong>Następne dwie linie</strong> to pamięć operacyjna, z podziałem na pamięć RAM oraz przestrzeń wymiany. <strong>Nas w sumie będzie ciekawić głównie</strong> ile wolnej pamięci nam jeszcze zostało, zatem powinna nas interesować ostatnia wartość w drugiej linii (uwaga, w tej wartośći nie jest zawarta pamięć SWAP) opisana jako <strong>avail Mem</strong>. Pozostałe pola raczej nie wymagają opisów.
+               </p>
+               <p>
+                       Do omówienia pozostała część główna programu, czyli tabelka z procesami, jej omówienie składa się
+                       głównie z opisu kolumn.
+               </p>
+               <ul>
+                       <li><strong>PID</strong> - Identyfikator procesu.</li>
+                       <li><strong>User</strong> - Właściciel procesu.</li>
+                       <li><strong>PR</strong> - Priorytet. Są dwa typy priorytetów: normalny (wyrażony liczbą) lub <strong>rt</strong> (real-time), jeśli natrafimy na proces z <em>rt</em>, oznacza to że pracuje on w czasie rzeczywistym.</li>
+                       <li><strong>NI</strong> - Wartość <em>NICE</em>, stopień priorytetu. Priorytet wynika z równania 20 + <em>NICE</em>. Wartości jak może przyjąć <em>NICE</em> są pomiędzy -20 (najwyższy priorytet) a 19 (najniższy).</li>
+                       <li><strong>VIRT</strong> - Wielkość obrazu wirtualnego. Ilość pamięci zaalokowanej przez proces wraz z bibliotekami współdzielonymi oraz pamięcią wspódzieloną przez inne procesy. Ta wartość nie jest zbyt miarodajna.</li>
+                       <li><strong>RES</strong> - Fizyczna pamięć (bez pliku wymiany) zaalokowana przez proces.</li>
+                       <li><strong>SHR</strong> - Pamięć współdzielona wraz z innymi procesami.</li>
+                       <li><strong>S</strong> - Status (<strong>R</strong>unning, <strong>S</strong>leeping, <strong>Z</strong>ombie, itd.).</li>
+                       <li><strong>%CPU</strong> - Zużycie procentowe procesora, jeśli mamy wielowątkowy lub wielordzeniowy procesor, to proces, który będzie zużywać cały procesor to wartość przedstawiona w tej kolumnie bedzie wynikiem iloczynu liczby watków/rdzeni * 100%. Proces zajmuje pełne 4 rdzenie = 400% itp.</li>
+                       <li><strong>%MEM</strong> - Zużycie procentowe pamięci przez proces.</li>
+                       <li><strong>%TIME+</strong> - Czas zużywania procesora od uruchomienia procesu. Plus oznacza że wyrażony czas jest przedstawiony w setkach sekund.</li>
+                       <li><strong>COMMAND</strong> - Polecenie.</li>
+               </ul>
+               <p>
+                       Top jest dość elastycznym programem, niektóre rzeczy możemy dostosować pod własne "widzi mi się". Jednak zanim przystąpimy do konfiguracji <strong>utworzymy, dowiązanie symboliczne do głównego programu tak jakoby byśmy działali na kopii</strong>.
+               </p>
+<pre class="code-block">
+$ sudo ln -s /usr/bin/top /usr/bin/my_top
+</pre>
+               <p>
+                       A więc sprawa z konfiguracją <em>top</em>. Jest na tyle nie skomplikowana, że żeby ją dokładnie wyjaśnić trzeba by przepisać stronę z podręcznika. Czego robił nie będę, jeśli wybraliśmy język polski podczas instalacji powinniśmy mieć strony podręcznika w naszym rodzimym języku. Jeśli nie to niestety musimy sobie jakoś radzić. Może zamiast przepisywania podręcznika, kilka uwaga. Na początku uruchomimy program <em>top</em> z naszego dowiązania symbolicznego w moim przypadku będzie to <em>my_top</em>.
+               </p>
+               <ul>
+                       <li><strong>Do zmiany kolejności pol, w tabelce lepiej użyć opcji <em>f</em> niż <em>o</em></strong>. W ten czas za pomocą spacji lub litery 'd' wyłączamy/włączamy pole. Strzałką w prawo zaznaczamy kolumnę, strzałka w góre/dół zmieniamy jej położenie, strzałka w lewo odznaczamy kolumnę.</li>
+                       <li><strong>Zmiana wyświetlania CPU w nagłówku (za pomocą klawisza t) na krótszą da lepszy obraz</strong>, ta liczba przy pasku do całkowity procent zużycia.</li>
+                       <li>Warto <strong>zmienić jednostkę miary pamięci (za pomocą E [shift + e]), dla lepszego obrazu</strong> do GiB.</li>
+                       <li><strong>Konfiguracje zapisujemy za pomocą W (shift + w).</strong></li>
+               </ul>
+               <p>
+                       <strong>
+                               Kiedy konfiguracja zostanie zapisana, wyłączymy <em>my_top</em>, następnie uruchomimy oryginalne polecenie <em>top</em>, okaże się że nie ma żadnych ustawień. Dzieje się tak, ponieważ konfiguracja utworzona jest przypisana tylko do tej kopii utworzonej przez dowiązanie symboliczne, którą wrazie czego zawsze można usunąć.
+                       </strong>
+               </p>
+               <p>
+                       Żeby używać <em>top</em>-a, w praktyce <strong>musimy pamiętać o dwóch klawiszach. Pierwszy z nich to <em>h</em> powodujący wyświetlenie pomocy, drugim z nich jest <em>q</em>, które naciśnięcie spowoduje zamknięcie programu.</strong> Jeśli coś w wyświetlanej pomocy nie jest jasne, zawsze pozostaje strona podręcznika <em>man 1 top</em>, ale jeśli ktoś jakimś cudem trafia właśnie na ten artykuł, w celu uzyskania pomocy odnośnie programu <em>top</em>, to poniżej kilka klawiszy, których trzeba się nauczyć, chcąc korzystać biegle z <em>top</em>-a.
+               </p>
+               </p>
+                       <u>Sortowanie i filtry</u>:
+               </p>
+               <ul>
+                       <li><strong>P</strong> - posortowanie procesów wg. użycia procesora.</li>
+                       <li><strong>M</strong> - posortowanie procesów wg. użycia pamięci.</li>
+                       <li><strong>n</strong> - sortowanie wg. PID.</li>
+                       <li><strong>&lt;,&gt;</strong> - zmiana pola sortowania.</li>
+                       <li><strong>u</strong> - filtruj w nazwy użytkownika.</li>
+                       <li><strong>R</strong> - odwrócenie sortowania.</li>
+               </ul>
+               <p>
+                       <u>Użyteczne polecenia <em>top</em></u>:<br />
+               </p>
+               <ul>
+                       <li><strong>k</strong> - wysłanie sygnały do procesu, przeważnie 15 SIGTERM lub 9 SIGKILL, choć można
+                               użyć dowolnego sygnału dostępnego na GNU/Linux.</li>
+                       <li><strong>r</strong> - zmiana priorytety dla procesu.</li>
+                       <li><strong>c</strong> - włączenie/wyłączenie ścieżek bezwzględnych przy procesach.</li>
+                       <li><strong>g</strong> - zmiana wyświetlania tabelki (przedstawiając tak jakby różne tryby pracy) z procesam do wyboru trzy predefiniowane układy kolumn, kolejno pod numerami 2,3,4. Numer 1 to tryb wyjściowy.</li>
+                       <li><strong>V</strong> - uruchomienie trybu drzewa, pokazującego hierarchie procesów.</li>
+               </ul>
+               <p>
+                       <u>Wyświetlanie agregowane*</u>:<br />
+                       * Wyświetla w jednej tabeli wszystkie tryby pracy od 1 do 4 (znane z polecenia <em>g</em>)<em>top</em>.
+               </p>
+               <ul>
+                       <li><strong>A</strong> - włączenie/wyłączenie trybu agregacji.</li>
+                       <li><strong>a</strong> lub <strong>w</strong> - przełączanie pomiędzy trybami.</li>
+               </ul>
+               <p>
+                       <u>Wyświetlanie podsumowania (dane nad tabelką)</u>:
+               </p>
+               <ul>
+                       <li><strong>1,2,3</strong> - zmiana trybu podsumowania zużycia procesora.</li>
+                       <li><strong>t</strong> - zmiana sposobu wyświetlania podsumowania zużycia procesora.</li>
+                       <li><strong>m</strong> - zmiana sposobu wyświetlania podsumowania zużycia pamięci.</li>
+                       <li><strong>l</strong> - włączenie/wyłączenie górnej linii, przedstawiającej tak
+                               naprawdę wynik działania polecenia <em>uptime</em></li>
+                       <li><strong>H</strong> - zmiana trybu wyświetlania z procesów na wątki oraz odwrotnie</li>
+               </ul>
+               <p>
+                       Obecnie w systemach GNU/Linux, istnieje wersja ulepszonego <em>top</em>-a. Pod nazwą <em>htop</em>. Różnica miedzy <strong>htop</strong> a <em>top</em> jest taka że przeważnie nie jest preinstalowany. Jest dostępny w repozytoriach lub trzeba go kompilować oraz jest prostszy w obsłudze. Z <em>Htop</em>-em możemy pracować od razu nie potrzeba go dostosowywać, ponieważ wszystko jest czytelne "out of box". Czynności mamy zmapowane pod klawiszami funkcyjnymi, gdzie na pasku na dole jest opisane, który klawisz jest do czego. Jest on na pewno bardzie interaktywny niż <em>top</em>. Jednak kiedy już ograniemy, konfiguracje <em>top</em>-a, <em>htop</em> staje się zbędny. Sam fakt że trzeba go doinstalowywać. Nie będę opisywał tu konfigurajcji programu <em>htop</em>, ponieważ wystarczy czytać ze zrozumieniem aby dostosować pod siebie ten menadżer zadań.
+                       Na koniec chciałbym dodać iż <em>htop</em> posiada wskaźnik baterii do włączenia w ustawieniach, może być to przydatne dla osób, które są zmuszone działać na bardzo uproszczonych (domyślnie) środowiskach graficznych.
+               </p>
+               <p>&nbsp;</p>
+               <br />
+               <h2 id="8.printf">8. Fancy napisy w terminalu</h2>
+               <p>
+                       Ten rodział można traktować z przymrużeniem oka. Tutaj nie zostaną przestawione żadne zaawansowane techniki wykorzystania powłoki, ale jednak <strong>jeśli ktoś szuka jakiegoś napisu na MOTD na serwer FTP czy IRC, lub nawet jako ładny nagłówek dla wyświetlenia pomocy w skrypcie/programie to tutaj znajdzie kilka rozwiązań</strong>.
+               </p>
+               <p>
+                       Pierwszym, najstarszym programem tego jest <strong>banner</strong>, który domyślnie wypisze do co podamy w argumentach za pomocą kratek (<strong>#</strong>), po jedenej linii dla każdego argumentu. Dla GNU/Linux Debian pakiet nazywa się <em>sysvbanner</em>, podaje tą informacje dlatego że prawdobnie trzeba będzie go do instalować.
+               </p>
+<pre class="code-block">
+$ banner GNU/Linux
+</pre>
+<pre>
+ #####  #     # #     #       # #
+#     # ##    # #     #      #  #           #    #    #  #    #  #    #
+#       # #   # #     #     #   #           #    ##   #  #    #   #  #
+#  #### #  #  # #     #    #    #           #    # #  #  #    #    ##
+#     # #   # # #     #   #     #           #    #  # #  #    #    ##
+#     # #    ## #     #  #      #           #    #   ##  #    #   #  #
+ #####  #     #  #####  #       #######     #    #    #   ####   #    #
+</pre>
+       <p>
+               Banner nie posiada żadnych przełączników, ani opcji do wyboru. To co widać powyżej jest jego główną i jedyną funkcjonalnością.
+       </p>
+       <p>
+               Inny programem, którego możemy użyć do tworzenia tekstowych banerów jest <strong>figlet</strong>. Ten jest już nieco bardziej dziej rozbudowany. Posiadający wiele tak zwanych czcionek, z których mozemy tworzyć napisy.
+       </p>
+<pre class="code-block">
+$ figlet GNU/Linux
+</pre>
+       <p>
+               Tak wygląda klasyczny font polecenia <em>figlet</em>.
+       </p>
+<pre>
+  ____ _   _ _   _   ___     _
+ / ___| \ | | | | | / / |   (_)_ __  _   ___  __
+| |  _|  \| | | | |/ /| |   | | '_ \| | | \ \/ /
+| |_| | |\  | |_| / / | |___| | | | | |_| |>  <
+ \____|_| \_|\___/_/  |_____|_|_| |_|\__,_/_/\_\
+</pre>
+       <p>
+               Poniżej drugi dośc popularny font <strong>slant</strong>.<br />
+       </p>
+<pre class="code-block">
+$ figlet -f slant GNU/Linux
+</pre>
+<pre>
+   _______   ____  __   ____    _
+  / ____/ | / / / / / _/_/ /   (_)___  __  ___  __
+ / / __/  |/ / / / /_/_// /   / / __ \/ / / / |/_/
+/ /_/ / /|  / /_/ //_/ / /___/ / / / / /_/ />  <
+\____/_/ |_/\____/_/  /_____/_/_/ /_/\__,_/_/|_|
+</pre>
+       <p>
+               Dla <em>figlet</em> istnieje masa różnych fontów. Jednego z nich użyłem do utworzenia baneru na górze tego dokumentu, przedstawiającego jego kategorię. Więcej czcionek znajduje się tutaj:
+       </p>
+       <p>
+               <a href="http://www.figlet.org/examples.html">http://www.figlet.org/examples.html</a>. Polecam również zapoznać się ze stroną podręcznika tego polecenie w poszukiwaniu bardzie zaawansowanych opcji tego polecenia. Za pomocą poniższego polecenia możemy sprawdzić jakie czcionki zostały z zainstalowane wraz z pakietem:
+       </p>
+<pre class="code-block">
+$ ls -al /usr/share/figlet/*.flf
+</pre>
+       <p>
+               W powszechnym użytku znajduje się znajdują się jeszcze dwa programy, które możemy wykorzystać do dowcipów w postaci "easter eggów" w skryptach, lub MOTD. Pierwszy z nich raczej może posłużyć do tego pierwszego lub otaczania istotnych informacji np. na LiveCD. <strong>Cowsay</strong>. Ten pakiet posiada dwa odrębne polecenia <strong>cowsay</strong> oraz <strong>cowthink</strong>. Przestawiające tekst z pierwszego argumentu jako wypowiedź lub myśli krowy.
+       </p>
+<pre class="code-block">
+$ cowsay "Login: user | Hasło: user1"
+</pre>
+<pre>
+____________________________
+< Login: user | Hasło: user1 >
+----------------------------
+\   ^__^
+ \  (oo)\_______
+    (__)\       )\/\
+       ||----w |
+       ||     ||
+</pre>
+       <p>
+               To polecenie możemy połączyć z jeszce jednym poleceniem <strong>fortune</strong> instalowanym z pakietu <em>fortune-mod</em>, wynik <strong>przełączenia wyjścia z polecenia <em>fortune</em> na <em>cowsay</em> lub <em>cowthink</em> może przynieść całkiem zabawne rezulataty.</strong> Np. krowa może rzucić jakimś cytatem Marka Twaina, albo dowcipem o tym ilu psyhiatrów potrzeba do zmiany żarówki. Teraz wiemy również co robi polecenie <em>fortune</em>. Wypisuje jakiś losowo wybrany tekst z swojej bazy.
+       </p>
+<pre class="code-block">
+ $ fortune | cowsay
+</pre>
+<pre>
+_______________________________________
+/ Don't hate yourself in the morning -- \
+\ sleep till noon.                      /
+---------------------------------------
+\   ^__^
+ \  (oo)\_______
+    (__)\       )\/\
+       ||----w |
+       ||     ||
+</pre>
+       <p>
+               Ostatnim programem tego typu, jeśli chodzi jakieś ładne napisy, jest myślę <strong>najlepszy pomysł na MOTD</strong>. Mianowicie chodzi o program <strong>neofetch</strong>, który oprócz wypisywania dużego loga dystrybucji w ASCII Wyświetla takie podsumowanie odnośnie maszyny jakiej używamy, przypomina ono troche informacje o systemie z macOS, którą otwiera każdy aby zobaczyć co to za mac i co ma w środku. Poniżej wynik polecenia z mojej maszyny, na której redagowałem fragment tekstu tego dokumentu.<br />
+       </p>
+<code class="code-block">
+               $ neofetch
+</code>
+<pre>
+       _,met$$$$$gg.          xf0r3m@vostro-3580
+    ,g$$$$$$$$$$$$$$$P.       ------------------
+  ,g$$P"     """Y$$.".        OS: Debian GNU/Linux 10 (buster) x86_64
+ ,$$P'              `$$$.     Host: Vostro 3580
+',$$P       ,ggs.     `$$b:   Kernel: 4.19.0-13-amd64
+`d$$'     ,$P"'   .    $$$    Uptime: 9 hours, 2 mins
+ $$P      d$'     ,    $$P    Packages: 1818 (dpkg), 3 (snap)
+ $$:      $$.   -    ,d$$'    Shell: bash 5.0.3
+ $$;      Y$b._   _,d$P'      Resolution: 1920x1080
+ Y$$.    `.`"Y$$$$P"'         DE: GNOME 3.30.2
+ `$$b      "-.__              Theme: Adwaita [GTK2/3]
+  `Y$$                        Icons: Adwaita [GTK2/3]
+   `Y$$.                      Terminal: terminator
+     `$$b.                    CPU: Intel i5-8265U (8) @ 3.900GHz
+       `Y$$b.                 GPU: Intel UHD Graphics 620
+          `"Y$b._             Memory: 2426MiB / 7835MiB
+              `"""
+
+</pre>
+       <p>
+       Jak widać, jest tu wiele informacji, których musieli byśmy szukać róznymi poleceniami.
+       </p>
+       <p>&nbsp;</p>
+       <h2 id="9.network">9. Obsługa sieci</h2>
+       <p>
+       Na pierwszy ogień weźmiemy problem, z którym chyba spotkał się każdy kto chciał za pomocą swojego ulubionego edytora, dokonywać zmian w plikach znajdujących się na serwerze. Rozwiązania tego problemu są dwa. Pierwszy z nich klasyczny: sciągamy plik z serwera, zmieniamy co trzeba, wrzucamy ponownie. Drugi to z kolei edycja zdalna, tylko aby jej użyć musimy mieć do dyspozycji <em>ssh</em>, plik możemy wyedytować za pomocą <em>vim</em>-a, ale co jeśli nie pamiętamy jego dokładnej nazwy? No właśnie, i tu przychodzi <strong>montowanie odległego systemu plików za pomocą <em>ssh</em> - <em>sshfs</em></strong>. Program możemy za instalować z repozytorium. Poźniej tworzymy na punkt montowania gdzieś w swoim katalogu domowym. Sama procedura montowania jest
+       banalna.
+       </p>
+<pre class="code-block">
+$ sshfs xf0r3m@192.168.8.4:/home/xf0r3m xf0r3m@sapphire
+</pre>
+       <p>
+       Gdzie:
+       </p>
+       <ul>
+               <li><strong>xf0r3m</strong> - nazwa użytkownika na serwerze.</li>
+               <li><strong>192.168.8.4</strong> - adres serwera.</li>
+               <li><strong>/home/xf0r3m</strong> - ścieżka do katalogu zdalnego.</li>
+               <li><strong>xf0r3m@sapphire</strong> - punkt montowania.</li>
+       </ul>
+       <p>
+               Teraz możemy wykonywać wszystkie możliwe operacje na plikach (z pewnymi ograniczeniami), tak jak byśmy wykonywali je na plikach lokalnych. Po zakończeniu prac, warto <strong>katalog odmontować, za pomoca poniższego polecenia:</strong>
+       </p>
+<pre class="code-block">
+$ fusermount -u /home/xf0r3m/xf0r3m@sapphire
+</pre>
+       <p>
+               Żeby zbytnio nie owijać w bawełne, przedstawie chyba naciekawszy problem który możemy rozwiązać kilkunastu stuknięć w klawiaturę. Powiedzmy że żyjemy w małej miejscowości (nie mowię, że na wsi), gdzie internet jest albo z osiedlówki albo z sieci komórkowej. Aby nie cieszyć się 200 Mb/s przez 20 dni, ponieważ w taki okres czasu jesteśmy w stanie wypompować 300GB pakietu danych, wybraliśmy osiedlówkę bujającą się na 10Mb/s. Po podłączeniu routera do modemu DOCSIS, okazałow się że adres na WAN-ie mamy prywatny 10.x.y.z/8. Chcemy jednak mieć dostęp do naszego serwera plików poprzez <em>ssh</em>. W pracy możemy skonfigurować sobie jedną z maszyn jako serwer stricte <strong><em>ssh</em></strong> (wystarczy zainstalować <em>openssh-server</em>) co pozwoli uruchomić nasz <strong>tunel</strong>, dzięki któremu będziemy mogli połączyć się z pracy z serwerem w domu bez otwierania portów na domowym routerze. Nie będe opisywał tutaj procedury, ponieważ już to zrobiłem przy okazji sieci
+               VPN. Zainteresowanych zapraszam do linku poniżej: <a href="articles/terminallog/laboratorium_vpn.html"> https://morketsmerke.net/articles/terminallog/laboratorium_vpn.html</a>
+       <p>
+       </p>
+               Do realizacji tego realizacji tego zadania użyjemy prawdopodobnie najpopularnieszego języka na świecie. A będzie on nam potrzebny do <strong>udostępnienia swojego katalogu domowego bez brudzenia w systemie</strong> i instalowania różnych usług w systemie, wystarczy jedno polecenie. Obecnie chyba w każdym GNU/Linux-ie preinstalowany jest <strong>Python w wersji 3</strong>.
+       </p>
+<pre class="code-block">
+$ python3 -m http.server 8080
+</pre>
+       <p>
+               Wydanie tego polecenia spowoduje uruchomienie bardzo prostego serwera, który udostępni zawartość katalog domowego o ile nie znajduje się w nim plik o nazwie <em>index.html</em>, wtedy zamiast plików zobaczymy jego zawartość. Domyślnie <strong>serwer HTTP Python-a</strong> nasłuchuje na wszystkich dostępnych interfejsach w systemie, za pomocą przełącznika <em>-b</em> możemy wymusić wykorzystanie tylko konkretnego interfejsu podając jako wartość przełącznika adres interfejsu. Np.
+       </p>
+<pre class="code-block">
+$ python3 -m http.server 8080 -b 127.0.0.1
+</pre>
+       <p>
+               Oczywiście nasłuchiwanie na pętli zwrotnej w tym przypadku akurat nie ma sensu. <strong>Podczas uruchamiania serwera najlepiej wybierać porty powyżej 1024, ponieważ do niższych portów będzie potrzebne uruchomienie polecenia z uprawnieniami administratora.</strong>
+       </p>
+       <p>
+               Kolejną ciekawą rzeczą jest skanowanie sieci, nie tylko pod kątem dostępności, ale również pod kątem zainstalowanych na danych hostach usług. <strong><u>Tutaj należy pamiętać aby wykonywać te czynności tylko na systemtach którymi administrujemy. Tak niewielka czynność jak skanowanie portów, może podnieść alarm i dzięki czemu możemy mieć poźniej problemy z prawem. Dlatego wpisując adres musimy upewnić się dwa razy, że wpisaliśmy poprawny.</u></strong>. Skanowania dokonujem za pomocą programu <strong>nmap</strong>, który dziś już ma renomę kultowego. <strong>Do wyszukiwania komputerów w sieci możemy użyć poniższego polecenia</strong>:
+       </p>
+<pre class="code-block">
+$ sudo nmap -sP 192.168.8.1/2
+</pre>
+       <p>
+               Jeśli upatrzymy sobie już jakiś serwer możemy go wyskanować pod kątem obecności usług, jakie posiada uruchomione, w zależności od używanego przez usługę rodzaju transmisji.
+       </p>
+       <p>
+               <u>Skanowanie TCP</u>:
+       </p>
+<pre class="code-block">
+$ sudo nmap -sS 192.168.8.4
+</pre>
+       <p>
+               Tutaj małe wyjaśnienie, do skanowania TCP używam <strong>skanowania SYN</strong>, żeby odkryć czy port jest otwarty nie potrzeba kończyć połączenia, wystarczy że otrzyma się wiadomość zwrotną o tym że można nawiązać połączenie. Skanowanie SYN jest znacznie szybsze od skanowania TCP, jednak może dać czasami nie miarodajne efekty, chociaż aby to nastąpiło serwer musi być nieco bardziej zabezpieczony. Wiec jeśli zależy nam jednak na wynikach skanowania, możemy użyć stricte skanowania TCP za pomocą poniższego polecenia.
+       </p>
+<pre class="code-block">
+$ sudo nmap -sT -T 4 192.168.8.4
+</pre>
+       <p>
+               Opcja <em>-T</em> - wskazuje na szablon zależności czasowych, mamy 6 stopni od 0 do 5, im niższy tym dokładniejsze skanowanie, jednak trwa ono dłużej. Więcej na ten temat w na stronie podręcznika <code class="code-inline">man nmap</code>, po uruchmieniu naciskamy ukośnik (<strong>/</strong>) po nim wpisujemy "szablonu\ zależności", następnie naciskamy enter, i powiniśmy zostać przeniesieni pod sekcje opisującą opcje <em>-T</em>.
+       </p>
+       <p>
+               <u>Skanowanie UDP</u>:
+       </p>
+<pre class="code-block">
+$ sudo nmap -sU 192.168.8.4
+</pre>
+       <p>
+               Często wykorzystywanym trybem jest <strong>tryb pełnego skanowania</strong>, który poza samym skanowaniem portów, stara się ustalić wersje wykorzystywanych usług, dodatkowe informacje już z samych usług oraz ustalić system operacyjny jaki jest używany na serwerze. Poniżej uruchomienie pełnego skanowania:
+       </p>
+<pre class="code-block">
+$ sudo nmap -A -T 4 192.168.8.4
+</pre>
+       <p>
+               <em>Nmap</em> sam w sobie jest dość niebezpiecznym programem w rękach osoby, która ma opananowane do perfekcji testy penetracyjne (oczywiście mającej złe intencje, nie można winić broni za morderstwa). Za pomocą skryptów rozszerzających ten sam program dla administratorów, który służy do lokalizowania drukarek można za pomocą kilku stuknięć w klawisze włamać się do systemu. Strasznie negatywanie nacechowany wyszedł ten paragraf, jednak myślę że zachęciłem do nauki <em>nmap</em>-a nim więcej osób niż mówił bym jaki to nie jest użyteczny, mimo tego właśnie w nim to zrobiłem. Ludzką naturę kręci wszystko co niebezpieczne.
+       </p>
+       <p>
+               Pośród ciekawych programów sieciowych mamy dyspozycji monitory ruchu sieciowego, oprócz Wiresharka, który jest niestety programem wymagającym środowiska graficznego oraz tshark, który jest nieco nieinteaktywny mamy ciekawą alternatywę: <strong>iptraf-ng</strong>, który jest troche jak wireshark tylko że interfejsem przeznaczonym na terminale. Innym programem jest minimalistyczny <strong>nload</strong>, który przy domyślnej konfiguracji zwraca tylko podsumowanie z prędkością oraz ilością przesyłanych przez nas danych. Jednak konfigracja <em>nload</em> wymaga przeczytania strony podręcznika.
+       </p>
+       <p>
+               Kiedyś aby zobczyć jakie porty są otwarte w systemie wydawało się polecenie <em>netstat</em>, obecnie czasy się zmieniły i do tego rodzaju czynności używa się polecenia <strong>ss</strong>. Jeśli wydamy poniższe polecenie zobaczymy wszystkie nawiązane połączenia w systemie.
+       </p>
+<pre class="code-block">
+$ ss
+</pre>
+       <p>
+               Większość wygląda nieco nie zrozumiale, te połączenia są to wewnętrzne połączenia procesów z użyciem gniazd, procesy mogą się tak komunikować z innymi procesami. Póki co nas to nie za bardzo interesuje. Poniżej znajduje się lista przełączników, dzięki której będziemy stanie wybrać interesujące nas połączenia.
+       </p>
+       <ul>
+               <li><strong>-t</strong> - połączenia TCP</li>
+               <li><strong>-u</strong> - połączenia UDP</li>
+               <li><strong>-l</strong> - w połączeniu w przełącznikiami TCP/UDP (<em>-lt</em>, <em>-lu</em>, <em>-ltu</em>)
+                       wyświetla listę otwartych portów w systemie.</li>
+               <li><strong>-n</strong> - wyświetla numery portów zamiast nazw usług z <em>/etc/services</em></li>
+               <li><strong>-r</strong> - rozwiązuje adresy IP na nazwy domenowe.</li>
+               <li><strong>-o</strong> - wyświetla czas trwania połączenia</li>
+       </ul>
+       <p>
+               Za pomocą prawdopodobnie dowolnego UNIX-a mamy możliwość komunikacji z dowolnym innym UNIX-em podwarunkiem że posiada on w swoim systemie program <strong>netcat</strong> (<strong>nc</strong>), za pomocą tego programu możemy np. połączyć się z dowolnym portem, lub tez otworzyć port i oczekiwać na nim na połączenie, od zwyczajnych tekstów przesyłanych z jednego systemu na drugi, które mogą wyglądać jak najzwyklejszy czat, po przez przesyłanie całych katalogów z użyciem metod kompresji, ale najpierw podstawy.
+       </p>
+       <p>
+               <u>Nawiązywanie połączenie TCP</u>:<br />
+       </p>
+<pre class="code-block">
+$ nc &lt;HOST&gt; &lt;PORT&gt;
+</pre>
+       <p>
+               <u>Nawiązywanie połączenie UDP</u>:
+       </p>
+<pre class="code-block">
+$ nc -u &lt;HOST&gt; &lt;PORT&gt;
+</pre>
+       <p>
+               <u>Zrzut danych z sesji do pliku</u>:
+       </p>
+<pre class="code-block">
+$ nc -o &lt;nazwa_pliku&gt; &lt;HOST&gt; &lt;PORT&gt;
+</pre>
+       <p>
+               Jak możemy przetestować naszego <em>nc</em>? Otoż sposób w samej funkcjonalności jest dość prosty. Połączmy się z jakimś lokalnym serwerem WWW, ale najpierw przygotujemy sobie żądanie. W pustym pliku wpiszymy te 3 linie:
+       </p>
+<pre class="code-block">
+GET / HTTP/1.0
+Host: &lt;HOST&gt;
+
+</pre>
+       <p>
+               Pusta linia jako trzeci wiersz w pliku, nie jest błędem, jest wręcz wymagana. Jeśli posiadamy polecenie <strong>unix2dos</strong>, to możemy skonwertować UNIX-owe znaki nowej linii, na te DOS-owskie, które są wymagane przez protokół HTTP. Jeśli nie mamy to musimy doinstalować (<code class="code-inline">apt install dos2unix</code>). Po instalacji konwertujemy znaki nowej linii.
+       </p>
+<pre class="code-block">
+$ unix2dos payload.txt
+</pre>
+       <p>
+               Gdzie <em>payload.txt</em>, jest moim plikiem z żądaniem, po konwersji możemy już wysłać nasze żądanie do serwera:
+       </p>
+<pre class="code-block">
+$ cat payload.txt | nc 192.168.8.4 80
+</pre>
+       <p>
+               W odpowiedzi powinniśmy dostać kod strony. Z testowaniem usług przy użyciu <em>netcat</em> po nawiązaniu połączenia musimy wydawać polecenia zgodne ze specyfikacją danych usług, które są dostępne w plikach RFC, pod poniższym adresem: <a href="https://www.rfc-editor.org/rfc-index.html">https://www.rfc-editor.org/rfc-index.html</a> Teraz przetestujemy sobie połączenia. Do tego ćwiczenia potrzebujemy dwóch UNIX-ów w sieci LAN, aby nic nie zaburzało połączenia. Na powiedzmy hoście A, który będzie naszym serwerem wydajemy proste polecenie:
+       </p>
+<pre class="code-block">
+$ nc -l -p 9090
+</pre>
+       <p>
+               Z kolei na hoście B, który będzie pełnił funkcje klienta, podłączymy się pod otwarty na serwerze port.
+       </p>
+<pre class="code-block">
+$ nc 192.168.8.4 9090
+</pre>
+       <p>
+               Teraz dosłownie możemy porozmawiać z komputerem. Możemy również przesłać plik, na komputerze B nadajemy plik na komputer A, jednak przed nadaniem pliku, musimy wiedzieć że komputer A na niego oczekuje:
+       </p>
+<pre class="code-block">
+/* KOMPUTER A */
+$ nc -l -p 9090 &gt; file.txt
+/* KOMPUTER B */
+$ cat file.txt | nc 192.168.8.4 9090
+</pre>
+       <p>
+               Polecenie po przesłaniu pliku nadal będzie oczekiwać dalsze dane, możemy zakończyć połączenie za pomocą skrótu ctrl + c. Ostatnią rzeczą do przedstawienia tutaj odnośnie netcat jest przesłanie całego katalogu za pomocą polecenia <strong>tar</strong> z algorytmem kompresji <strong>gzip</strong>, jak to wygląda po względem technicznym? Otóż tworzymy skompresowane archiwum za pomocą <em>tar</em> wraz z <em>gzip</em> na standardowym wyjściu, które następnie przekazywane jest za pomocą potoku do ustawionego połączenia sieciowego przez nasz <em>netcat</em> do odbiorcy, gdzie znów potokiem przekierowane jest do dekompresji. Jednak kolejność wydawania poleceń jest odwrotna do sposobu działania, to odbiorca w tym przypadku komputer A musi czekać na katalog.
+       </p>
+<pre class="code-block">
+/* KOMPUTER A */
+$ nc -l -p 9090 | tar -xzvf -
+/* KOMPUTER B */
+$ tar -czvf - sciezka/do/katalogu/ | nc 192.168.8.4 9090
+</pre>
+       <p>
+               Gdzie myślniki (<strong>-</strong>) oznaczają stardardowe wyjście.
+       </p>
+       <p>
+               Odnośnie sprawdzania odległych portów, to istnieje jeszcze jeden sposób, nieco przestarzały, ale nadal spełniający swoje zadanie. Mianowicie chodzi o <strong>telnet</strong>. Jest to protokół, który umożliwiał połączenie ze zdalną powłoką gdzieś na odległym serwerze. Jak każdy protokół, musi mieć programy go obsługujące, tak protokół <em>telnet</em> posiada program, o jakżeby innej nazwie jak <em>telnet</em>. Jestem ciekaw okoliczności w jakich ktoś pomylił się przy wpisywaniu portu i doszedł do wniosku że <em>telnet</em> można wykorzystać do skanowania portów na hostach w sieci, i takie zadanie przychodzi realizować temu programowi, w 95% przypadków jego użycia w obecnych czasach, innym zastosowanie jest bardziej zaawansowana konfiguracja nieco starszych urządzeń sieciowych lub też obsługa protokół TFTP. Zatem jak sprawdzić za pomocą telenetu czy port jest otwarty, najprościej wydając poniższe polecenie
+       </p>
+<pre class="code-block">
+$ telnet 192.168.8.4 22
+</pre>
+       <p>
+               Odpowiedź:
+       </p>
+<pre class="code-block">
+Trying 192.168.8.4...
+Connected to 192.168.8.4.
+Escape character is '^]'.
+SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2
+
+Protocol mismatch.
+Connection closed by foreign host.
+</pre>
+       <p>
+               Po tej odpowiedzi możemy bardzo, ale to bardzo wiele wywnioskować.
+       </p>
+       <ol>
+               <li>Port 22 jest otwarty</li>
+               <li>Host używa SSH w wersji 2.0</li>
+               <li>Do obsługi SSH używa daemon OpenSSH w wersji 7.9p1</li>
+               <li>System operacyjny jest GNU/Linux-em Debian w wersji 10
+                       lub opartym na GNU/Linux Debian 10 (buster)</li>
+       </ol>
+       <p>
+               Oczywiście nie ma się co łudzić niewiele jest tak gadatliwych protokołów, ale jeśli tylko zobaczymy linijkę <code class="code-inline">Connected to &lt;HOST&gt;</code>. To nasz cel został osiągnięty, połącznie zostało nazwiązane i możemy sobie wpisać ten port jako otwarty. Zatem aby sprawdzić telenetem port wystarczy podać adres hosta następnie port i czekać na informacje o nawiązaniu połączenia.
+       </p>
+       <p>&nbsp;</p>
+       <h2 id="10.tipsntricks">10. Porady i sztuczki</h2>
+       <p>
+               <h3>Powtarzaj do skutku</h3>
+               <p>
+                       Czasami może zdarzyć się że nie możemy wykonać pewnej czynności ponieważ serwer z którego potrzebujemy danych sam ich jeszcze nie posiada. Zatem jedyną rzeczą jaką możemy zrobić to stworzyć skrtypt, który <strong>zapętli nasz skrypt do momentu, gdy ten zróci poprawne wykonanie</strong>. Możemy wykorzystać do tego poniższy skrypt.
+               </p>
+<pre class="code-block">
+#!/bin/bash
+while [ true ]; do . $1 && break; done
+</pre>
+               <p>
+                       W dobie dzisiejszych komputerów pozostawienie skryptu na nieskończonej pętli, nie spowoduje jakiegoś nadmiernego obciążenia, jeden wątek może zostać obciążony na 100%. Co tu się tak naprawdę dzieje? Otóż skrypt uruchamia jakieś polecenie, nie wiadomo jakie, podawana przez użytkownika w parametrze pozycjnym, na podstawie wartości zwracanej przez skrypt określane jest przy użyciu <code class="code-inline">&&</code> czy pętla wykona się ponownie czy też nie. Jednak generalnie w sztuce programowania przyjeło się kontrolowanie w jakiś sposób konstrukcji tego typu. Opcje są dwie. Albo ustawimy jakiś limit jej wykonań albo też możemy użyć czasu. Rozpatrzymy pierwszy przypadek użycia limitu.
+               <p>
+<code class="code-block">
+i=1;<br />
+while [ $i -le 1000 ]; do
+       echo "$i: ";
+       . $1 && break;
+       i=$((i + 1));
+done
+</code>
+               <p>
+                       Tutaj dodałem licznik, który ma pewny limit. Warto zwrócić uwagę na to iż nie jest już to pętla nieskończona. Oczywiście można ten kod przerobić w taki sposób że warunek <em>true</em> pozostanie i wewnątrz pętli zimplementować mechanizmy jej kontroli. Jednak nie widze sensu w tym konkretnym przypadku. Identycznie jest ustawieniem pętli na czas. Zatem na początku pętli zdefiniowałem zmienną, której nadałem wartość 1, mniej więcej wyzerowałem licznik. Warunek ustawiłem, wartość licznika mniejszą lub równą 1000. Pod linią definiująca dalsze wykonianie pętli została umieszczona inkrementacja licznika i to jest wszystko. Teraz zajmiemy się limitem czasowym
+               </p>
+<pre class="code-block">
+if [ ! "$2" ]; then limit=10;
+else limit=$2; fi
+i=1;
+starttime=$(date +%s);
+while [ $(($(date +%s) - starttime)) -lt $limit ]; do
+       echo "Sekund: $(($(date +%s) - starttime))";
+       echo "Numer obrotu: $i";
+       . $1 && break;
+       i=$((i + 1));
+done
+</pre>
+       <p>
+               Tutaj to znów pętla nie jest nieskończona, został ustawiony warunek, w którym sprawdzane jest czy różnica sekund pomiedzy czasem zmierzonym w momencie sprawdzenia warunku a czasem rozpoczęcia pętli jest mniejsza od limitu, w ten czas wykonywane jest ciało pętli, licznik tutaj został umieszczony dla celów badawczych aby sprawdzić ile obrotów pętli zostanie wykonanych na danym odcinku czasu. Lepiej nie tworzyć nieskończonych pętli. Dlaczego tutaj też zmieniłem warunek, mogła pozostać pętla nieskończona i ustawić limit czasowy z timeout-em w środku. Otóż jeśli w konstrukcji kontrolnej zdarzył by się błąd, pętla leciała by ku nieskończoności.
+       </p>
+       <br />
+               <h3>Wydrukowanie konkretnych linii z pliku</h3>
+               <p>
+                       Omawiając to zagadnienie, warto wspomnieć jak możemy wyświetlić sobie plik wraz z numerami linii przy każdej z nich kiedy używamy polecenia <code class="code-inline">cat</code> wystarczy dodać przełącznik <code class="code-inline">-n</code>. Dla przykładu wylistujemy sobie fragment pliku <em>/etc/passwd</em>.
+               </p>
+<pre class="code-block">
+$ cat -n /etc/passwd | head -n 10
+1 root:x:0:0:root:/root:/bin/bash
+2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
+3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
+4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
+5 sync:x:4:65534:sync:/bin:/bin/sync
+6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
+7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
+8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
+9 mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
+10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
+</pre>
+               <p>
+                       Polecenie <code class="code-inline">head -n 10</code> odfiltrowuje z wyjścia na potoku ze wszystkich linii pozostawiają tylko 10 początkowych. Kiedy wiemy jak wypisać sobie plik wraz z numerami możemy teraz spokojnie, przejść do głównego tematu, który jest realizowany za pomocą polecenia <code class="code-inline">sed</code> z przełącznikiem <code class="code-inline">-n</code>. Po przełączniku podajemy polecenie dla <em>sed</em>. Sam <em>sed</em> jest edytorem strumienia, coś ala nieinteraktywny edytor tekstu, gdzie wiele rzeczy robi się za pomocą specjalnych poleceń i teraz tak też zrobimy.
+               </p>
+<pre class="code-block">
+$ cat -n /etc/passwd | head -n 10 | sed -n '3,8p'
+3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
+4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
+5 sync:x:4:65534:sync:/bin:/bin/sync
+6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
+7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
+8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
+</pre>
+               <p>
+                       Polecenie <em>sed</em> podajemy w pojedyńczych apostrofach, na początku zawsze podajemy numery linii, na których mamy wykonać polecenie, którym jest mała literka po zakresie linii. Zakres linii może być pojedyńczą liczbą wtedy polecenie  wykonywane jest na tej jednej konkretnej linii. Wszystkie polecenia <em>sed</em> są dostępne na stronie podręcznika polecenia, dostępnej chyba w każdym UNIX-ie.
+               </p>
+               <br />
+               <h3>Podgląd pliku na żywo.</h3>
+               <p>
+                       Podgląd pliku w momencie wypełniania go informacjami jest niezwykle przydatny. Szczególnie gdy administrujemy usługami. Sam pamiętam gdzie dla zleceniodawcy monitorowałem serwer WWW ponieważ ciągle był problem z dostępnością udostępnionych na nim zasobów, po zresetowaniu połączeń wyszystko wracało do normy. Podejrzewałem jedno, atak DoS. Własnie za pomocą podglądu na żywo <em>accesslog</em>-u daemon'a Apache2 upewniłem się że to rzeczywiście atak DoS. Zatem aby uruchomić plik w taki sposób aby przyjrzeć się jak wypełnia się on danymi wystarczy wydać poniższe polecenie
+               </p>
+<pre class="code-block">
+$ tail -f sciezka/do/pliku
+</pre>
+               <p>
+                       Plik będzie wyświetlał się i wypełniał ekran w miarę wypełniania go treścią.
+               </p>
+               <br />
+               <h3>Nieinteraktywne find and replace w strumieniu</h3>
+               <p>
+                       Za pomocą już wcześniej poznanego programu <strong>sed</strong> możemy odnajdować i zamieniać ciągi znaków w strumieniu. Składnia tego polecenia jest nieco dziwna. Jednak jej opanowanie nie powinno przysporzyć problemów. W tym poleceniu zakres linii również może zostać użyty, poźniej następuje polecnie: <code class="code-inline">s/old/new/[mods]</code>. Polecenie poszuka piewszego wystąpienia ciągu <em>old</em> i zamieni je na <em>new</em>. Modyfikatory jakie możmy użyć z tym poleceniem to:
+               <p>
+               <ul>
+                       <li><strong>g</strong> - zamienia wszystkie wystąpienia w strumieniu lub w jego fragmencie o ile został podany zakres linii</li>
+                       <li><strong>i</strong> - wyłącza natywną dla UNIX-ów wrażliwość na wielkość liter.</li>
+               </ul>
+               <p>
+                       <strong>Warto wspomnieć że <em>sed</em> jest tutaj bardzo elastyczny, gdy będziemy musieli operować np na ukośnikach (<strong>/</strong>), to ukośniki z polecenia możemy zmienić na dowolny inny znak</strong>. Na przykład na małpę (<strong>@</strong>). <em>Sed</em> przyjmuje plik/ściezkę do pliku jak kolejny argument za poleceniem, użycie pliku jednak spowoduje, że wszelkie zmiany jakie na nim dokonamy, dokonamy tak naprawdę na utworzonym z pliku strumieniu, jeśli chcemy zapisać nasze zmiany musimy użyć przełącznika <code class="code-inline">-i</code> przed poleceniem.
+               </p>
+               <h3>Skrypt kończy swoje działanie po napotkaniu pierwszwgo błędu</h3>
+               <p>
+                       Często problemem przy obszernych skryptach jest jeden błąd, może narobić niezłego bałaganu w plikach samego skryptu, jak nie gorzej w samym systemie. Jest na sposób oczywiście. Na początku skryptu należy ustawić opcje powłoki, aby kończyła działanie po pierwszym napotkanym błędzie, ustawienie to wymaga jedynie drobnego polecenia zapisanego przez pierwszymi poleceniami. Poniżej znajduje się to polecnie:
+               </p>
+<pre class="code-block">
+$ set -e
+</pre>
+               <p>
+                       Możemy je sobie przestestować wykonując je w zwykłej powłoce, a następnie wpisać byle co w powłoce np. 'asdasdsdsdfa' przy zwykłych ustawieniach dostaniem informacje że nie odnaleziono takiego polecenia, ale w tym wypadku powłoka po prostu się zamknie. Tak samo będzie ze skryptem. <em>BASH</em> posiada jeszcze jedną dość przydatną rzecz jeśli chodzi o bardziej restrykcyjne działanie skryptów. Przy uruchamianiu skryptu bez tego ustawienia, możemy definiować puste zmienne. Po włączeniu tej opcji puste zmienne będą oznaczane jako błąd, a jeszcze opcja <code class="code-inline">-e</code> spowoduje zakończenie wykonywania skryptu. Ustawienie opcji bardziej restrykcyjnego traktowania zmiennych zawsze jest ustawiene wraz z kończeniem wykonywania skryptu na pierwszym błędzie. Ustawianie bardziej restyrkcyjnego traktowania zmiennych służy przełącznik <code class="code-inline">-u</code> polecenia <em>set</em>.
+               </p>
+<pre class="code-block">
+$ set -eu
+</pre>
+               <br />
+               <h3>Debugowanie skryptów powłoki BASH</h3>
+               <p>
+                       Debugowanie skryptu powłoki, nie jest tak bardzo zawansowane ja w przypadku innych języków. Nie co liczyć na manualne uruchamianie linia po linii i tego typu rzeczy. Jedyne co dostaniemy to rozwinięte linie o ile korzystaliśmy z podstawień oraz wartości zmiennych, które muszą być wynikiem jakiś operacji. I to wystarczy. Jedyne co warto zmienić to jeśli skrypt korzysta z innego skryptu to ciężko się połapać, które linie są od czego, więc zmienimy znak zachęty odpowiedzialny oznaczenia <em>BASH</em> w trybie debugowania.
+               </p>
+<pre class="code-block">
+export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+</pre>
+               Gdzie:<br />
+               <ul>
+                       <li><code class="code-inline">BASH_SOURCE</code> - zmienna zawierająca scieżkę do pliku żródłowego skryptu</li>
+                       <li><code class="code-inline">LINENO</code> - zmienna zawierająca numer linii własnego wywołania</li>
+                       <li><code class="code-inline">${FUNCNAME[0]:+${FUNCNAME[0]}(): }</code> - instrukcja podstawienia, jeśli
+                               <code class="code-inline">FUNCNAME[0]</code> istnieje i nie jest pusty zostaje podstawione słowo
+                               po znaku <strong>+</strong> (plus) w tym przypadku <code class="code-inline">${FUNCNAME[0]}():</code>, zmienna
+                               <code class="code-inline">FUNCNAME[0]</code> przechowuje nazwę obecnie wywoływanej funkcji zdefiniowanej
+                               w skrypcie.</li>
+               </ul>
+               <p>
+               Sekcja z <code class="code-inline">FUNCNAME[0]</code> nie zostanie użyta do momentu wywołania przez skrypt funkcji.
+               </p>
+               <br />
+               <h3>Twórz lepsze skrypt powłoki</h3>
+               <p>
+                       Dawniej istniały oddzielne programy, których zadaniem była analiza kodu po względem jakości, takie programy były w stanie wystawić nawet programiście ocenę zgodną z anglosaskim system szkolnictwa, takie programy zwały się linterami. W obenych czasach lintery są zintegrowane w nowoczesne IDE, przekazując programistom różnego rodzaju wskazówki. Z racji tego że dla skryptów powłoki nie ma jakoś IDE, ponieważ są one tworzone w razie potrzeby, to ktoś w trosce o jakość tych skryptów stworzył własnie linter, skryptów powłoki <em>BASH</em>. Taki program nazywa się <strong>shellcheck</strong> i nawet posiada paczkę w repozytorium dystrybucji GNU/Linux Debian. Użycie go jest dziecinnie protste, jako pierwszy argument podajemy ścieżkę do skryptu.
+               </p>
+<pre class="code-block">
+$ shellcheck sciezka/do/skryptu
+</pre>
+               <p>
+                       Wynik działania <em>shellcheck</em> przedstawiam poniżniej:
+               </p>
+<pre class="code-block">
+In RUS.sh line 18:
+while [ $(($(date +%s) - starttime)) -lt $limit ]; do
+                                ^-- SC2086: Double quote to prevent globbing and word splitting.
+
+
+In RUS.sh line 21:
+. $1 && break;
+^-- SC1090: Can't follow non-constant source. Use a directive to specify location.
+  ^-- SC2086: Double quote to prevent globbing and word splitting.
+</pre>
+               <p>
+                       Niestety nie będzie tego widać na powyższym przykładzie, ale shellcheck swoje uwagi zwraca w kolorze. Tak więc błedy są oznaczone na kolor wiadomo - czerwony, ostrzeżenia - na zółty, a uwagi na zielony. Każda uwaga zwrócona przez <em>shellcheck</em> rozpoczyna się od pewnego rodzaju kodu identyfikującego komunikat, każdy kod na stronie wiki projektu na GitHub, posiada swoją stronę rozszerzającą informacje na jego temat z przykładami. Dlatego można zajrzeć w link poniżej <a href="https://github.com/koalaman/shellcheck/wiki">https://github.com/koalaman/shellcheck/wiki</a>, rozwijając zakładkę "Pages", znajduje się wyszukiwarka, gdzie możemy wrzucić kod interesującego nas błędu lub podać po ukośniku na końcu adresu linku.
+               </p>
+               <h3>Wykonanie polecenia o podanym czasie</h3>
+               <p>
+                       Chcemy wykonać pewne polecnie, ale nie teraz powiedzmy że za dwie minuty, to możemy to zrealizować za pomocą polecenia <strong>at</strong>. Jeśli nasze polecenie za powiedzmy 2 minuty ma zostać uruchomione to na początku wskazujemy poleceniu <em>at</em> czas, który jest wynikiem dodawania pożądanego czasu do obecnego jak w przykładzie poniżej.
+               </p>
+<pre class="code-block">
+$ at now + 2 minutes
+</pre>
+               <p>
+                       Następnie zostanie nam wyświetlony znak zachęty programu <code class="code-inline">at&gt;</code>, po którym wpisujemy polecenia jakie mają się wykonać. Warto pamiętać o przekierowaniu wyjścia do pliku, ponieważ polecenie <em>at</em>, podczas wykonywania zadań nie zwrócić żadnych danych, chyba że mamy zainstalowany program <em>mailx</em>. Więc jeśli nam na tym zależy musimy te dane przekierować. Zatwierdzenie listy poleceń i wyjście z trybu polecenia <code class="code-inline">at&gt;</code> dokonujemy za pomocą skrótu klawiszowego ctrl + d. Więcej informacji znajduje się na stronie podręcznika polecenia <em>at</em>.
+               </p>
+               <h3>AWK wyświetla linie wg. zakresu</h3>
+               <p>
+                       <strong>Awk</strong>, podbnie jak <em>sed</em> za pomocą specjalnych poleceń może wyświetlić linie z konkretnego zakresu, jednak tutaj konstrukcja polecenia jest nieco bardziej skomplikowana. Kiedy otwieramy plik lub przekazujemy strumień to w <em>awk</em> jest specjalna zmienna, która przechowuje numer linii <code class="code-inline">NR</code>, i to na niej oprzemy warunki naszego polecenia.
+               </p>
+<pre class="code-block">
+$ awk 'NR&gt;=2 && NR&lt;=8' /etc/passwd
+</pre>
+                       <br />
+               <h3>dos2unix, unix2dos</h3>
+               <p>
+                       Przypomnijmy sobie ten drobny programik, który zamieniał znak końca wiersza w pliku z żądaniem HTTP dla <em>telnet</em>. To czasami może być potrzeba aby zamienić te znaki w drugą stronę, kiedy edytowaliśmy coś na MS Windows i nagle przeniesiemy to na UNIX-a, to nagle mamy takie znaczki jak <code class="code-inline">^M</code>, to jeśli to kod źródłowy, to interpreter/kompilator może sypać błędami. Zamiast usuwać te znaki ręcznie możemy użyć właśnie programu o przeciwynym działaniu od tego którego używaliśmy przy żądaniu HTTP dla <em>telnet</em>, <strong>dos2unix</strong>
+               </p>
+<pre class="code-block">
+$ dos2unix hello.c
+</pre>
+                       <br />
+                       <h3>Tablica ASCII</h3>
+                       <p>
+                               Tablica ASCII jest dostępna w prawie każdym GNU/Linux za pomocą poniższego polecenia:
+                       </p>
+<pre class="code-block">
+$ man 7 ascii
+</pre>
+                       <br />
+                       <h3>Automatyczne wylogowanie z połoki</h3>
+                       <p>
+                               Kiedy pracujemy bez GUI, możemy ustawić sobie <strong>automatyczne wylogowanie podczas bezczynnosci na podstawie wartość zmiennej <em>TMOUT</em></strong>, której wartość przechowuje ilość czasu bez żadnego wydanego polecenia w wyrażonego w sekundach, po upływie tego czasu zostaniemy wylogowanii z połoki. Jeśli jednak w naszej powłoce działa jakiś proces to wylogowanie nie będzie możliwe, z kolei mimo procesów w tle wylogowanie nastąpi. Aby ustawić sobie autowylogowanie wystarczy zdefiniować w powłoce zmienną <em>TMOUT</em> i jeśli nie wydamy przez ten czas żadnego polecenia zostaniemy wylogowani. Zmienną również możemy dopisać do naszego pliku <em>.bashrc</em>, pamiętając poprzedzeniu deklaracji słowem <em>export</em>.
+                       </p>
+<pre class="code-block">
+$ TMOUT=30
+</pre>
+                       <br />
+                       <h3>Timeout dla procesów</h3>
+                       <p>
+                               Za pomocą spcjalnego polecenia zakończyć działanie procesów jeśli przekroczą limit czasowy. Najprostszym przykładem żeby to zaprezentować jest ustawienie limitu czasu za pomocą polecenia <strong>timeout</strong> dla polecenia <em>sleep</em>.
+                       </p>
+<pre class="code-block">
+$ timeout 5 sleep 7 || echo "It fails!"
+</pre>
+                       <p>
+                       Zwróćmy uwagę na to iż polecenie dla któremu checemy nadać czas oczekiwania podajemy jak argument polecenia <em>timeout</em> za raz po limicie czasowym.
+                       </p>
+                       <br />
+                       <h3>Jaki jest mój publiczny adres IP?</h3>
+                       <p>
+                               Na to pytanie może odpowiedzieć nam jedna strona, jednak <strong>wymagane jest posiadanie w systemie polecenia <em>curl</em></strong>. Kiedy mamy zainstalowany pakiet w systemie, wystarczy że wydamy poniższe polecenie aby dowiedzieć się jaki jest nasz publiczny adress IP.
+                       </p>
+<pre class="code-block">
+$ curl ifconfig.co
+</pre>
+                       <br />
+                       <h3>Podgląd wielu plików na żywo</h3>
+                       <p>
+                               Może zdarzyć się tak że musimy podejrzeć kilka plików na żywo na jednym oknie. Możemy wspomóc się multiplekserami terminali takimi jak <em>GNU Screen</em> czy <em>TMUX</em>. Jednak nie jest to konieczne jeśli jesteśmy w stanie zainstalować w systemie taki program jak <strong>multitail</strong>, program jako argumenty przymuje kolejne pliki do podglądu, dzieli ekran na równe części a w każdej z tych części mamy jeden z naszych plików. <em>Multitail</em> zawiera wiele przełączników i konfigurowalnych opcji, które są opisane w wyczerpujący sposób na stronie podręcznika polecenia <em>multitail</em>.
+                       </p>
+<pre class="code-block">
+$ sudo multitail /var/log/messages /var/log/auth.log
+</pre>
+
+                       <h3>Wykonywanie poleceń co jakiś czas</h3>
+                       <p>
+                               Tytuł może być mylący. Może wskazywać na harmonogram zadań, jednak w tym akapicie nie o to chodzi. Na UNIX-ach istnieje takie polecenie jak <strong>watch</strong>, które uruchamia nam polecenie co jakiś interwał czasu, domyślnie są to 2 sekundy, ale oczywiście za pomocą przełącznika <code class="code-inline">-n</code> możemy ustawić dowolny interwał.
+                       </p>
+<pre class="code-block">
+$ watch uptime
+</pre>
+                       <p>
+                               Warto wspomnieć o dwóch rzeczach. <em>Watch</em> najmniejszy interwał jaki może przyjąć to 0.1 sekundy. Drugą rzeczą jest największy możliwy interwał, który wynosi wielkość 32-bitowej zmiennej integer bez znaku czyli 2^32. <em>Watch</em> może być naprawdę użytecznym programem, o wiele więcej informacji znajduje się na stronie podręcznika polecenia <em>watch</em>.
+                       </p>
+                       <br />
+                       <h3>Konwersja z użyciem ImageMagick</h3>
+                       <p>
+                               ImageMagick jest programem graficznym, którego obsługa nie należy do najbardziej przyjaznych użytkownikowi. Ma on jednak jedną bardzo ważną rzecz. Można niektóre czynności wykonać z poziomu terminala, a wraz z pakietem <em>ImageMagick</em> dostajemy polecenie <strong>convert</strong>, za pomocą którego możemy w prosty sposób konwertować obrazki. Skonwertujemy sobie na początek PNG na JPEG.<br />
+                       </p>
+<pre class="code-block">
+$ convert obrazek.png obrazek.jpg
+</pre>
+                       <p>
+                               Niezbyt skomplikowane? Innymi czynnościami jakie możemy wykonać za pomocą polecnie <em>convert</em> jest kompresja.
+                       </p>
+<pre class="code-block">
+$ convert original.jpg -strip -sampling-factor 4:2:0 -quality 80 -interlace JPEG -colorspace RGB compressed.jpg
+</pre>
+                       <p>
+                               Za pomocą naszego polecenia możemy również zmienić wielkość naszego obrazka.
+                       </p>
+<pre class="code-block">
+$ convert huge_image.png -resize 500x500 resized_image.png
+</pre>
+                       <p>
+                               Obrazek zostanie przeskalowany za pomocą w uzwględnieniem proprocji, aby wyłączyć tę funkcję wydamy poniższe polecnie.
+                       </p>
+<pre class="code-block">
+$ convert huge_image.png -resize 500x500! resized_image.png
+</pre>
+                       <p>
+                               <strong>
+                                       Najciekawszą rzeczą jaką możemy zrobić za pomocą polecenia <em>convert</em> jest stworzenie gifa wskazując np. wszystkie obrazki w danym folderze za pomocą symbolu wieloznaczności.
+                               </strong>
+                       </p>
+<pre class="code-block">
+$ convert -delay 80 -loop 0 *.png my.gif
+</pre>
+                       <br />
+                       <h3>Połączenie wielu plików PDF w jeden</h3>
+                       <p>
+                               Pracujemy cięzko w systemie GNU/Linux, usprawniając nasze skrypty i nagle ktoś prosi nas o to <strong>aby połaczyć kilka PDF-ów</strong> w jeden żeby miał łatwiej do wydrukowania. Możemy spędzić znaczną częsć czasu na poszukiwanie odpowiedniego oprogramowania, chyba że <strong>użyjemy polecenia <strong>gs</strong></strong>, skrótu od nazwy programu <em>Ghostscript</em>, służacego do manipulowania PostScript-em oraz PDF-ami.
+                       </p>
+<pre class="code-block">
+$ gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=out.pdf file1.pdf file2.pdf file3.pdf ...
+</pre>
+                       <br />
+                       <h3>Łatwiejsze kopiowanie lub zmiana nazwy</h3>
+                       <p>
+                               Te zagadnienie mogą się przydać przy tworzeniu pierwotnej kopii pliku, przed wprowadzeń zmian oraz gdy utworzony plik powinien mieć jakieś przyrostek na końcu nazwy.
+                       </p>
+<pre class="code-block">
+$ cp /etc/fstab{,.bak}
+</pre>
+                       <p>
+                               To polecenie spowoduje utworzenie kopii pliku <em>/etc/fstab</em> z rozszerzeniem <em>.bak</em>. Podobne polecenie możemy wykonać gdy jesteśmy w takiej typowej sytuacji, że do pliku tekstowego stworzonego na UNIX-ie musimy do dodać rozszerzenie <em>.txt</em>.<br />
+                       </p>
+<pre class="code-block">
+$ mv wazne_dane{,.txt}
+</pre>
+                       <br />
+                       <h3>du oraz ncdu</h3>
+                       <p>
+                               Programy takie jak <strong>du</strong>, pomagają monitorować użycie miejsca na dysku, jednak samo wydanie polecnie wydaje się mało przydatne więc poniżej umieszcze kilka przydatnych przełączników, aby <em>du</em> zwracało bardzie przystępne wyniki.
+                       </p>
+                       <ul>
+                               <li><strong>-a</strong> - wyświetla rozmiar każdego pliku a nie rozmiar sumaryczny katalogów</li>
+                               <li><strong>-h</strong> - skalowanie jednostek rozmiaru</li>
+                               <li><strong>-s</strong> - sumaryczna wartość dla każde podanego argumentu (katalogu, pliku). Przydatne dla katalogów.</li>
+                               <li><strong>-x</strong> - przeliczenie jednostek dla jednego systemu plików, niektóre udziały sieciowe mogą być bardzo
+                                       wolne przez co przelicznie katalogów wraz z miejscami montowania może zająć wieki.</li>
+                               <li><strong>-d</strong> - maksymalny poziom zagłębienia w katalogi (rekruencji).</li>
+                       </ul>
+<pre class="code-block">
+/* Wyświetlenie przestrzeni zużytej przez nasz katalog domowy */
+$ du -sh ~/*
+</pre>
+                       <p>
+                               Innym ciekawym rozwiązaniem w monitorowaniu przestrzeni na dysku/dyskach może być program <strong>ncdu</strong>, do zainstalowania z repozytorium (przynajmniej w GNU/Linux Debian). Pozwala on w sposób bardziej interaktywny zaprezentowanie wykorzystania przestrzeni dyskowej. Program nie jest jakość bardzo skomplikowany, więc nie ma sensu go tu opisywać. Uruchomienie go bez żadnego argumentu pokaże zużycie dla katalogu, w którym się obecnie znajdujemy.
+                       </p>
+<pre class="code-block">
+$ ncdu
+</pre>
+                       <br />
+                       <h3>Podgląd potoku</h3>
+                       <p>
+                               Istnieje narzędzie, dzięki któremu możemy podejrzeć kopiowanie danych, <strong>pv</strong> - Pipe Viewer. Dosłownie podglądacz potoku. Zasada korzystania z <em>pv</em> jest dosyć prosta, otóż chcąc skopiować zwyczajny plik, podajemy ścieżkę zródłową jako pierwszy argument następnie przekierowujemy standardowe wyście na ścieżkę docelową pamiętając po podaniu nazwy kopiowanego pliku.
+                       </p>
+<pre class="code-block">
+$ pv Dokumenty/oldVM.ova &gt; Pobrane/oldVM.ova
+</pre>
+                       <p>
+                               <strong>
+                                       Inny przykładem tutaj może być tworzenie pendrive-ów bootowalnych z GNU/Linux-em.
+                               </strong>
+                       </p>
+<pre class="code-block">
+$ dd if=Pobrane/manjaro-xfce-20.2.1-210103-linux59.iso | pv | dd  of=/dev/sdc bs=4M conv=fsync
+</pre>
+                       <p>
+                               Możliwe jest również użycie polecenia z przykładu ze zwykłym plikiem, jako ścieżkę źródłową podajemy ścieżkę do plik, natomiast jako ścieżkę dysk, tylko należy pamiętać aby podać cały, nie jedną partycje.
+                       </p>
+<pre class="code-block">
+$ pv Pobrane/manjaro-xfce-20.2.1-210103-linux59.iso &gt; /dev/sdX
+</pre>
+                       <br />
+                       <h3>Pewne działania w systemie działają bardzo długo...</h3>
+                       <p>
+                               Tak jak w tytule tego akapitu, niektóre operacje kopiowania działają bardzo długo a jeszcze jeśli nie damy żadnych dodatkowych opcji zwiększających gadatliwość tych programów to zobaczymy jedynie migający kursor. Jednak jest na jakieś rozwiązanie. Polecenie <strong>progress</strong>, jest wstanie wyciągnąć informacje na temat działania, niektórych poleceń systemowych takich jak <em>cp</em>, <em>rsync</em> itp. Poniżej lista:
+                       </p>
+<pre class="code-block">
+cp, mv, dd, tar, cat, rsync, grep, fgrep, egrep, cut, sort, md5sum, sha1sum,<br /> sha224sum, sha256sum, sha384sum, sha512sum, adb, gzip, gunzip, bzip2, bunzip2, xz, unxz, lzma, unlzma, 7z, 7za, zcat, bzcat, lzcat, split, gpg
+</pre>
+                       <p>
+                               Wystarczy że polecenie działa w tle lub na innym terminalu. Wystarczy wydać polecnie <em>progress</em>, już on sam je odnajdzie.
+                       </p>
+                       <br />
+                       <h3>Wysyłanie komunikatów wewnątrz systemu w postaci maili</h3>
+                       <p>
+                               <strong>Aby móc wysyłać maile wewnątrz systemu, potrzebujemy programu <em>mailx</em></strong>, wraz z nim zainstaluje się exim4. Pod czas jego konfiguracji wybierzemy konfiguracje lokalną. Po zainstalowaniu programu samo wysyłanie komunikatów jest proste za pomocą potoku przekazujemy komunikat, czy to log z pliku, wyjście ze skryptu czy zwykły napis za pomocą polecnie <em>echo</em>, temat podajemy po przełączniku <code class="code-inline">-s</code> po temacie podajemy nadawcę, przeważnie <code class="code-inline">nazwa_uzytkownika@localhost</code>.
+                       </p>
+<pre class="code-block">
+$ echo "TEST" | mail -s "Komunikat testowy" xf0r3m@localhost
+</pre>
+                       <br />
+                       <h3>Lista otwartych plików</h3>
+                       <p>
+                               Po skopiowaniu danych pendrive, chcemy go odmontować jednak dostajemy komunikat o tym że cel jest zajęty. W tym przypadku możemy podejrzeć otwarte pliki za pomocą polecenia <strong>lsof</strong> i sprawdzić czy jakiś proces korzysta z plików z naszego pendrive'a, kiedy wydamy jest od tak po prostu w systemie ukaże nam się bardzo długa lista wyszystkich otwartych plików systemie, z racji konstrukcji UNIX-ów, gdzie prawie wszystko jest plikiem ta lista może być naprawdę długa. Możemy ją jednak ograniczyć za pomocą potoku oraz polecenia <em>grep</em>.
+                       </p>
+<pre class="code-block">
+$ lsof | grep "bushi"
+vim 4504 xf0r3m 4u REG 254,3 122880 7735057 /home/xf0r3m/Nextcloud/Devel/morketsmerke/articles/terminallog/.bash_bushido.html.swp
+</pre>
+                       <br />
+                       <h3>Automatyczne potwierdzenie wykonania polecenia</h3>
+                       <p>
+                               Czasami działanie, niektórych programów może mieć bardzo destrukcyjny wpływ na systemem, wiec same programy pytają czy kontynuować. Takie zachowanie jest bezpieczne, ale jeśli chcemy użyć tego polecenia w skrypcie? Czasami sami twórcy implementują opcje wymuszenia potwierdzenia zazwyczaj za pomocą przełącznika <code class="code-inline">-f</code> lub <code class="code-inline">--force</code>, nie jest to jednak standardem. Dla wszystkich poleceń, których działanie wymaga potwierdzenia a chcemy ich użyć w skrypcie to możemy przekierować do takiego polecenia wyjście polecenia <strong>yes</strong>, które po prostu potwierdzi automatycznie działanie takich programów.
+                       </p>
+                       <br />
+                       <h3>Jednoczesne przekierowanie wyjścia do pliku i wyjście standardowe</h3>
+                       <p>
+                               Polecenie <strong>tee</strong> przekierowuje wszystko co dostanie na standardowe wejście na swoje standardowej wyjście oraz do pliku, który podamy jako pierwszy argument, polecenie to ma tyle zastosowań że aż ciężko wymienić. Na przykład:
+                       </p>
+<code class="code-block">
+$ bash -x script.sh 2&gt;&1 | tee script.debug
+</code>
+                       <p>
+                               W tym wypadku podczas debugowania sporych pętli możemy użyć polecnia        <em>tee</em>. Jednak nie jest to najlepszy przykład ponieważ <em>tracelog</em>, <em>BASH</em>-a jest wyświetlany na strumieniu błędów więc musiałem podłączyć wyjście diagnostyczne do standardowego wyjścia.
+                       </p>
+                       <br />
+                       <h3>Zapisanie sesji terminala</h3>
+                       <p>
+                               Tytuł może wprowadzić w błąd, ponieważ jeśli ktoś czytał rodział o historii wie, że każda sesja jest zapisna w historii sztuką jest ją tylko odnaleźć, <strong>jednak tutaj "Zapisanie sesji termianala" możemy określić jako nagranie sesji terminala do pliku tekstowego. Program <em>script</em> do uruchomienia potrzebuje pliku jako pierwszego argumentu po uruchomieniu zapisuje do niego wszystkie wpisane polecenia</strong> kiedy chcemy zakończyć nagrywanie wydajemy po prostu polecenie <em>exit</em>. Polecenie <em>script</em> może być niezwykle przydatne podczas tworzenia skryptów czy tutoriali.
+                       </p>
+                       <br />
+                       <h3>Miekki restart powłoki</h3>
+                       <p>
+                       Czasami nasza powłoka może zachowywać się dziwnie, szczególnie gdy wyświetlimy jakiś przypadkiem jakiś plik binarny. To teraz możemy albo wyłączyć terminal i włączyć go ponownie lub wykonać miękki restart powłoki. Dlaczego <em>miękki</em>? Ponieważ jest on wykonywany z polecenia wydawanago właśnie w uszkodzonej powłoce, jeśli czujemy że coś jest nie tak, wywołajmy po prostu polecenie <strong>reset</strong>.
+                       </p>
+                       <br />
+                       <h3>Uruchomienie polecenia na podstawie odpowiedniego obciążenia systemu (load average)</h3>
+                       <p>
+                               <strong>Za pomocą polecnie <em>batch</em>, możey ustawić odpowiedni program, który zostanie uruchomiony kiedy wartość <em>load average</em> osiągnie konkretną wartość</strong>. Warto zwrócić uwagę że jest polecnie podobne do polecenia <em>at</em>, nawet znak zachęty jest identyczny, więc konfiguracja jest już znana z <em>at</em>, warto wspomnieć że domyślną wartością załadowania systemu dla programu <em>batch</em> jest <em>0.8</em>. Możemy to zmienić wykorzystując zmienną <em>OPTS</em>, w której to zdefiniujemy wartość <em>load average</em>, po której osiągnięciu zostanie uruchomione polecenie zdefiniowane w przy użyciu polecnia <em>batch</em>.
+                       </p>
+               <p>&nbsp;</p>
+               <h2 id="11.terminator">11. Emulatory terminala</h2>
+               <p>
+               Tworząc maszyny dla projektu VTMP, podczas instalacji dystrybucji BlackArch skierowanej pod testy penetracyjne po wybraniu środowiska zostaniemy nazwani <em>noobami</em> - nowicjuszem/słabiakiem. Daje to trochę do myślenia. Sam RMS nie korzysta ze srodowiska graficznego zatem tekstowa konsola systemu jest najlepszym emulatorem terminala, oparta na wyżej wspomnianej bibliotece GNU Readline. Jednak rzeczywistość weryfikuje nasze marzenia bycia pro, musimy skorzystać z przeglądarki albo jak odpalić muzykę na Spotify bez GUI. Na GitHub jest kilka projektów, z których możemy skorzystać, ale i tak poprawne skonfigurowanie programów odpowiedzialnych za dźwiek na UNIX-ach przypada konfiguracji środowiska graficznego, więc puki co radzę przy tym pozostać. Szanujmy nasz czas oraz pracę tych wszystkich osób zaangażowanych w tworzenie GUI. Ile środowisk tyle różnych emulatorów, ale jeden się wybija ponad wszystkie i trzeba go zainstalować.
+               Mianowicie <strong>terminator</strong>, najciekawszą z funkcji jest możliwość podzielenia jednego okna na kilka odrębnych powłok<br />
+               </p>
+               <ul>
+                       <li><strong>ctrl+shift+e</strong> - podzielenie panelu na dwie równe części w pionie.</li>
+                       <li><strong>ctrl+shift+o</strong> - podzielenie panelu na dwie równe części w poziomie.</li>
+               </ul>
+               <p>
+                       Na liście specjalnie napisałem panelu, ponieważ każdą wydzieloną częsć również możemy znów podzielić na kolejne dwie części w dowolnym kierunku. Samo początkowe okno jest pojedyńczym panelem. Inną ciekawą rzeczą jest możliwość zmiany nazw kart jeśli już ich używamy. Terminator daje znacznie więcej możliwości, pomoc jest dostępna pod klawiszem F1, niestety potrzebny jest internet. Wiem że Twój ulubiony emulator jest najlepszy jednak serdecznie polecam wypróbować <em>terminator</em>.
+               </p>
+               <br />
+               <h2 id="12.end">12. Koniec</h2>
+               <p>
+                       To było by na tyle jeśli chodzi jakąś bardziej zaawansowaną naukę obsługi powłoki. Jeśli ktoś jest "powłokofilem", to polecam użyć poniższego polecenia.
+               </p>
+<pre class="code-block">
+$ man bash
+</pre>
+               <p>
+               Poziomu mistrzowskiego w obsłudze powłoki.
+               </p>
+           </div>
+      </div>   
+               </body>
+       </html>
diff --git a/articles/terminallog/GNU_mailutils_jako_program_mailowy.html b/articles/terminallog/GNU_mailutils_jako_program_mailowy.html
new file mode 100755 (executable)
index 0000000..1d5dde1
--- /dev/null
@@ -0,0 +1,410 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <style>
+                               .code-block {
+                                       display: block;
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                                       text-align: left;
+                               }
+                               .code-inline {
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+                               p { text-align: justify; }
+                       </style>
+               </head>
+               <body style="font-family: monospace;" >
+<pre>
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+                       <p style="margin: 0; padding: 0; outline: 0; font-size: 18pt;">
+                               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+                       </p>
+                       <div style="margin-left: auto; margin-right: auto; width: 80%;">
+                               <h1 style="text-align: center;">GNU mailutils jako program mailowy</h1>
+        <p>
+          W niektórych UNIX-ach można napotkać polecenie <em>mail</em>.
+          Jest ono obecnie wykorzystywane do przesyłania wiadomości
+          w obrębnie jednego systemu, jednego serwera. Za pomocą kilku
+          dodatkowych programów można go skonfigurować do użytku z serwerami
+          konfigurowanymi na podstawie materiałów z tej strony oraz popularnymi
+          skrzynkami dostępnymi w internecie.
+        </p>
+        <p>
+          Przed każdą instalacją oprogramowania warto zaktualizować nie tylko
+          listy pakietów, ale i zainstalowany system. Ja używam greenOS
+          bazującego na GNU/Linux Debian, dlatego też przedstawiony tutaj 
+          menedżer pakietów to APT.
+        </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+</pre>
+        <ol>
+          <li>
+            <strong>Instalacja oprogramowania</strong>
+            <p>
+              <em>GNU mailutils</em> nie jest sam w sobie klientem pocztowym
+              jakie wszyscy znamy, dlatego musimy go wspomóc kilkoma
+              programami, aby spełnił naszym oczekiwaniom.  Jeśli w naszym w 
+              systemie polecenie <em>mail</em>
+              nie występuje to należy również zainstalować pakiet 
+              <em>GNU mailutils</em>.
+            </p>
+<pre class="code-block">
+$ sudo apt install mailutils fetchmail procmail postfix libsasl2-2 ca-certificates libsasl2-modules
+</pre>
+            <p>
+              Podczas instalacji <em>Postfix</em>-a zostanie wyświetlone
+              okno dialogowe odnośnie jego konfiguracji, wybieramy
+              <em>Strona internetowa/Internet site</em>, w polu wpisujemy
+              FQDN swojego komputera.
+            </p>
+          </li>
+          <li>
+            <strong>Utworzenie skrzynki mailowej</strong>
+            <p>
+              Skrzynka mailowa na UNIX-ie jest zwykłym plikiem o nazwie
+              użytkownika, który powinien znajdować się w katalogu 
+              <em>/var/mail</em>, jeśli jednak musieliśmy zainstalować
+              <em>GNU mailutils</em>, to prawdobodobnie plik nie będzie
+              istnieć i trzeba go utworzyć.
+            </p>
+<pre class="code-block">
+$ sudo touch /var/mail/xf0r3m
+$ sudo chown xf0r3m:mail /var/mail/xf0r3m
+</pre>
+            <p>
+              Aby plik mógł być obsługiwany przez <em>mail</em>, musimy nadać
+              mu odpowiednie prawa własności - takie jak na powyższym
+              przykładzie.
+            </p>
+          </li>
+          <li>
+            <strong>Konfiguracja fetchmail - plik ~/.fetchmail</strong>
+            <p>
+              Kiedy plik skrzynki jest gotowy, możemy skonfigurować program,
+              który pobierze do niego maile z serwera. W pliku
+              <em>.fetchmailrc</em> w katalogu domowym użytkownika zapisujemy
+              poniższe opcje. 
+            </p>
+<pre class="code-block">
+set daemon 300
+set logfile fetchmail.log
+
+poll mail.example.com proto IMAP
+  user "xf0r3m" pass "passw0rd" is "xf0r3m" preconnect "date &gt;&gt; fetchmail.log"
+  ssl
+  fetchall
+  no rewrite
+  mda "/usr/bin/procmail -f %F -d %T";
+</pre>
+            <p>
+              Gdzie:
+              <ul>
+                <li>
+                  <code class="code-inline">set daemon 300</code> -
+                  uruchomienie <em>fetchmail</em> powoduje uruchomienie
+                  daemona, który pobiera maile następnie przechodzi w stan
+                  uśpienia, ta opcja ustawia co ile sekund daemon 
+                  <em>fetchmail</em> ma się wybudzać i pobierać pocztę.
+                </li>
+                <li>
+                  <code class="code-inline">set logfile fetchmail.log</code> - 
+                  wskazanie pliku dla logów programu.
+                </li>
+                <li>
+                  <code class="code-inline">
+                    poll mail.example.com proto IMAP
+                  </code> - wskazanie serwera oraz protokołu z jakiego ma
+                  korzystać.
+                </li>
+                <li>
+                  <code class="code-inline">
+                    user "xf0r3m" pass "passw0rd" is "xf0r3m" preconnect
+                    "date &gt;&gt; fetchmail.log"
+                  </code> - wskazanie użytkownika zdalnego wraz danymi
+                  uwierzytelniającymi, jawne przekazanie informacji do czyjej
+                  skrzynki mają trafić pobrane wiadomości
+                  (<code class="code-inline">is "xf0r3m"</code>), dyrektywa
+                  <code class="code-inline">preconnect</code> wykonuje podane
+                  jako argument polecenie przy każdym połączeniu z serwerem.
+                  W tym przypadku będziemy wiedzieć kiedy wiadomości zostały
+                  pobrane, lub coś poszło nie tak.
+                </li>
+                <li>
+                  <code class="code-inline">ssl</code> - fetchmail 
+                  wykorzysta SSL/TLS
+                  do połączenia się z serwerem, używając przy tym portów IMAPS
+                  lub POP3S. 
+                </li>
+                <li>
+                  <code class="code-inline">fetchall</code> - program będzie
+                  pobierać wszystkie maile jakie znajdzie w skrzynce tego
+                  użytkownika na serwerze. 
+                </li>
+                <li>
+                  <code class="code-inline">no rewrite</code> - opcja powoduje
+                  pozostawienie oryginalnych nagłówków, bez tej opcji mogły
+                  by zostać nadpisane przez fetchmail.
+                </li>
+                <li>
+                  <code class="code-inline">
+                    mda "/usr/bin/procmail -f %F -d %T";
+                  </code> - MDA (ang. <em>Mail Delivery Agent</em>) - program
+                  dostarczający pocztę, fetchmail po pobraniu przekaże maile
+                  do <em>procmail</em>, który dostarczy je do naszej skrzynki.
+                  Opcje procmaila: <code class="code-inline">-f %F</code> -
+                  zarejestruje w logach od kogo przychodzi wiadomość,
+                  <code class="code-inline">-d %T</code> - właśnie ta opcja
+                  umożliwia dostarczenie poczty do lokalnej skrzynki
+                  użytkownika.
+                </li>
+              </ul>
+            </p>
+          </li>
+          <li>
+            <strong>Zmiana uprawnień ~/.fetchmailrc</strong>
+            <p>
+              Daemon nie wystartuje jeśli plik ~/.fetchmailrc nie będzie
+              posiadał odpowiednich uprawnień.
+            </p>
+<pre class="code-block">
+$ chmod 700 ~/.fetchmailrc
+</pre>
+          </li>
+          <li>
+            <strong>Testowanie fetchmaila</strong>
+            <p>
+              Teraz możemy przestestować <em>fetchmail</em>, wysyłając 
+              testowego maila
+              na skrzynkę, z której program pobiera wiadomości. Zaraz po 
+              uruchomieniu
+              polecenia warto w drugim terminalu otworzyć sobie plik logów
+              <em>fetchmail</em> w podglądzie na żywo. Wydajemy polecenie:
+            </p>
+<pre class="code-block">
+$ fetchmail
+
+#w drugim terminalu:
+$ tail -f fetchmail.log
+</pre>
+            <p>
+              Jeśli jesteśmy pewni, że nowa wiadomość znajduje się na skrzynce
+              a <em>fetchmail</em> niczego nie pobrał, w logach wyświetla się
+              tylko data. Oznacza to, że program się zawiesił. Tak się dzieje
+              za pierwszym razem. W tej sytuacji zostaje zabicie procesu i 
+              uruchomienie go ponownie, jeśli to nie zadziała to należy
+              wyłączyć SSL, uruchomić ponownie <em>fetchmail</em> pobrać pocztę
+              i uruchomić SSL ponownie.
+            </p>
+          </li>
+          <li>
+            <strong>Konfiguracja Postfix, aby wysyłać maile przez GNU
+              mailutils</strong>
+            <p>
+              Załóżmy, że otrzymaliśmy maila i chcemy na niego odpowiedzieć,
+              aby wiadomość opuściła nasz komputer i została przesłana do
+              serwera SMTP musimy mieć skonfigurowany <em>Postfix</em>
+              jako przekaźnik (ang. <em>relay</em>).
+            </p>
+            <p>
+              W pliku <em>/etc/postfix/main.cf</em> odnajdujemy opcje
+              <code class="code-inline">relayhost</code> przypisujemy jej
+              adres serwera SMTP w nawiasach kwadratowych, za nawiasami po
+              dwukropku podajemy numer portu, pod którym SMTP jest dostępny
+              dla klientów.
+            </p>
+<pre class="code-block">
+relayhost = [mail.example.com]:587
+</pre>  
+            <p>
+              Aby można było przekazać wiadomości, które będą wysyłane za
+              pośrednictwem tego systemu, potrzeba jeszcze kilku ustawień, pod
+              <code class="code-inline">relayhost</code> zapisujemy
+              poniższe opcje.
+            </p>
+<pre class="code-block">
+smtp_sasl_auth_enable = yes
+smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+smtp_sasl_security_options = noanonymous
+smtp_tls_CAfile = /etc/postfix/cacert.pem
+smtp_use_tls = yes
+</pre>
+            <p>
+              Zapisujemy zmiany w pliku.
+            </p>
+          </li>
+          <li>
+            <strong>Utworzenie pliku z danymi uwierzytelniającymi i nadanie
+              mu odpowiednich uprawnień</strong>
+            <p>
+              Jak mogliśmy zauważyć w poprzednim punkcie, występuje tutaj plik 
+              mapowania, zawierający powiązania adresów 
+              serwerów z danymi uwierzytelniającymi. Plik tworzymy zgodnie ze
+              ścieżką podaną w opcji 
+              <code class="code-inline">smtp_sasl_password_maps</code>,
+              wewnątrz każda jedna linia to mapowanie. Na mapowanie składa się
+              adres serwera wraz z portem zapisane identycznie jak w opcji
+              <code class="code-inline">relayhost</code> oraz kombinacja nazwy
+              użytkownika z hasłem odseparowane dwukropkiem.
+            </p>
+<pre class="code-block">
+[mail.example.com]:587  xf0r3m:passw0rd
+</pre>
+            <p>
+              Uprawnienia jakie należy nadać są chyba najbardzie restrykcyjne w
+              całym systemie, bo tylko użytkownik z uprawnieniami
+              administracyjnymi będzie mógł w nim wprowadzać zmiany. Właściciel
+              bez podniesienia uprawień, będzie mógł jedynie przeczytać 
+              zawartość.
+              Grupa oraz pozostali nie będą mieć żadny praw.
+            </p>
+<pre class="code-block">
+$ sudo chmod 400 /etc/postfix/sasl_passwd
+</pre>
+          </li>
+          <li>
+            <strong>
+              Utworzenie bazy z pliku mapowania.
+            </strong>
+            <p>
+              Plik, aby był użyteczny przez <em>Postfix</em>, musi zostać
+              skonwertowany na format dla niego czytelny. Do konwersji posłuży
+              polecenie dostarczane wraz z <em>Postfix</em>.  
+            </p>
+<pre class="code-block">
+$ sudo postmap /etc/postfix/sasl_passwd
+</pre>
+          </li>
+          <li>
+            <strong>Plik /etc/postfix/cacert.pem</strong>
+            <p>
+              Jeśli wrócimy do konfiguracji <em>Postfix</em> to, że 
+              zauważymy
+              wartości opcji <code class="code-inline">smtp_tls_CAfile</code>
+              przypisana jest ścieżka. Ścieżka do pliku, który nie istnieje.
+              Plik ten jest certyfikatem urzędu certyfikacji - wystawcy
+              certyfikatu, który jest używany przez serwer SMTP, aby dowiedzieć
+              kto jest wystawcą certyfikatu dla serwera SMTP musimy się z nim
+              w odpowiedni sposób połączyć. Poniższe polecenie wskaże plik,
+              który należy skopiować do <em>/etc/postfix/cacert.pem</em>.
+            </p>
+<pre class="code-block">
+$ echo "/etc/ssl/certs/$(ls /etc/ssl/certs | grep "$(openssl s_client -showcerts
+-starttls smtp -connect mail.example.com:587 &lt; /dev/null 2&gt;1 | head -1 
+| cut -d "=" -f 5 | sed 's/ /_/g' | sed 's/_//')" | tail-1)"
+</pre>
+            <p>
+              <em>Polecenie zawinięto, aby zachować poprawne wyświetlanie layout strony</em>
+            </p>
+            <p>
+              Wyświetlony plik  należy skopiować na wyżej
+              wymienioną ścieżkę.
+            </p>
+<pre class="code-block">
+$ cat /etc/ssl/certs/IRSG_Root_X1.pem | sudo tee -a /etc/postfix/cacert.pem
+</pre>
+            <p>
+              Plik ten może przydać się przy potencjalnych problemach z 
+              rozpoznaniem certyfikatu.
+            </p>
+          </li>
+          <li>
+            <strong>Problem z adresem nadawcy</strong>
+            <p>
+              Ten punkt tyczy się głównie połączeń z serwerami SMTP, które były
+              konfigurowane za pomocą materiałów dostępnych na tej stronie.
+              Dla innych to już jest koniec, teraz można smiało czytać i pisać
+              maile za pomocą podstawowych UNIX-owych narzędzi.
+            </p>
+            <p>
+              Restrykcje
+              wprowadzone na serwerze wyrażają jasno, że by wysłać wiadomość
+              adres nadawcy musi zgadzać się z mapowaniem. Niestety
+              <em>GNU mailutils</em> automatycznie przypisuje adres nadawcy
+              składający się z nazwy użytkownika oraz nazwy komputera. W moim
+              przypadku było to <em>xf0r3m@e5270</em>, jest to 
+              niezgodne z mapowaniem i wiadomości zostaną odrzucone przez
+              serwer. Nie znalazłem sposobu, aby obejść to lokalnie
+              w obrębnie jednego użytkownika, jest możliwość ustawienia 
+              domyślnego adresu nadawcy w obrębie całego systemu. Tworzymy
+              plik <em>/etc/mailutils.conf</em>, i zapisujemy w nim poniższą
+              konfigurację.
+            </p>
+<pre class="code-block">
+program mail {
+
+  address {
+    email-addr xf0r3m@example.com;
+  }
+
+};
+</pre>
+            <p>
+              Teraz maile powinny się bez problemu wysyłać.
+            </p>
+          </li>
+        </ol>
+        <p>
+          Przestawione tutaj rozwiązanie, nie jest pozbawione wad. Mogą pojawić
+          się problemy ze znalezieniem serwera przez <em>Postfix</em>, ponieważ
+          faworyzuje on IPv6, można temu zaradzić ustawiając opcję 
+          <code class="code-inline">inet_protocols</code> na <em>ipv4</em>.
+          Po czym należy kompletnie zrestartować usługę za pomocą
+          polecenia <em>systemctl</em>.
+          Problemem też jest nierejestrowanie wiadomości wysłanych, co też
+          jest do rozwiązania poprzez ustawienie opcji <em>Postfix</em>
+          <code class="code-inline">always_bcc</code> na swój adres przez co
+          zaraz po wysłaniu maila dostaniemy zwrotkę z własną wiadomością. 
+          Kolejnym
+          problemem może być sama obsługa programu <em>mail</em>, po otrzymaniu
+          wiadomości dostaniemy powiadomienie najczęściej w terminalu. Po
+          sprawdzeniu tych wiadomości zostaną one przekopiowane do pliku
+          <em>mbox</em> w naszym katalogu domowym. A co jeśli odczytaliśmy
+          wiadomość, nie mogliśmy na nią wcześniej odpowiedzieć i chcemy to
+          zrobić teraz, to kiedy wpisujemy polecenie <em>mail</em> to okazuje
+          się że domyślna skrzynka jest pusta i musimy uruchomić program z 
+          odpowiednim przełącznikiem i wskazać mu plik skrzynki.
+        </p>
+<pre class="code-block">
+$ mail -f ~/mbox
+</pre>
+        <p>
+          Interaktywana praca z tym programem również, może przyprawić o ból
+          główy, jednak dawno temu nie jaki John Kerl odwalił kawał dobrej 
+          roboty opisując jak używać tego programu.
+        </p>
+        <p>
+          <a href="http://www.johnkerl.org/doc/mail-how-to.html">
+            http://www.johnkerl.org/doc/mail-how-to.html
+          </a>
+        </p>
+        <p>
+          Rozwiązanie to jest definitywnie hakerskie, dla ludzi nie bojących
+          pobrudzić sobie rączek. Taka gimnastyka dla mózgu z rana, kiedy
+          trzeba wysłać maila, będąc w powłowie jeszcze w łóżku.
+        </p>
+        <p>
+          ~xf0r3m
+        </p>
+                       </div>
+                       <p style="margin: 15px; padding: 0; outline: 0;">
+                               2021; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/Git_-_podstawy_systemu_kontroli_wersji.html b/articles/terminallog/Git_-_podstawy_systemu_kontroli_wersji.html
new file mode 100755 (executable)
index 0000000..ee6bcce
--- /dev/null
@@ -0,0 +1,663 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       <style>
+                               .code-block {
+                                       text-align: left;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+                       </style>
+               </head>
+               <body>
+<pre>
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+       <div class="main">
+               <h1 class="title">Git - podstawy systemu kontroli wersji</h1>
+
+               <p>
+                       <strong>
+                               Ta strona wymaga aktualizacji, informacje na niej zawarte <u>mogą być niezgodne z prawdą.</u>
+                       </strong>
+               </p>
+               <p>
+                       W tym jakże krótkim wpisie chciałbym przedstawić podstawową obsługę systemu kontroli wersji <strong>Git</strong>. Podstawowym zadaniem Git-a jest monitorowanie zmian oraz umożliwienie wycofania modyfikacji w danym pliku.
+               </p>
+               <h2>Podstawy lokalnego systemy kontroli wersji Git</h2>
+               <p>
+                       Folder z danymi, na których pracujemy po zainstalowaniu <strong>repozytorium</strong> staje się pierwszą warstwą pracy z Git. Tę warstwę nazywamy <strong>working directory</strong> (ang. katalog roboczy). Natomiast samo repozytorium, które umożliwni nam pracę z Git instalujemy poniższym poleceniem.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git init
+</pre>
+               <p>
+                       Czym jest repozytorium? Repozytorium to ukryty katalog wewnątrz katalogu roboczego. W nim  znajdują się zapisane i przechowane w odpowiedni sposób zamiany wprowadzone w plikach katalogu roboczego. Po zainstalowaniu repozytorium w katalogu, w którym jakieś pliki już istnieją możemy je dodać wybiórczo, korzystając z poniższego polecenia:
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git add landisk.sh</pre>
+</pre>
+               <p>
+                       lub dodać wszystkie pliki z katalogu, wykorzystując to polecenie:
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git add .
+</pre>
+               <p>
+                       Nowe pliki są automatycznie zauważane przez Git, jako zmiany w katalogu roboczym.
+               </p>
+               <p>
+                       Podając <strong>.</strong> (kropkę) jako argument polecenia <em>add</em>, dodaliśmy wszystkie plik do naszego repozytorium. Rozważmy teraz taki scenariusz, że nasze repozytorium zawiera bardzo dużo plików. Moglibyśmy skorzystać z polecenia <code class="code-inline">git add .</code> jednak w naszym repozytorium znajdują się pliki, których nie chcemy monitorować, w tej sytuacji możemy regulować, które pliki mają być monitorowane, a które nie. Służy temu specjalny plik Git-a, umieszczany w repozytorium: <strong>.gitignore</strong>. W tym pliku umieszczamy nazwy katalogów, plików (w nazwach plików możemy używać symbolu wieloznaczności <strong>*</strong>) lub ścieżki, które mają zostać pominięte podczas monitorowania katalogu przez Git. Pamiętać należy o tym że <span style="text-decoration: underline;">ten plik jest ukryty</span>.
+               </p>
+               <p>
+                       Wszystkie zauważone przez Git zmiany możemy sprawdzić za pomocą polecenia:
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git status
+</pre>
+               <p>
+                       Z informacji zwróconych przez polecenie, możemy sprawdzić stan naszych plików, teraz po dodaniu plików do monitorowania mamy informacje o zamianach w naszym katalogu roboczym. Korzystanie z Git-a, nie jest wcale trudne, sam Git daje nam podpowiedzi, aby usunąć jakiś plik z obecnego <strong>stanu przejściowego</strong> wydajemy poniższe polecenie. <strong>Uwaga!</strong> <strong>Usunięcie plików ze stanu przejściowego nie spowoduje przywrócenia pliku przed zmianami.</strong> Plik zostanie pominięty podczas zapisywania go zapisywania go w repozytorium:
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git rm --cached &lt;nazwa_pliku&gt;
+</pre>
+               <p>
+                       Czym jest ten stan przejściowy? Otóż podczas pracy z Git-em, operujemy tak naprawdę na trzech płaszczyznach.
+               </p>
+               <figure style="margin: auto; width: 50%;">
+                               <img src="https://i.ibb.co/CsgDgyb/git-diagram-1.png" alt="Diagram with local repository workflow"/>
+               </figure>
+               <p>
+                       Pierwszy z nich to <strong>katalog roboczy</strong>, na plikach w tym katalogu są dokonywane przez nas zmiany, te zmiany są rejestrowane w tak zwanym <strong>stanie przejściowym</strong>. Ten stan przechowuje wszystkie zmiany przed zapisaniem ich w repozytorium, tworzy tymczasowe migawki plików, w których dokonano zmian. Ze stanu przejściowego bardzo łatwo cofnąć zmiany wystarczy jedno polecenie.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/Dokumenty/landisk $ git checkout landisk.sh
+</pre>
+               <p>
+                       Podając jako argument nazwę pliku przywracamy tylko konkretny plik, warto zauważyć że po wydaniu tego polecenia, zmiany zarejestrowane przez Git w pliku zostają wycofane oraz zostaje on usunięty ze stanu przejściowego. Zamiast nazwy pliku możemy użyć kropki (<strong>.</strong>), wtedy przywrócimy wszystkie pliki. Warto pamiętać, że polecenie <em>checkout</em> wycofuje zmiany tylko z stanu przejściowego. To polecenie <strong>nie działa na nowe pliki</strong>. Jak widzimy możemy sobie swobodnie balansować pomiędzy stanem przejściowym, a katalogiem roboczym. W edytorze naciskamy <em>ctrl+s</em>, Git od razu wyłapuje zmianę, testujemy, coś nie działa, wydajemy polecenie <code class="code-inline">git checkout</code>, zmiany zostały wycofane, kiedy jednak jesteśmy pewni że nasz kod działa możemy dokonać <strong>zatwierdzenia</strong>. Zatwierdzenie jest dokonywane z plików, których zmiany zostały uwzględnione w stanie przejściowym.
+                       To co znajduje się w stanie przejściowym sprawdzamy poleceniem <code class="code-inline">git status</code>. Zatwierdzenie dokonuje takiej stałej migawki, którą będzie mogli przywrócić nie zależnie od tego ile zmian było już plikach projektu, kiedy przy poleceniu <em>checkout</em> możemy cofnąć tylko ostatnią zmianę. Aby dokonać zatwierdzenia, wydajemy następujące polecenie.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/git_lab/repo1$ git commit -am "Pierwsze pliki"
+[master (root-commit) 7f5135a] Pierwsze pliki
+ 2 files changed, 9 insertions(+)
+ create mode 100644 imiona
+ create mode 100644 kolory
+</pre>
+               <p>
+                       Opcja <code class="code-inline">-a</code> w poleceniu powoduje uwzględnienie wszystkich zmodyfikowanych plików, z kolei <code class="code-inline">-m</code> powoduje dodanie komentarza do zatwierdzenia. Sprawdzenie stanu repozytorium dokonujemy za pomocą polecenia
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/git_lab/repo1$ git log --pretty=oneline
+7f5135af8bca2dad1d9f1d7c7db34990a6115efa (HEAD -&gt; master) Pierwsze pliki
+</pre>
+               <p>
+                       Jak widzimy repozytorium jest takim miejscem przechowywania zatwierdzeń. Teraz dokonamy zmian w plikach aby mieć jeszcze jedno zatwierdzenie w repozytorium. Po wiedzmy że w tym zatwierdzeniu powinny być dwa pliki zmienione nie tylko jeden. Z repozytorium pliki możemy przywrócić na dwa sposoby: do stanu przejściowego (<code class="code-inline">git reset --soft</code>) oraz do katalogu roboczego (<code class="code-inline">git reset --hard</code>), jeśli chcemy dodać po prostu plik wycofując stare zatwierdzenie i utworzyć nowe tym razem obejmujące wszystkie pliki, wybierzemy opcje <em>--soft</em>. Jako argument opcji <em>--soft</em> podajemy to zatwierdzenie, z którego chcemy przywrócić pliki, nie te które ostatnio wprowadziliśmy, w którym znajduje się nasz błąd.
+               </p>
+<pre class="code-block">
+1f7ecc0bca359431bf11493358fd1f87e24fc341 (HEAD -&gt; master) Zmiany w imionach
+7f5135af8bca2dad1d9f1d7c7db34990a6115efa Pierwsze pliki
+</pre>
+               <p>
+                       Więc jako argument opcji <em>--soft</em> podamy <em>ID</em> zatwierdzenia <em>7f5135</em>. Po przywróceniu zatwierdzenie opisane jako "Zmiany w imionach" przestaje istnieć. Słowo o <strong>commit ID</strong>. Każde zatwierdzenie jest identyfikowane przez Git za pomocą długiego ciągu znaków zapisanego w systemie heksadecymalnym, który występuje w pierwszej kolumnie danych zwracanych przez polecenie <code class="code-inline">git log --pretty=oneline</code>. <em>Commit ID</em> jest sześcioma pierwszymi znakami tego ciągu.
+               </p>
+               <p>
+                       To kiedy wydamy polecenie
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/git_lab/repo1$ git status
+</pre>
+               <p>
+                       Otrzymamy taką odpowiedź (o ile nie wprowadziliśmy żadnych w innych plikach) od Git.
+               </p>
+<pre class="code-block">
+On branch master
+Changes to be committed:
+  (use "git restore --staged &lt;file&gt;..." to unstage)
+       zmodyfikowany: imiona
+</pre>
+               <p>
+                       Jeśli zmieniliśmy jakieś pliki to odpowiedź będzie taka jak poniżej:
+               </p>
+<pre class="code-block">
+On branch master
+Changes to be committed:
+  (use "git restore --staged &lt;file&gt;..." to unstage)
+       zmodyfikowany: imiona
+
+Changes not staged for commit:
+  (use "git add &lt;file&gt;..." to update what will be committed)
+  (use "git restore &lt;file&gt;..." to discard changes in working directory)
+       zmodyfikowany: kolory
+</pre>
+               <p>
+                       Teraz aby dodać te pliki należy wydać polecenie <code class="code-inline">git add &lt;nazwa_pliku&gt;</code> w tym przypadku są to <em>kolory</em>.
+               </p>
+               <p>
+                       Na tym przykładzie lepiej widać jak działa stan przejściowy. Kiedy plik zostaje zmodyfikowany, trafia on do stanu przejściowego jednak nie jest oznaczony jako plik do zatwierdzenia, dlatego wydajemy polecenie <em>commit</em> wraz opcją <code class="code-inline">-a</code>, aby nie musieć dodawać plików jako "do zatwierdzenia". Tylko zatwierdzać wszystkie zmodyfikowane pliki. Gdybyśmy nie stosowali tej opcji, to należało by każdy nieoznaczony plik dodać za pomocą polecenia <em>add</em>.
+               </p>
+               <p>
+                       Pozostała w sumie ostatnia podstawowa czynność jaką możemy wykonać czyli przywrócić pliki z repozytorium bezpośrednio do katalogu roboczego. Aby wykonać tą czynność wydajemy polecenie.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~/git_lab/repo1$ git reset --hard 7f5135
+</pre>
+               <p>
+                       Przy tym poleceniu z <em>ID</em> <em>commit-u</em> jest identycznie. Ten <em>commit</em>, który wybraliśmy jest oznaczony jako <strong>HEAD</strong>, czyli główny <em>commit</em> repozytorium.
+               </p>
+               <p>&nbsp;</p>
+               <h2>Prywatne, zdalne repozytorium</h2>
+               <p>
+                       Teraz utworzymy sobie w prosty sposób zdalne repozytorium, będzie to wymagać jedynie kilka poleceń w powłoce, ponieważ połączenia będziemy realizować za pomocą <strong>SSH</strong>.
+               </p>
+               <p>
+                       Na naszym serwerze sprawdzamy czy jest dostępny Git. Jeśli jest dostępny to możemy przejść od razu do tworzenie nowego użytkownika. Jeśli po wydaniu polecenia <code class="code-inline">git</code> dostajemy informacje o tym, że nie można odnaleźć polecenia, to wydajemy polecenie odpowiednie dla naszej dystrybucji, które zainstaluje Git w systemie.
+               </p>
+<pre class="code-block">
+ubuntu@gitssh:~$ sudo apt install git
+</pre>
+               <p>
+                       Kiedy Git znajduje się już w systemie, lub został przed chwilą zainstalowany, tworzymy użytkownika, który w swoim folderze domowym będzie przechowywał nasze repozytoria.
+               </p>
+<pre class="code-block">
+ubuntu@gitssh:~$ sudo adduser git
+</pre>
+               <p>
+                       W tym momencie (najlepiej zaraz po utworzeniu użytkownika), podać nasz klucz publiczny do logowania przez SSH nowemu użytkownikowi.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:~$ ssh-keygen
+xf0r3m@K53F:~$ ssh-copy-id git@gitssh
+</pre>
+               <p>
+                       Teraz kiedy już możemy zalogować się bez hasła, zalogujemy się na serwer jako <em>git</em>. Następnie tworzymy nowy katalog o nazwie <em>git-shell-commands</em> oraz nadamy mu odpowiednie uprawnienia.
+               </p>
+<pre class="code-block">
+git@gitssh:~$ mkdir git-shell-commands
+git@gitssh:~$ chmod 775 git-shell-commands
+</pre>
+               <p>
+                       Wylogowujemy się z tego użytkownika, a następnie logujemy się na użytkownika z uprawnieniami administracyjnymi, po zalogowaniu w pliku <em>/etc/passwd</em> zmieniamy domyślną powłokę dla użytkownika <em>git</em> z <code class="code-inline">/bin/bash</code> na <code class="code-inline">/usr/bin/git-shell</code>. Zapisujemy zmiany w pliku.
+               </p>
+<pre class="code-block">
+git:x:1001:1001:git,,,:/home/git:/usr/bin/git-shell
+</pre>
+               <p>
+                       Teraz kiedy wydamy polecenie <code class="code-inline">su git</code> ukaże nam się taki obraz (aby wyjść wydajemy polecenie <code class="code-inline">exit</code>):
+               </p>
+<pre class="code-block">
+git&gt;
+</pre>
+               <p>
+                       Aby jednak uruchomić normalną powłokę UNIX-ową dla tego użytkownika musimy zalogować się jako <em>root</em>. Następnie wydać poniższe polecenie.
+               </p>
+<pre class="code-block">
+root@gitssh:/home/ubuntu$ su -s /bin/bash - git
+</pre>
+               <p>
+                       Teraz zalogujemy się do powłoki <em>bash</em> na użytkowniku <em>git</em> i utworzymy katalog naszego repozytorium:
+               </p>
+<pre class="code-block">
+git@gitssh:~$ mkdir example.git
+</pre>
+               <p>
+                       Wewnątrz utworzonego przez nas katalogu wydajemy poniższe polecenie:
+               </p>
+<pre class="code-block">
+git@gitssh:~/example.git$ git --bare init
+</pre>
+               <p>
+                       Po wydaniu tego polecenia, nasze repozytorium jest gotowe, w celach testowych możemy przesłać na niego pusty plik README.
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:/git_lab/repo3$ touch README.md
+xf0r3m@K52F:/git_lab/repo3$ git init
+Initialized empty Git repository in /home/xf0r3m/git_lab/repo3/.git/
+xf0r3m@K52F:/git_lab/repo3$ git add .
+xf0r3m@K52F:/git_lab/repo3$ git commit -am "first commit"
+[master (root-commit) 5bafc2b] first commit
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ create mode 100644 README.m
+xf0r3m@K52F:/git_lab/repo3$ git remote add origin ssh://git@192.168.56.211/~/example.git
+xf0r3m@K52F:/git_lab/repo3$ git push origin master
+Enumerating objects: 3, done.
+Counting objects: 100% (3/3), done.
+Writing objects: 100% (3/3), 209 bytes | 209.00 KiB/s, done.
+Total 3 (delta 0), reused 0 (delta 0)
+To ssh://192.168.56.211/~/example.git
+ * [new branch]      master -&gt; master
+</pre>
+               <p>
+                       Powyżej mamy listing z terminala, użyłem tutaj dwóch nowych poleceń, które często będą wykorzystywane przez nas podczas pracy ze zdalnym repozytorium. Pierwsze polecenie:
+               </p>
+<pre class="code-block">
+xf0r3m@K52F:/git_lab/repo3$ git remote add origin ssh://git@192.168.56.211/~/example.git
+</pre>
+               <p>
+                       dodaje pod nazwą <strong>origin</strong> adres do zdalnego repozytorium do naszej lokalnej konfiguracji Git. Dzięki tej nazwie łatwiej będzie nam <strong>wpychać</strong> (przesyłać) nasze repozytorium na zdalny Git. Drugie polecenie:
+               </p>
+<pre class="code-block">
+git push origin master
+</pre>
+               <p>
+                       powoduje wepchnięcie <strong>gałęzi</strong> o nazwie <strong>master</strong> (głównego repozytorium) na zdalne repozytorium, którego adres kryje się po nazwą <em>origin</em>.
+               </p>
+               <p>
+                       Zdalne repozytorium po SSH jest dobre kiedy w szybki, prosty i bezpieczny sposób musimy stworzyć prywatne repozytorium. Jednak do pracy w wieloma użytkownikami jest ono nadzwyczaj nie wygodne, ponieważ każdy użytkownik musi zalogować się jako root, aby utworzyć kolejne repozytorium.
+               </p>
+               <p>
+                       Obecnie dostępne są trzy sprawne pakiety oprogramowania zapewniające usługę zdalnego repozytorium obsługiwane z poziomu WWW. Taki GitHub tylko że hostowany na swoich serwerach. Poniżej przedstawię instalację wszystkich trzech pakietów. Obsługa nie jest trudna, wystarczy czytać ze zrozumieniem i nie bać się eksperymentować. Jak co się uszkodzi to zawsze możemy zainstalować to jeszcze raz z poniższych poradników lub mieć z tyłu głowy zapisane, aby zrobić kopie zapasową naszego środowiska testowego przed wprowadzeniem jakieś poważnej zmiany, prawda ?
+               </p>
+               <p>&nbsp;</p>
+               <h2>GitLab</h2>
+               <p>
+                       Na początek weźmiemy pod lupę pierwszy najbardziej zaawansowany i w sumie najłatwiejszy do zainstalowania - <strong>GitLab</strong>. Moim środowiskiem testowym to przedstawienia instalacji była maszyna wirtualna VirtualBox z Ubuntu Server 20.04, nie radze używać kontenerów chyba że uprzywilejowanych, ponieważ GitLab podczas swojej instalacji zmienia kilka ustawień kernela.
+               </p>
+               <p>
+                       Dokonujemy aktualizacji repozytoriów z paczkami oprogramowania następnie instalujemy niezbędne w systemie pakiety. W Ubuntu Server 20.04, wymagane oprogramowanie jest już zainstalowane, jednak kiedy korzystamy z 18 lub 16.04 warto upewnić się czy te pakiety są już w naszym systemie.
+               </p>
+<pre class="code-block">
+xf0r3m@gitlab:~$ sudo apt update
+xf0r3m@gitlab:~$ sudo apt install curl openssh-server ca-certificates tzdata
+</pre>
+               <p>
+                       Instalacje Postfix możemy pominąć.
+               </p>
+               <p>
+                       Teraz dodamy repozytoria GitLab do naszych repozytoriów systemowych.
+               </p>
+<pre class="code-block">
+xf0r3m@gitalab:~$ curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
+</pre>
+               <p>
+                       Właściwa instalacja GitLab odbywa się za pomocą APT. Jednak przed wydaniem polecenia należy zdefiniować w zmiennej <code class="code-inline">EXTERNAL_URL</code>, adres pod którym nasz GitLab będzie dostępny.
+               </p>
+<pre class="code-block">
+xf0r3m@gitlab:~$ sudo EXTERNAL_URL="http://192.168.0.211" apt install gitlab-ce
+</pre>
+               <p>
+                       Instalacja GitLab może potrwać nawet do dwóch godzin w zależności od łącza internetowego oraz mocy obliczeniowej naszego sprzętu. O zakończeniu instalacji zostaniemy poinformowani odpowiednim komunikatem. Po zainstalowaniu możemy przejść pod adres, który podaliśmy w zmiennej EXTERNAL_URL. Po załadowaniu strony, zostaniemy poproszeni o zdefiniowanie hasła dla użytkownika administracyjnego GitLab. Teraz możemy zalogować się, podając w nazwie użytkownika nazwę <em>root</em>. Jeśli zdecydujemy się na użycie GitLab jako naszego zdalnego repozytorium, to należało by użyć HTTPS. Aby to zrealizować należy<em>:</em>
+               </p>
+               <ol>
+                       <li>Zmienić w pliku <em>/etc/gitlab/gitlab.rb</em> wartość opcji EXTERNAL_URL. Zmieć protokół na HTTPS następnie podać nazwę domeny, pod którą GitLab będzie dostępny.<br />
+<pre class="code-block">
+xf0r3m@gitlab:~$ sudo vi /etc/gitlab/gitlab.rb
+</pre>
+                               <p>
+                                       Wewnątrz pliku odszukujemy opcję <code class="code-inline">EXTERNAL_URL</code> i ustawiamy jej wartość na adres pod którym będzie widoczny GitLab.
+                               </p>
+<pre class="code-block">
+EXTERNAL_URL="https://gitlab.morketsmerke.net"
+</pre>
+                       </li>
+                       <li>Utworzyć katalog <em>ssl</em> wewnątrz katalogu <em>/etc/gitlab</em>, nadać mu uprawnienia 755 następnie przekopiować do tego katalogu nasze pliki certyfikatu.<br />
+<pre class="code-block">
+xf0r3m@gitlab:~$ sudo mkdir -p /etc/gitlab/ssl
+xf0r3m@gitlab:~$ sudo chmod 755 /etc/gitlab/ssl
+xf0r3m@gitlab:~$ sudo cp *.pem /etc/gitlab/ssl
+</pre>
+                       </li>
+                       <li>Następnie wydajemy polecenie:<br />
+<pre class="code-block">
+xf0r3m@gitlab:~$ sudo gitlab-ctl reconfigure
+</pre>
+                       </li>
+               </ol>
+               <p>
+                       Po zakończeniu rekonfiguracji GitLab powinien być dostępny pod adresem jaki podaliśmy w zmiennej <code class="code-inline">EXTERNAL_URL</code>, po protokole HTTPS.
+               </p>
+               <p>
+                       Kolejnym oprogramowaniem umożliwiającym nam łatwe utworzenie ogólnodostępnego zdalnego repozytorium Git-a będzie <strong>Gogs</strong>.
+               </p>
+               <p>&nbsp;</p>
+               <h2>Gogs</h2>
+               <p>
+                       Instalacje Gogs-a w naszym systemie <strong>rozpoczynamy od zainstalowania jakiegoś pakietu bazodanowego</strong> np. MySQL.
+               </p>
+<pre class="code-block">
+xf0r3@gogs:~$ sudo apt install mysql-server mysql-client
+</pre>
+               <p>
+                       Następnie pobieramy najnowszą paczkę z Gogs-em z <a href="https://gogs.io/docs/installation/install_from_binary">https://gogs.io/docs/installation/install_from_binary</a>
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ wget https://dl.gogs.io/0.12.1/gogs_0.12.1_linux_amd64.tar.gz
+</pre>
+               <p>
+                       Po pobraniu rozpakowujemy paczkę.
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ tar -xzvf gogs_0.12.1_linux_amd64.tar.gz
+</pre>
+               <p>
+                       W katalogu <em>gogs/scripts</em> będzie plik o nazwie <em>mysql.sql</em>. Otwieramy go i dopisujemy dwie linie.
+               </p>
+<pre class="code-block">
+CREATE USER 'gogs'@'localhost' IDENTIFIED BY 'Trudn3Hasl0DOMysql';
+GRANT ALL ON gogs.* TO 'gogs'@'localhost';
+</pre>
+               <p>
+                       Zapisujemy zmiany w pliku, następnie tworzymy bazę dla Gogs.
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~/gogs/scripts$ sudo mysql &lt; mysql.sql
+</pre>
+               <p>
+                       Teraz tworzymy nowego użytkownika np. o nazwie <em>git</em>. To na jego katalogu domowym będą tworzone repozytoria użytkowników oraz to z jego uprawnieniami będzie uruchamiany Gogs.
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo adduser git
+</pre>
+               <p>
+                       Kopiujemy na jego katalog domowy naszą paczkę z Gogs.
+               </p>
+<pre class="code-block">
+xf0r3@gogs:~$ sudo cp gogs_0.12.1_linux_amd64.tar.gz /home/git
+</pre>
+               <p>
+                       Przechodzimy na jego katalog domowy, albo przez <code class="code-inline">sudo su</code> i następnie <code class="code-inline">su git</code> lub bezpośrednio <code class="code-inline">su git</code>. Tam wypakowujemy naszą paczkę.
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ su git
+Password:
+git@gogs:~$ tar -xzvf gogs_0.12.1_linux_amd64.tar.gz
+</pre>
+               <p>
+                       Teraz możemy uruchomić nasz serwer. <strong>Uwaga! </strong>Jeśli uruchamiamy naszego Gogs-a w środowisku produkcyjnym, to przed pierwszym uruchomieniem serwera należy wykonać czynność opisane poniżej, w przeciwnym wypadku możemy przejść do uruchomienia serwera.
+               </p>
+               <p>
+                       Poniżej przedstawię jak należy skonfigurować <strong>Nginx</strong> jako <strong>reverse proxy</strong>, aby nasz serwer Gogs był widoczny pod konkretnym adresem oraz pod klasycznym portem HTTPS.
+               </p>
+               <p>
+                       Na początku w katalogu <em>/etc/ssl</em> tworzymy katalog o nazwie <em>gogs.</em>
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo mkdir -p /etc/ssl/gogs
+</pre>
+               <p>
+                       Następnie kopiujemy do niego pliki certyfikatu
+               </p>
+<pre class="code-block">
+xf0r3@gogs:~$ sudo cp *.pem /etc/ssl/gogs
+</pre>
+               <p>
+                       Teraz instalujemy <em>nginx</em>.
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo apt install nginx
+</pre>
+               <p>
+                       Po zainstalowaniu pakietu, w katalogu <em>/etc/nginx/sites-enabled</em> tworzymy plik o nazwie <em>gogs</em> następnie w nim wklejmy poniższą konfiguracje.
+               </p>
+<pre class="code-block">
+server {
+    listen 443 ssl;
+    server_name git.example.com;
+               root /var/www/html/system/nginx-root; # Used for acme.sh SSL verification (https://acme.sh)
+
+               location / {
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header Host $http_host;
+        proxy_pass http://127.0.0.1:3000;
+               }
+
+    ssl on;
+    ssl_certificate /etc/ssl/gogs/fullchainX.pem;
+    ssl_certificate_key /etc/ssl/gogs/privkeyX.pem;
+    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+
+    ssl_session_timeout 5m;
+    client_max_body_size 50m;
+}
+</pre>
+               <p>
+                       W pliku zmieniamy:
+               </p>
+               <ul>
+                       <li><strong>server_name</strong> - podajemy nazwę, pod którą Gogs będzie widoczny.</li>
+                       <li><strong>proxy_pass</strong> - podajemy adres oraz port, na którym nasłuchuje główny proces serwera Gogs</li>
+                       <li><strong>ssl_certificate </strong>- podajemy ścieżkę do pliku certyfikatu</li>
+                       <li><strong>ssl_certificate_key</strong> - podajemy ścieżkę do pliku klucza prywatnego certyfikatu.</li>
+               </ul>
+               <p>
+                       Restartujemy nginx:
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo systemctl restart nginx
+</pre>
+               <p>
+                       Sprawdzamy czy serwer wystartował prawidłowo:
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo systemctl status nginx
+</pre>
+               <p>
+                       Jeśli nginx wystartował poprawnie lub uruchamiamy gogs dla celów testowych to możemy, uruchomić serwer a następnie instalacje Gogs, na którą wchodzimy przez adres zdefiniowany w parametrze <code class="code-inline">server_name</code>.
+               </p>
+<pre class="code-block">
+git@gogs:~$ gogs/gogs web
+2020/09/13 08:54:43 [ WARN] Custom config "/home/git/gogs/custom/conf/app.ini" not found. Ignore this warning if you're running for the first time
+2020/09/13 08:54:43 [TRACE] Log mode: Console (Trace)
+2020/09/13 08:54:43 [ INFO] Gogs 0.12.1
+2020/09/13 08:54:43 [TRACE] Work directory: /home/git/gogs
+2020/09/13 08:54:43 [TRACE] Custom path: /home/git/gogs/custom
+2020/09/13 08:54:43 [TRACE] Custom config: /home/git/gogs/custom/conf/app.ini
+2020/09/13 08:54:43 [TRACE] Log path: /home/git/gogs/log
+2020/09/13 08:54:43 [TRACE] Build time: 2020-08-27 07:07:30 UTC
+2020/09/13 08:54:43 [TRACE] Build commit: 43fc8260850090b55d4ee2586a819b3b6c016279
+2020/09/13 08:54:43 [ INFO] Run mode: Development
+2020/09/13 08:54:43 [ INFO] Listen on http://0.0.0.0:3000
+</pre>
+               <p>
+                       Do stworzenia w dużej mierze (90 kilku %) Gogs wykorzystano język programowania Go. Dlatego podobnie do aplikacji stworzonych w Node.js, Gogs startuje na wysokim porcie, aby mógł wystartować na porcie poniżej 1024 musi zostać uruchomiony jako <em>root</em>, co nie jest zalecane. Adres z portem 3000 na końcu przepiszemy do naszej przeglądarki zamiast zer, podstawimy adres naszej maszyny.
+               </p>
+               <p>
+                       Po wpisaniu naszego zmienionego adresu w przeglądarkę, wyświetli nam się strona instalacyjna. Co zmieniamy?
+               </p>
+               <ul>
+                       <li>Hasło MySQL do użytkownika Gogs - musimy podać hasło jakie podaliśmy przy zakładaniu bazy.</li>
+                       <li>Nazwa aplikacji - według uznania. </li>
+                       <li>Domena - podajemy adres IP maszyny (w przypadku środowiska testowego) lub domenę (w przypadku środowiska produkcyjnego).</li>
+                       <li>Adres URL aplikacji - podobnie do domeny (w przypadku środowiska testowego) lub https://git.naszadomena.org (w przypadku środowiska produkcyjnego)</li>
+               </ul>
+               <p>
+                       Po zainstalowaniu zostaniemy przyniesieni nas stronę logowania. <strong>Jednak naszą pracę z Gogs-em zaczniemy od utworzenia konta. Pierwszy zarejestrowany użytkownik dostaje uprawnienia administracyjne.</strong> Pod formularzem logowania znajduje się odnośnik kierujący nas do formularza rejestracji. Wypełniamy wszystkie pola i rejestrujemy użytkownika, po zarejestrowaniu zostaniemy przeniesieni z powrotem na stronę logowania, logujemy się nowo utworzonym użytkownikiem i mamy Gogs-a do dyspozycji.
+               </p>
+               <p>
+                       Powiedzmy że mamy zainstalowany Gogs (w wersji produkcyjnej) i musimy wyłączyć nasz serwer. Po jego ponownym uruchomieniu i próbie połączenia z Gogs otrzymujemy błąd "502 Bad Gateway". Oznacza on mniej więcej tyle że proxy nie ma gdzie przekierować danych ponieważ usługa na podanym przez nas adresie i porcie nie odpowiada. Gogs nie został uruchomiony po starcie systemu. Musimy go uruchomić ręcznie. Jednak uruchamianie Gogs-a po każdym resecie serwera nie jest raczej mile widziane. Współczesne systemy, tak jak w moim przypadku Ubuntu posiadają bardzo zaawansowaną obsługę poziomów uruchomienia systemu jednym z nich jest <strong>systemd</strong>. Za uruchomienie konkretnych usług w danym momencie odpowiadają specjalne skrypty systemd, Gogs w swoich plikach instalacyjnych również posiada taki skrypt.
+               </p>
+               <p>
+                       <strong>
+                       Aby dodać Gogs do autostartu, wystarczy że skopiujemy plik <em>gogs.service</em> z katalogu <em>gogs/scripts/systemd</em> do <em>/etc/systemd/system</em> następnie wydamy polecenie:
+                       </strong>
+               </p>
+<pre class="code-block">
+xf0r3m@gogs:~$ sudo systemctl enable gogs.service
+</pre>
+               <p>
+                       W pliku nie musimy nic zmieniać, ponieważ tak zainstalowaliśmy Gogs-a, że nasze ścieżki do danych Gogs pokrywają się tymi w pliku usługi. To polecenie spowoduje zarejestrowanie nowej usługi na danym poziomie uruchomienia.
+               </p>
+               <p>
+                       Ostatnim pakietem jaki będziemy instalować jest <strong>Gitea</strong>. Jej instalacja jest bardzo podobna do Gogs-a.
+               </p>
+               <p>&nbsp;</p>
+               <h2>Gitea</h2>
+               <p>
+                       A więc <strong>instalacje Gitei rozpoczynamy od zainstalowania na serwerze systemu bazodanowego</strong> może być to MySQL może być to MariaDB lub PostgreSQL.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo apt install mysql-client mysql-server
+</pre>
+               <p>
+                       Następnym krokiem jest stworzenie bazy danych.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo mysql
+mysql&gt; CREATE DATABASE gitea;
+-- ciach --
+mysql&gt; CREATE USER 'gitea'@'localhost' IDENTIFIED BY '2up3rT4jn3H4s|_0';
+-- ciach --
+mysql&gt; GRANT ALL ON gitea.* TO 'gitea'@'localhost';
+</pre>
+               <p>
+                       Kolejną czynnością jest utworzenie użytkownika, z którego uprawnieniami będziemy uruchamiać Giteę. W tym przypadku stworzymy użytkownika systemowego poniższym poleceniem.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo adduser --system --shell /bin/bash --group --disable-password --home /home/git git
+</pre>
+               <p>
+                       Po stworzeniu użytkownika, możemy utworzyć niezbędne dla Gitei katalogi.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo mkdir -p /home/git/{custom,data,log}
+xf0r3m@gitea:~$ sudo chown -R git:git /home/git
+xf0r3m@gitea:~$ sudo chmod -R 750 /home/git
+xf0r3m@gitea:~$ sudo mkdir /etc/gitea
+xf0r3m@gitea:~$ sudo chown root:git /etc/gitea
+xf0r3m@gitea:~$ sudo chmod 770 /etc/gitea
+</pre>
+               <p>
+                       <strong>Po instalacji będziemy, musieli pamiętać o odebraniu uprawnień do zapisu w katalogu <em>/etc/gitea</em> oraz w pliku <em>/etc/gitea/app.ini</em></strong>.
+               </p>
+               <p>
+                       Teraz przelogujemy się na użytkownika git.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo su
+root@gitea:/home/xf0r3m# su git
+</pre>
+               <p>
+                       Bezpośrednio do katalogu domowego ściągamy plik binarny Gitei. Kiedy plik znajdzie się już na serwerze możemy go uruchomić i zainstalować Giteę.
+               </p>
+<pre class="code-block">
+git@gitea:~$ GITEA_WORK_DIR=/home/git ./gitea web -c /etc/gitea/app.ini
+</pre>
+               <p>
+                       Nie musimy przejmować się brakiem pliku <em>/etc/gitea/app.ini</em>. Zostanie on utworzony podczas instalacji. Kiedy nasz serwer wystartuje możemy przejść pod <em>http://&lt;ip_serwera&gt;:3000</em>. Naszym oczom ukaże się strona startowa, podobna do tej, którą znamy z Gogs. Wygląda to trochę jakby nie trzeba było tego instalować, mamy w prawym górnym rogu dwa odnośniki <em>Zaloguj się </em>oraz <em>Zarejestruj się</em>, z racji tego iż musimy zarejestrować pierwszego użytkownika (pierwszy zarejestrowany użytkownik zyskuje uprawnienia administracyjne) <strong>klikamy w odnośnik <em>Zarejestruj sie</em> i wyświetla nam się stroną instalacji, którą już znamy z Gogs</strong>. Uzupełniamy lub zmieniamy te pola, jakie zostały wymienione przy okazji Gogs-a. Po zainstalowaniu zostaniemy przekierowani na stronę logowania, klikamy odnośnik pod przyciskiem aby zarejestrować pierwszego użytkownika. Następnie możemy się już logować.
+               </p>
+               <p>
+                       Dla Gitei również dostępny jest plik usługi po tym adresem <a href="https://github.com/go-gitea/gitea/blob/master/contrib/systemd/gitea.service">https://github.com/go-gitea/gitea/blob/master/contrib/systemd/gitea.service</a>, w którym musimy zmienić parę opcji, m.in. wskazać jakiego systemy bazodanowego użyliśmy, aby wstrzymać uruchamianie Gitei do momentu  uruchomienia bazy danych. Poniżej znajduje się zawartość pliku <em>gitea.service</em> przygotowana dla przedstawionej tutaj instalacji Gitei.
+               </p>
+<pre class="code-block">
+[Unit]
+Description=Gitea (Git with a cup of tea)
+After=syslog.target
+After=network.target
+###
+# Don't forget to add the database service requirements
+###
+#
+Requires=mysql.service
+#Requires=mariadb.service
+#Requires=postgresql.service
+#Requires=memcached.service
+#Requires=redis.service
+#
+###
+# If using socket activation for main http/s
+###
+#
+#After=gitea.main.socket
+#Requires=gitea.main.socket
+#
+###
+# (You can also provide gitea an http fallback and/or ssh socket too)
+#
+# An example of /etc/systemd/system/gitea.main.socket
+###
+##
+## [Unit]
+## Description=Gitea Web Socket
+## PartOf=gitea.service
+##
+## [Socket]
+## Service=gitea.service
+## ListenStream=&lt;some_port&gt;
+## NoDelay=true
+##
+## [Install]
+## WantedBy=sockets.target
+##
+###
+
+[Service]
+# Modify these two values and uncomment them if you have
+# repos with lots of files and get an HTTP error 500 because
+# of that
+###
+#LimitMEMLOCK=infinity
+#LimitNOFILE=65535
+RestartSec=2s
+Type=simple
+User=git
+Group=git
+WorkingDirectory=/home/git
+# If using Unix socket: tells systemd to create the /run/gitea folder, which will contain the gitea.sock file
+# (manually creating /run/gitea doesn't work, because it would not persist across reboots)
+#RuntimeDirectory=gitea
+ExecStart=/home/git/gitea web --config /etc/gitea/app.ini
+Restart=always
+Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/home/git
+# If you want to bind Gitea to a port below 1024, uncomment
+# the two values below, or use socket activation to pass Gitea its ports as above
+###
+#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+#AmbientCapabilities=CAP_NET_BIND_SERVICE
+###
+
+[Install]
+WantedBy=multi-user.target
+</pre>
+               <p>
+                       <strong>Ten plik umieszczamy w katalogi <em>/etc/systemd/system</em></strong> następnie wydajemy polecenie:
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo systemctl enable gitea.service
+</pre>
+               <p>
+                       Jeśli jeszcze tego zrobiśmy to teraz zatrzymamy naszą ręcznie uruchomioną Giteę, naciskając w oknie połaczonego z serwerem terminala <em>Ctrl+c</em>. Następnie wydajemy poniższe polecenia. Te polecenia zmieniają uprawnienia do pliku konfiguracyjnego Gitei.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo chmod 750 /etc/gitea
+xf0r3m@gitea:~$ sudo chmod 640 /etc/gitea/app.ini
+</pre>
+               <p>
+                       Na końcu możemy uruchomić naszą usługę z Giteą.
+               </p>
+<pre class="code-block">
+xf0r3m@gitea:~$ sudo systemctl start gitea.service
+</pre>
+               <p>
+                       Jeśli chcemy Giteę uruchomić w środowisku produkcyjnym, to przydałby się HTTPS. <em>Reverse proxy</em> dla Gitei uruchomiamy identycznie jak dla Gogs. Nawet możemy użyć tego samego pliku konfiguracyjnego.
+               </p>
+               <p>&nbsp;</p>
+               <h2>Podsumowanie</h2>
+               <p>
+                       Pomiędzy tymi trzema, który wybrać. Osobiście jeśli potrzebujemy na wczoraj skonfigurować ogólnodostępnego prostego zdalnego Gita, to wybrał bym Gogsa. Instaluje się go szybko i bez wiekszych problemów, prawdopodbnie zawiera wszystko co potrzeba.
+               </p>
+               <p>
+                       Jeśli jesteśmy na prawdę dużymi leniami, lub nie dysponujemy żadną mocą obliczeniową, którą możemy swobodnie zarządzać z Internetu, to czwartą opcją najmniej bolesną pozostaje konto na <strong>GitHub</strong>.
+               </p>
+               <p>
+                       ~xf0r3m
+               </p>
+       </div>
+<p class="footer">
+2021; COPYLEFT; ALL RIGHTS REVERSED
+</p>
+               </body>
+       </html>
diff --git a/articles/terminallog/Linux.Podstawy.html b/articles/terminallog/Linux.Podstawy.html
new file mode 100644 (file)
index 0000000..9b0d34d
--- /dev/null
@@ -0,0 +1,8065 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <style>
+                               .code-block {
+                                       display: block;
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                                       text-align: left;
+                               }
+                               .code-inline {
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+        p { text-align: justify; }
+        .toc { list-style-type: none; }
+                       </style>
+               </head>
+               <body style="font-family: monospace;" >
+<pre>
+    __    _                       ____            __     __                      
+   / /   (_)___  __  ___  __     / __ \____  ____/ /____/ /_____ __      ____  __
+  / /   / / __ \/ / / / |/_/    / /_/ / __ \/ __  / ___/ __/ __ `/ | /| / / / / /
+ / /___/ / / / / /_/ />  <_    / ____/ /_/ / /_/ (__  ) /_/ /_/ /| |/ |/ / /_/ / 
+/_____/_/_/ /_/\__,_/_/|_(_)  /_/    \____/\__,_/____/\__/\__,_/ |__/|__/\__, (_)
+                                                                        /____/   
+
+</pre>
+<p style="margin: 0; padding: 0; outline: 0; font-size: 18pt;">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+                       <div style="margin-left: auto; margin-right: auto; width: 80%;">
+        <h1>Linux. Podstawy.</h1>
+        <div>
+          <h2>Spis treści</h2>
+          <ul class="toc">
+            <li><a href="#1.howlinuxismade">1. Budowa systemu Linux<a>
+              <ul class="toc">
+                <li><a href="#1.1.hardware">1.1. Sprzęt</a>
+                  <ul class="toc">
+                    <li><a href="#1.1.1.ram">1.1.1. Pamięć operacyjna</a>
+                  </ul>
+                </li>
+                <li><a href="#1.2.kernel">1.2. Jądro</a>
+                <li><a href="#1.3.userspace">1.3. Przestrzeń użytkownika</a>
+                <li><a href="#1.4.users">1.4. Użytkownicy</a>
+              </ul></li>
+              <li><a href="#2.linuxbasics">2. Podstawy obsługi Linuksa</a>
+                <ul class="toc">
+                  <li><a href="#2.1.shells">2.1. Powłoka</a></li>
+                  <li><a href="#2.2.shellusage">2.2. Korzystanie z powłoki</a>
+                    <ul class="toc">
+                      <li><a href="#2.2.1.catcommand">2.2.1. Polecenie cat</a></li>
+                      <li><a href="#2.2.2.stdinstdout">2.2.2. Standardowe wejście i standardowe wyjście</a></li>
+                    </ul></li>
+                  <li><a href="#2.3.basicscommands">2.3. Podstawowe polecenia</a></li>
+                  <li><a href="#2.4.commandsworksondir">2.4. Polecenia działające na katalogach</a>
+                    <ul class="toc">
+                      <li><a href="#2.4.1.globbing">2.4.1. Nazwy wieloznaczne</a></li>
+                    </ul></li>
+                  <li><a href="#2.5.proxycommands">2.5. Polecenia pośredniczące</a></li>
+                  <li><a href="#2.6.passwdandchsh">2.6. Zmiana hasła i powłoki</a></li>
+                  <li><a href="#2.7.dotfiles">2.7. Plik z kropką</a></li>
+                  <li><a href="#2.8.shellandenvvars">2.8. Zmienne środowiskowe i powłoki</a></li>
+                  <li><a href="#2.9.path">2,9, Ścieżka poleceń</a></li>
+                  <li><a href="#2.10.specialchars">2.10. Znaki specjalne</a></li>
+                  <li><a href="#2.11.commadlineedit">2.11. Edycja wiersza poleceń</a></li>
+                  <li><a href="#2.12.texteditors">2.12. Edytory tekstu</a></li>
+                  <li><a href="#2.13.gettinghelp">2.13. Uzyskiwanie pomocy</a></li>
+                  <li><a href="#2.14.shellio">2.14. Wejście i wyjście powłoki</a>
+                    <ul class="toc">
+                      <li><a href="#2.14.1.stderr">2.14.1. Standardowy strumień błędów</a></li>
+                      <li><a href="#2.14.2.stdin">2.14.2. Przekierowanie standardowego wejścia</a></li>
+                    </ul></li>
+                  <li><a href="#2.15.readingerrors">2.15. Odczytwanie komunikatów o błędach</a></li>
+                  <li><a href="#2.16.manipulatingprocesses">2.16. Przeglądanie procesów i manipulowanie nimi</a>
+                    <ul class="toc">
+                      <li><a href="#2.16.1.processkilling">2.16.1. Przerywanie działania procesów</a></li>
+                      <li><a href="#2.16.2.jobcontrol">2.16.2. Kontrola zadań</a></li>
+                      <li><a href="#2.16.3.processinbg">2.16.3. Procesy działające w tle</a></li>
+                    </ul></li>
+                  <li><a href="#2.17.filemodeandpermissions">2.17. Tryb pliku i uprawnienia</a>
+                    <ul class="toc">
+                      <li><a href="#2.17.1.modifypermissions">2.17.1. Modyfikacja uprawnień</a></li>
+                      <li><a href="#2.17.2.sylinks">2.17.2. Dowiązania symboliczne</a></li> 
+                    </ul></li>
+                  <li><a href="#2.18.archvesandcompression">2.18. Archiwizowanie i kompresowanie danych</a>
+                    <ul class="toc">
+                      <li><a href="#2.18.1.tarprogram">2.18.1. Program tar</a></li>
+                      <li><a href="#2.18.2.gzipprogram">2.18.2. Program gzip</a></li>
+                      <li><a href="#2.18.3.compressedarchives">2.18.3. Skompresowane archiwa</a></li>
+                      <li><a href="#2.18.4.othercommpression">2.18.4. Inne metody kompresji</a></li>
+                    </ul></li>
+                  <li><a href="#2.19.filesystemhierarchy">2.19. Hierarchia katalogów</a>
+                    <ul class="toc">
+                      <li><a href="#2.19.1.othermainsubdirs">2.19.1. Pozostałe katalogi główne</a></li>
+                      <li><a href="#2.19.2.usrdirectory">2.19.2. Katalog /usr</a></li>
+                      <li><a href="#2.19.3.kernelplace">2.19.3. Umiejscowienie jądra w systemie</a></li>
+                    </ul></li>
+                  <li><a href="#2.20.runitasroot">2.20. Uruchamianie poleceń przez superużytkownika</a>
+                    <ul class="toc">
+                      <li><a href="#2.20.1.sudoersfile">2.20.1. Plik /etc/sudoers</a></li>
+                    </ul></li>
+                  <li><a href="#2.21.summary">2.21. Podsumowanie</a></li>
+                </ul></li>
+              <li><a href="#3.devices">3. Urządzenia</a>
+                <ul class="toc">
+                  <li><a href="#3.1.devicefiles">3.1. Pliki urządzeń</a>
+                  <li><a href="#3.2.sysfsdevicepath">3.2. Ścieżka urządzeń sysfs</a></li>
+                  <li><a href="#3.3.ddcommand">3.3. Polecenie dd</a></li>
+                  <li><a href="#3.4.namingsummary">3.4. Podsumowanie nazewnictwa urządzeń</a>
+                    <ul class="toc">
+                      <li><a href="#3.4.1.makedev">3.4.1. Tworzenie plików urządzeń</a></li>  
+                    </ul></li>
+                  <li><a href="#3.5.udev">3.5. System udev></a>
+                    <ul class="toc">
+                      <li><a href=#3.5.1.devtmpfs">3.5.1. System plików devtmpfs</a></li>
+                    </ul></li>
+                </ul></li>
+              <li><a href="#4.disksandfs">4. Dyski i systemy plików</a>
+                <ul class="toc">
+                  <li><a href="4.1.paritioning">4.1. Partycjonowanie</a>
+                    <ul class="toc">
+                      <li><a href="4.1.1.listingpartitiontable">4.1.1. Przeglądanie tablicy
+                        partycji</a></li>
+                      <li><a href="4.1.2.modifypartition">4.1.2. Modyfikowanie tablicy partycji</a></li>
+                    </ul></li>
+                  <li><a href="4.2.filesystems">4.2. Systemy plików</a>
+                    <ul class="toc">
+                      <li><a href="#4.2.1.fstypes">4.2.1. Typy systemów plików</a></li>
+                      <li><a href="#4.2.2.createfs">4.2.2. Tworzenie systemów plików</a></li>
+                      <li><a href="#4.2.3.mountfs">4.2.3. Montowanie systemów plików</a></li>
+                      <li><a href="#4.2.4.uuid">4.2.4. Identyfikator UUID systemu plików</a></li>
+                      <li><a href="#4.2.5.diskcache">4.2.5. Buforowanie dysku i systemu pliku</a></li>
+                      <li><a href="#4.2.6.mountoptions">4.2.6. Opcje montowania</a></li>
+                      <li><a href="#4.2.7.remount">4.2.7. Ponowne montowanie systemu plików</a></li>
+                      <li><a href="#4.2.8.fstabfile">4.2.8. Tablica systemów plików /etc/fstab</a></li>
+                      <li><a href="#4.2.9.fscapacity">4.2.9. Pojemność systemu plików</a></li>
+                      <li><a href="#4.2.10.fsrescue">4.2.10. Sprawdzenie i naprawianie systemu plików</a></li>
+                      <li><a href="#4.2.11.specialfs">4.2.11. Systemy plików o specjalnym znaczeniu</a></li>
+                    </ul></li>
+                  <li><a href="#4.3.swapspace">4.3. Przestrzeń wymiany</a>
+                    <ul class="toc">
+                      <li><a href="#4.3.1.swappartition">4.3.1. Wykorzystanie partycji jako przestrzeni wymiany.</a></li>
+                      <li><a href="#4.3.2.swapfile">4.3.2. Wykorzystanie pliku jako przestrzeni wymiany</a></li>
+                      <li><a href="#4.3.3.swapsize">4,3,3, Jak dużej przestrzeni wymiany potrzebuje</a></li>
+                    </ul></li>
+                  <li><a href="#4.4.fsfuture">4.4. Przyszłość systemów plików</a></li>
+                </ul></li>
+            <li><a href="#5.startingkernel">5. Uruchamianie jądra Linux</a>
+              <ul class="toc">
+                <li><a href="#5.1.dmesg">5.1. Komunikaty rozruchowe</a></li>
+                <li><a href="#5.2.kernelinitandbootoptions">5.2. Inicjowanie jądra i opcje rozruchu</a></li>
+                <li><a href="#5.3.kernelparameters">5.3. Parametry jądra</a></li>
+                <li><a href="#5.4.bootloaders">5.4. Programy rozruchowe</a></li>
+                <li><a href="#5.5.practicalusagegrub">5.5. Praktyczne użytcie programu rozruchowego GRUB</a>
+                  <ul class="toc">
+                    <li><a href="#5.5.1.firstcontactwithgrub">5.5.1. Pierwszym kontakt z GRUB</a></li>
+                    <li><a href="#5.5.2.grubinstallationinbiosmode">5.5.2. Instalacja GRUB w trybie BIOS</a></li>
+                    <li><a href="#5.5.3.grubinstallationinefimode">5.5.3. Instalacja GRUB w trybie UEFI</a></li>
+                    <li><a href="#5.5.4.changegruborder">5.5.4. Zmiana kolejności w menu GRUB</a></li>
+                  </ul></li>
+                <li><a href="#5.6.usagerefindasbootmanager">5.6. Wykorzystanie rEFInd jako menedżer rozruchu.</a></li>
+              </ul></li>
+            <li><a href="#6.startinguserspace">6. Uruchamianie przestrzeni użytkownika</a>
+              <ul class="toc">
+                <li><a href="#6.1.initprocess">6.1. Proces init</a></li>
+                <li><a href="#6.2.runlevels">6.2. Poziomy uruchomienia</a></li>
+                <li><a href="#6.3.initidentify">6.3. Rozpoznawanie programu typu init</a></li>
+                <li><a href="#6.4.introductiontochoosedinitprograms">6.4. Wprowadzenie do wybranych programów typu init</a>
+                  <ul class="toc">
+                    <li><a href="#6.4.1.systemd">6.4.1. Systemd</a></li>
+                    <li><a href="#6.4.2.sysvinit">6.4.2. Proces typu init w stylu System V</a></li>
+                  </ul></li>
+                <li><a href="#6.5.shutdownthesystem">6.5. Wyłączenie systemu</a></li>
+                <li><a href="#6.6.initramfs">6.6. Początkowy system plików w pamięci RAM</a></li>
+                <li><a href="#6.7.oneusermode">6.7. Tryb jednego użytkownika</a></li> 
+              </ul></li>
+          </ul>
+        </div>
+        <p>
+          Opisywany tutaj materiał będzie kompatybilny z dystrybucjami 
+          pochodnymi od GNU/Linux Debian zarówno tymi opartymi na 
+          <em>systemd</em> jak <em>sysvinit</em> oraz tymi z rodziny
+          <em>RHEL</em>/<em>Fedora</em>/<em>CentOS</em>. 
+        </p>
+        <p>
+          GNU/Linux czy raczej sam Linux? Sama nazwa, jest już tematem dość
+          kontrowersyjnym. Ludzie związani z projektem GNU twierdzą, że ta
+          pierwsza liczba jest właściwa ponieważ wskazuje ona na to, że isotne
+          elemnty projektu GNU zostały wykorzystane do stworzenia tego systemu.
+          W mowie potocznej jednak przyjęło się użycie tej drugiej nazwy. Jest
+          to jedno, łatwe do zapamiętania słowo. Jeśli mówimy następujące
+          zdanie wyrażające chęć zainstalowania na jakiejś maszynie omawianego
+          tutaj systemu, mówimy że "zainstalujemy jakiegoś Linuksa". Słowo
+          "jakiegoś" zostało tu użyte w kontekscie wyboru konkretnej
+          dystrybucji. Co to dystrybucja wyjaśnie za chwilę. Bez projektu GNU
+          niebyło by Linuksa. Wydaje mi się, że każdy kto jest nieco bardziej
+          związany z tym środowiskiem o tym wie. Ja również jestem tego świadom
+          dla tego też w tym dokumencie użyje nazwy Linux. Poprostu.
+        </p>
+        <h1 id="1.howlinuxismade">1. Budowa systemu Linux</h1>
+        <p>
+          Nie zagłebiając się w szczegóły, to Linux składa się z 
+          <strong>jądra</strong> oraz
+          <strong>przestrzeni użytkownika</strong>. Oba kompomenty rezydują w 
+          pamięci więc
+          wiele, nie które teksty popularno-naukowe mogą włączać pamięć lub
+          ogólnie sprzęt do składowych systemu operacyjnego Linux, w mojej
+          opinii jest raczej cecha wykorzystywanych przez nas komputerów
+          konwencjonalnych. 
+        </p>
+        <p>
+          Mówiąc o jądrze możemy wskazać konktretny program, konkretny plik.
+          W przypadku przestrzeni użytkownika, w systemie nie istnieje żaden
+          namacalny byt cyfrowy jak w przypadku jądra. Przestrzeń użytkownika
+          jest bowiem <strong>warstwą abstrakcji</strong> - czyli terminem,
+          bądź założeniem wykorzystywanym w celu określenia czynności, funkcji,
+          zjawiska bez wdawania się w szczegóły. Przestrzeń użytkownika jest
+          miejscem uruchamiania <strong>procesów</strong> użytkownika. Procesy
+          to nic innego jak wystąpienia programów uruchomionych przez
+          użytkownika. Nie wszystkie procesy są programami użytkownika w
+          dosłownym tych słów znaczeniu. Część tych procesów to programy
+          wspomagające wykorzystanie komputera i jego zasobów. Bez nich systemy
+          operacyjne dalej mogły by spełniać swoją rolę, jednak nie miały by
+          powszechnie znanej nam dzisiaj formy. Przestrzeń użytkownika  składa 
+          się z wielu ogólno dostępnych kompnentów ich istnienie w danej wersji
+          systemu oraz ich konfiguracja sprawia, iż nie mamy doczynienia z
+          gotowym jednolitym produktem, ale z dystrybucją. Z jedną z wersji, 
+          gdzie ktoś
+          wziął jądro, które jest ogolno dostępne i skomponował przestrzeń
+          użytkownika. Obecnie na rynku mamy dostępnych ok. 600 dystrybucji.
+          Wiekszość z nich to pochodne innych, oryginalnych rozwiązań
+          rozwijanych przez setki osób na całym świecie. Kilka takich głównych
+          dystrybucji, znajduje się w tabeli poniżej. Przejrzałem większość z
+          nich, a z częsci osobiście korzystałem. 
+        </p>
+        <table border="1">
+          <thead>
+            <th>Logo</th>
+            <th>Nazwa</th>
+            <th>Opis</th>
+          </thead>
+          <tbody>
+            <tr>
+              <td><img src="https://i.ibb.co/GspTqqK/linux-mint-logo32.png" alt="linux-mint-logo32" border="0"></td>
+              <td>Linux Mint</td>
+              <td>
+                Dystrybucja bardzo przyjazna użytkownikowi. Wykorzystywana 
+                przez nowych niedoświadczonych użytkowników system Linux. 
+                Pod czas
+                instalacji mogą być instalowane nie wolne moduły oraz nie
+                wolne oprogramownie. Jej głównym zadaniem jest sprzyjanie
+                użytkownikowi i umożliwienie mu wykorzystanie Linuksa przy
+                codziennym wykorzystaniu komputera. Mint rozwijany jest przez
+                społeczność zebraną wokół niego.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/ckrkfjX/ubuntu-logo32.png" alt="ubuntu-logo32" border="0"></td>
+              <td>Ubuntu</td>
+              <td>
+                  Podobnie jak Linux Mint, Ubuntu również jest skierowane dla
+                  osób ceniących sobie wygodne i prostę rozwiązania. Jest
+                  przyjazna użytkownikowi, ma nieco bardziej konserwatywne
+                  podejście do ideii wolnego oprogramowania, jądro może
+                  zawierać nie wolne moduły, jednak zamknięte oprogramowanie
+                  nie jest domyślnie instalowane. Ubuntu rozwijane jest przez 
+                  firmę
+                  Canonical. Jej technologię są wdrażane do Ubuntu, dzięki
+                  czemu może ona uchdzić za system klasy <em>enterprise</em> 
+                  wśród
+                  dystrybucji opartych o GNU/Linux Debian. Poza wersją na
+                  komputery biurkowe istnieją również wersja skierowana
+                  na serwery oraz inne wersje z preinstalowanymi różnymi
+                  środowiskami graficznymi czy wersja skierowana do obróbki
+                  multimediów zawierająca pozwalające do tego oprogramowanie.
+                  Społeczność zebrana
+                  wokół systemu Linux zarzuca jej siłowe próby wdrożenia
+                  manedżera oprogramowania <em>Snap</em>, rozwijanego przez tę 
+                  firmę
+                  przez co może ona pretendować do stopniowego zarzucenia
+                  klasycznego schematu dystrybucji pakietów rozwijanego wraz
+                  z GNU/Linux Debian.
+              </td> 
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/v4026kk/fedora-logo32.png" alt="fedora-logo32" border="0"></td>
+              <td>Fedora Linux</td>
+              <td>
+                  Fedora jest dystrybucją skierowaną do różnej maści
+                  użytkowników, ponieważ istnieje w kilku głównych wersjach.
+                  oraz wiele wersji pobocznych tzw. <em>spins</em>. Fedora ma
+                  najprzyjźniejszy instalator chyba ze wszystkich możliwych
+                  dystrybucji. Wymaga on głównie wybrania miejsca instalacji
+                  i kliknięcia przycisku dalej. Fedora została stworzona i jest
+                  rozwiajana przez firme Red Hat Inc. (obecnie IBM) jako
+                  <em>upstream</em> (poligon doświadczalny dla zmian), dla 
+                  glównego produktu tej firmy Red Hat Enterprise Linux - 
+                  płatnej dystrybucji skierowanej do środowisk produkcyjnych 
+                  (100$ rocznie). Jest to system o dużej stabilości ze
+                  wsparciem dla najnowszego sprzetu. Fedora również
+                  charakteryzuje się wprowadzeniej jako pierwsza środowiska
+                  GNOME w najnowszej wersji 41 oraz innych nowych technologi
+                  wśród otwartego oraz wolnego oprogramowania. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/Q965txs/debian-logo32.png" alt="debian-logo32" border="0"></td>
+              <td>GNU/Linux Debian</td>
+              <td>
+                  Debian jest jedną z pierwszy dostępnych dystrybucji, początek
+                  jej istnienia jest datowany na 1993 rok. Dystrybucja 
+                  konserwatywna, posiadała w pierwszych latach swojego 
+                  istnienia aprobatę FSF (Free Software Fundation). Jednak
+                  została ona wycofana, za zezwolenie na instalację zamkniętego
+                  oprogramowania. Kernel przygotowywany przez twórców tej
+                  dystrybucji pozbawiony jest tzw. blobów binarnych (nie
+                  wolnych prekompilowanych modułów, używanych przy budowaniu
+                  jądra.) Bloby najczęściej dotyczą sterowników sprzętu.
+                  Dystrybucja charkteryzuje się wysoką stabilnościa
+                  porównywalną z RHEL, wsparciem dla starszego sprzętu. Jedną
+                  z cech, która może odstraszać potencjalnych użytkowników
+                  od niej jest długi cykl wydawniczy (co dwa lata) oraz
+                  używanie sprawdzone oprogramowania czy technologii (pozostaje
+                  dość mocno w tyle jeśli chodzi o najnowsze wersje
+                  oprogramowania). Wydaje mi się, że niema
+                  stabilniejszego gotowego rozwiązania niż GNU/Linux Debian.
+                  Debian wymaga nieco większego zaawansowania niż dystrybucje
+                  podane do tej pory. Stosowany jest częściej w środowiskach
+                  produkcyjnych niż np. Ubuntu. Rozwój Debiana opiera się
+                  na zaangażowaniu społeczności z całego świata.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/MpCcKqy/arch-linux-logo32.png" alt="arch-linux-logo32" border="0"></td>
+              <td>Arch Linux</td>
+              <td>
+                  Dystrybucja skierowana do zaawansowanych użytkowników.
+                  Charakteryzuje się wysoką konfigurowalnością oraz
+                  dostępnością najnowszych wersji oprogramowania. Nie posiada
+                  oficjalnego instalatora, choć można pobrać skrypt z sieci.
+                  Instalacji dokonuj się ręcznie, wpisującac kolejne polecenia
+                  z podręcznika instalacji w środowisku LiveCD, gdzie
+                  przygotowuje się dysk, pobiera się pakiety i je konfiguruje.
+                  Instalacja i konfiguracji Arch Linux nie jest tak
+                  pracochłonna jak innych dystrybucji, można by powiedzieć,
+                  meta-dystrybucji. Dość ciekawą cechą jest społeczność zebrana
+                  wokół niej, która przechwalająca się swoją wyższością na
+                  innymi (ponieważ przebrneli przez proces instalacji) 
+                  używając frazy "I use Arch BTW.". Dystrybucja rozwijana
+                  jest przez społeczność na całym świecie.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/vz98yMx/void-linux-logo32.png" alt="void-linux-logo32" border="0"></td>
+              <td>Void Linux</td>
+              <td>
+                  Nie zależna dystrybucjna, trochę odmienna od inny dystrybucji
+                  głównego nurtu. Systemd zastąpiono programem <em>runit</em>,
+                  zamiast OpenSSL, użyto projektu OpenBSD LibreSSL jak jedyna
+                  z dystrybucji Linuksa. Kernel Void-a pozbawiony jest blobów,
+                  a domyślna instalacja zawiera tylko wolne oprogramowanie,
+                  posiada on jednak oficjalne repozytorium z zamkniętym
+                  oprogramowaniem. Instalacja pakietów opiera się stworzonym
+                  dla Void menedżerze pakietów XBPS. Pakiety są wydawane stylu
+                  <em>rolling release</em>, co daje szybkie i stabline
+                  aktualizacje. Obok standardowej biblioteki języka C -
+                  GNU libc, mamy również bibliotekę <em>musl</em>. Za pomoca
+                  programu <em>xbps-src</em> możemy tworzyć z kodu źródłowego
+                  własne pakiety XBPS. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/0QsPfPh/gentoo-linux-logo32.png" alt="gentoo-linux-logo32" border="0"></td>
+              <td>Gentoo Linux</td>
+              <td>
+                  Gentoo jest dystybucją na tyle zaawansowaną, że można by się
+                  pokusić o nazwanie jej meta-dystrybucją. Jest ona bowiem
+                  jedną z najbardziej konfigurowalnych dystrybucji. Jedną z
+                  ciekawszych czynności, jakie należy wykonać podczas
+                  instalacji, to ręczna kompliacja jądra. Dystrybucja
+                  skierowana do jeszcze bardziej zaawansowanych użytkowników
+                  niż w przypadku Arch Linux. Instalacja Gentoo na maszynie
+                  wirtualnej wraz z poradnikiem, zajeło mi to jakieś dwie
+                  godziny. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/hKwFYQh/lfs-logo32.jpg" alt="lfs-logo32" border="0"></td>
+              <td>Linux from scratch</td>
+              <td>
+                  LFS to w zasadzie projekt, a niżejli sama dystrybucja.
+                  Umożliwia on stworzenie oraz skonfigurowanie własnej
+                  dystrybucji. Na stronie projektu zawarte są wskazówki, co
+                  należy zrobić, aby stworzyć rozwiązanie najbardziej
+                  elastyczne dla siebie. LFS z pewnością może nosić miano
+                  meta dystrybucji.
+              </td>
+            </tr>
+          </tbody>
+        </table> 
+        <p>
+          W powyższej tabeli przedstawiłem  dystrybucje, na które
+          warto zwrócić uwagę. Teraz prawdopodobnie czekać będzie Cię duży
+          dylemat, którą wybrać. W pierwszej kolejności ważny jest sprzęt,
+          na którym będziemy z tego systemu korzystać. Część sprzętu, 
+          z którego chcemy korzystać może 
+          nie działać <em>out of box</em>, wowczas potrzebne będą sterowniki,
+          które mogą być własnościowe (nie wolne, generalnie być zamkniętym 
+          oprogramowaniem), jeśli zależy nam na prywatności, to lepiej upewnić
+          się z jakiego rodzaju sprzętem będzie mieć doczynienia, ponieważ 
+          każde zamknięte oprogramowanie można teoretycznie uznać za
+          oprogramowanie szkodliwe. Dobrym wyborem może być zakup Thinkpada z
+          przed 2008 roku. Wówczas będziemy mogli bez obaw wybrać Debiana i
+          zainstalować np. XFCE (to dość lekkie środowisko graficzne, nadające
+          się do codziennej pracy, bez zniechęcania się). Kolejną rzeczą do
+          wyboru dystrybucji jest zapał do pracy. Mimo iż opisując dystrybucje
+          napisałem że ta jest dla początkujących, a ta dla zaawansowanych to 
+          żadna z
+          nich nie jest ani dla jednych ani dla drugich. Obsługa czego kolwiek
+          związanego z komputerami wymaga przeczytania dokumentacji ze
+          zrozumieniem i umiejętności radzenie sobie z ewentualnymi problemami.
+          Dlatego dlaczego by nie wybrać Gentoo, zainstalować go 
+          z poradnikiem, skonfigurować, a wrazie problemów użyć Googla, lub
+          poprość kogoś ze społeczności o pomoc.  
+        </p>
+        <p>
+          Dość częstym zjawiskiem, wśród społeczności użytkowników Linuksa jest
+          tzw. <em>distro-hopping</em>, czyli przesiadanie się z jednej
+          dystrybucji na drugą. Jest to normalne zjawisko, chciaż można
+          powszechną opinia jego jest raczej negatywna, głównym argumentem
+          oponetów jest stwierdzenie, że przez to nie uczymy się niczego. Moim
+          zdaniem, możemy dojść do wniosku, że tak naprawdę nie ma dystrybucji
+          tylko produkt w ciągłej ewolucji z dostępnym takim a takim
+          oprogramowaniem. Nie mam mendżera pakietów, mam program do instalacji
+          i konfiguracji oprogramowania, nieważne czy jest apt, dnf, yum czy
+          pacman. Mam stronę podręcznika i znajduj sobie potrzebne opcje. Mam
+          dostęp do internetu, i wystarczy wyszukać konkretną potrzebną 
+          czynność np.: "Remove packages with all dependencies pacman". I mam
+          gotowy wynik. Wiele miesięcy błądziłem słuchając mendrców jak RMS
+          (<em>Richard Matthew Stallman</em>). Myślcie samodzielnie, 
+          przeskakujcie z distro na distro i bawcię się dobrze.
+        </p>
+        <h2 id="1.1.hardware">1.1. Sprzęt</h2>
+        <p>
+          Sprzęt sam w sobie nie mozę wchodzić z skład systemu operacyjnego,
+          to jego elementy jak pamieć operacyjna, procesor czy pamięć masowa
+          odgrywają w nim bardzo ważna rolę.
+        </p>
+        <h3 id="1.1.1.ram">1.1.1. Pamięć operacyjna</h3>
+        <p>
+          W działaniu systemów operacyjnych takich jak Linux, najważniejszym
+          komponentem sprzętowym może być pamięć operacyjna, ponieważ to w
+          niej rezyduje jądro oraz przestrzeń użytkownika. Dane zapisane w
+          pamięci nie są niczym innym jak zbiorem zer i jedynek określanych
+          mianem <strong>bitów</strong> (najmniejsze przetwarzanej ilości
+          informacji). Procesy oraz jądro są jednymi z takich zbiorów. Takie
+          zbiory określa się mianem <strong>obrazu</strong>. 
+        </p>
+        <h2 id="1.2.kernel">1.2. Jądro</h2>
+        <p>
+          Jądro Linux jest to nadrzędy proces w całym systemie, realizuje swoje
+          działania w czterech obszarch funkcjonalności systemu operacyjnego.
+        </p>
+        <ul>
+          <li><strong>Zarządzanie procesami</strong> - jądro jest
+            odpowiedzialne za uruchamianie, wstrzymywanie, ponowne uruchomienie
+            oraz kończenie pracy procesów. Korzystając ze współczesnych
+            systemów operacyjnych możemy mieć wrażenie uruchomione przez nas
+            programy (a co za tym idzie ich procesy) mogą działać jednocześnie.
+            Dzieje się tak dlatego, iż jądro uruchamia kod procesu na ułamek
+            sekundy, po upłynięciu danego przez jądro <strong>wycinka czasu</strong>
+            stan procesora wykonującego kod danego procesu zapisywany jest
+            w pamięci, a jądro wybiera kolejny proces i ładuje stan procesora
+            po czym wznawia jego wykonanie. Tych czynności jest znacznie więcej
+            zostało tu wymionionych. Te
+            czynności nazywane są <strong>przełączaniem kontekstu</strong>.
+            Na współczesnych procesorach dzieje się to tak szybko, że możemy
+            mieć złudzenie <strong>wielozadaniowości</strong>. W przypadku 
+            maszyn wielordzeniowych jak i wieloprocesorowych jądro nie musi
+            zwalniać wykorzystywanego procesora (rdzenia), ale robi to aby
+            jak najlepiej wykorzystać zasoby.</li>
+          <li><strong>Zarządzanie pamięcią</strong> - każdy proces jest obrazem
+            w pamięci, każdy proces również potrzebuje pamięci na swoje
+            obliczenia. Zadaniem jądra jest przydzielanie, zwalnianie jak i
+            ochrona (przed tym aby proces nie uzyskał dostępu do obszaru
+            innego procesu) przekazanych procesom obszarów. Czynności z tym
+            związane są dość złożone, ale jądro może posiłkować się 
+            rozszerzenim MMU we współczesnych procesorach. Pozwala ono podczas
+            dzielenia pamięci wykorzystać metodę <strong>pamięci wirtualnej</strong>,
+            polegającej na zamianie adresów pamięci, przez co proces jest
+            skonfigurowany, że "tak jakby" miał do dyspozycji całą pamięć
+            fizyczną maszyny. Zamiana adresów wiąże się z potrzebą posiadania
+            map (czy też tabel), pozwalających na odzorowanie adresów, co
+            dokłada czynność aktualizacji mapy podczas przełączania kontekstu.
+            Mapy adresów nazywane są <strong>tablicami stron</strong>.
+          <li><strong>Sterowniki urządzeń</strong> - zadaniem sterowników
+            jest dostarczenie identycznego interfejsu do komunikacji z
+            poszczególnymi urządzeniami zainstalowanymi w komputerze. Za racji
+            to iż swobodny dostęp do sprzetu jest potencjalnie niebezpieczny,
+            to jaka kolwiek próba komunikacji z urządzeniem odbywać się
+            zawsze będzie za pośrednictwem jądra systemu. Sterowniki w systemie
+            Linux są częścią jądra, nie oznacza to jednak, że nie możemy
+            jakiegoś brakującego do instalować. Sterowniki są przechowywane w
+            postaci modułów, które są ładowane podczas uruchamiania jądra, a
+            nie które znich mogą być ładowane podczas pracy systemu.</li>
+          <li><strong>Wywołania systemowe</strong> - są to funkcje udostępnione
+            przez jądro procesom użytkownika. Wywołania realizują zadania,
+            które są trudne do zrealizowania przez procesy użytkownika lub w
+            ogóle nie wykonalne. Przykładem wykonywania wywołań systemowych
+            jest obsługa plików (otwieranie, odczyt czy zapis), innymi
+            bardzo często wykorzystywanymi wywołaniami są <em>fork()</em> oraz
+            <em>exec()</em>, wykonywane są za każdym wydanym poleceniem w
+            powłoce.</li> 
+        </ul>
+        <p>
+          Inną ciekawą cechą jądra są <strong>pseudourządzenia</strong>.
+          Procesy widzą takie urządenia jak każde inne, jednak występują on
+          wyłącznie w warstwie programowej, dzięki temu nie muszą być częścią
+          jądra, ale ze względów praktycznych się je tam umieszcza. Inna
+          implementacja urządzenia <em>/dev/random</em> - służacego
+          do generowania liczb pseudolosowych, które jest urządzeniem 
+          programowym mogłoby nie być zbyt bezpieczne.
+        </p>
+        <h2 id="1.3.userspace">1.3. Przestrzeń użytkownika</h2>
+        <p>
+          Przestrzeń użytkownika formalnie jest obszarem pamięci, w którym
+          spedzimy 99% czasu pracy na Linuksie. Wewnątrz przestrzeni
+          użytkownika znajdują się procesy definiujące dystrybucje wykonujące
+          różne zadania dla użytkownika, teoretycznie są one wobec siebie
+          równe, to jednak przestrzeń użytkownika można podzielić na trzy
+          warstwy, na której warstwie będzie znajdować się proces zależy jak
+          bardzo skomplikowane zadania wykonuje. Przeglądarka sieci WWW, może
+          się taka nie wydawać ale to potężny subsystem więc będzie znajdować
+          na najwyższej warstwie, z kolei proces służący za rejestrowanie
+          logów, tzw. protokół diagnostyczne będzie znajdować się na najniższej
+          warstwie blisko jądra, ponieważ nie jest on zbyt skomplikowany w
+          porównaniu do na przykład przeglądarki, warstwa środkowa
+          zarezerowana jest dla różnej maści serwerów. Najproście rzecz ujmując
+          podstawowe usługi znajdują się na najniższej warstwie, usługi
+          pomocnicze na warstwie środkowej, a aplikacje, które kontroluje już
+          sam użytkownik będą znajdować się na samej górze. Procesy mogą
+          komunikować się z innymi procesami o ile te znajdują się na tym
+          samym lub niższym poziomie. Używanie tego rozdzaju podziału, może
+          być kłopotliwe ponieważ obecne serwery nie są już tak prostym
+          oprogramowaniem więc powinny znajdować się tej samej warstwie co
+          przeglądarka czy klient pocztowy, jednak to te aplikacje mogą
+          wykorzystywać serwery do realizacji zadań użytkownika, więc ich
+          miejsce jest raczej na warstwie centralnej (środkowej).
+        </p>
+        <h2 id="1.4.users">1.4. Użytkownicy</h2>
+        <p>
+          Użytkownicy w Linksie są odwzorowaniem rzeczywistych obiektów, czyli
+          <em>encją</em>. Użytkownicy mają prawo do uruchamiania procesów oraz
+          posiadnia (bycia właścielem) plików. Jądro nie rozpoznaje
+          użytkowników po ich nazwach, tak jak mają w zwyczaju to ludzie,
+          używa ono identyfikatorów <strong>userid</strong> w skrócie
+          <strong>UID</strong>. Identyfikatory są przedstawiane za pomocą 
+          liczb. 
+        </p>
+        <p>
+          Użytkownicy istnieją wyłącznie po to aby wyznaczać granice. Każdy
+          proces ma swojego właściela, dlatego też mówi się że proces
+          uruchamia się z uprawnieniami takiego a takiego użytkownika.
+          Użytkownicy mogą uruchamiać i konczyć procesy w własnych granicach
+          (tylko te, których są właścicielami), przez co nie mogą wpływać na
+          procesy innych użytkowników. Poza procesami, użytkownicy mogą 
+          tworzyć własne pliki, których automatycznie stają się właścicielami.
+          Mogą oni decydować czy chcą się nimi dzielić, ustalając im
+          odpowiednie uprawnienia.
+        </p>
+        <p>
+          Poza użytkownikami przypisanymi do konkretnych osób (raczej
+          spotkamy jednego), istnieje kilku dodatkowych specjalnych 
+          użytkowników, głównie mają oni na celu ograniczenie uprawnień
+          serwerów. Po za tymi specjalnymi istnieje jeszcze użytkownik
+          <strong>root</strong>, którego nie tyczą się zapisane powyżej
+          ograniczenia dlatego jest on nazywany <em>superużytkownikiem</em>.
+        </p>
+        <p>
+          Osoba pracująca na koncie użytkownika <em>root</em>, nazywana jest
+          <em>administratorem systemu</em>. <em>Root</em> może kończyć
+          procesy innych użytkowników, przeglądać cudze pliki czy instalować
+          oprogramowanie z repozytorium. Praca na tym koncie jest dość
+          niebezpieczna z punktu widzenia systemu, ponieważ ten użytkownik
+          jest wstanie wykonać czynności prowadzące do zniszczenia całego
+          systemu. Na Linuksie <em>root</em> ma do tego pełne prawo, dlatego
+          projektancji dystrybucji starają się ograniczyć konieczność pracy
+          z wykorzystaniem tego użytkownika.
+        </p>
+        <p>
+          Innym tworem podobnym to użytkowników są <strong>grupy</strong>.
+          Grupy są zbiorem użytkowników, a ich zadaniem jest współdzielenie
+          plików wewnątrz jednej grupy, między jej użytkownikami.
+        </p>
+        <h1 id="2.linuxbasics">2. Podstawy obsługi Linuksa</h1>
+        <p>
+          W tym rozdziale przedstawione zostaną podstawy obsługi systemu
+          Linux, oczywiście z poziomu powłoki, ponieważ inne sposóby
+          zależą w dużej mierze od programów, które do tego celu będziemy
+          wykorzystywać. Takich programów może być kilka, powłok
+          również dostępnych jest kilka rodzajów, jednak sam program powłoki
+          nie będzie wpływać na prezentowane w tym rozdziale czynności. Ten
+          rozdział zaczniem od tego czy jest powłoka.
+        </p>
+        <h2 id="2.1.shells">2.1. Powłoka</h2>
+        <p>
+          <strong>Powłoka</strong> jest chyba jednym z najistoniejszych 
+          komponentów systemu
+          Linux, pozwala ona na uruchamianie róznych poleceń wydawanych przez
+          użytkownika. Powłoki są również małymi środowiskami programistycznymi.
+          Nie które narzędzia systemowe są <strong>skryptami powłoki</strong> - 
+          plikami tekstowymi zawierającymi zbiór wykonywanych kolejno (jedno po
+          drugim) poleceń powłoki.
+        </p>
+        <p>
+          Pierwotną powłoką była <strong>powłoka Bourna</strong>, opracowana
+          jeszcze dla systemu UNIX w laboratoriach <em>Bell Labs</em>. Mimo
+          niezbyt częstego wykorzystywania, powłoka ta jest stałym kompenetem
+          nie tylko systemu Linux, ale i innych systemów uniksopodbnych.
+          Obecnie wykorzystywaną powłoką jest <strong>BASH</strong> - 
+          ulepszona wersja oryginalnej powłoki. Korzystając z róznych
+          dystrybucji, domyślna powłoka może być inna. Ten materiał zakłada
+          wykorzystanie powłoki BASH, szczególnie w rozdziale poświęconym 
+          skryptom powłoki.
+        </p>
+        <h2 id="2.2.shellusage">2.2. Korzystanie z powłoki</h2>
+        <p>
+          Dostęp do powłoki może odbywać się w dwojaki sposób wykorzystać
+          możemy wbudowaną w każdą dystrybucję konsole, nie zależnie od
+          instalacji wybranej przez nas dystrybucji. Jeśli jest to dystrybucja
+          skierowana do komputery biurkowe, to możemy skorzystać z wbudowanego
+          programu <em>terminal</em>. Po uruchomieniu okna powłoki, w prawym
+          górnym rogu pojawi się <strong>symbol zachęty</strong>. Jest to ciąg
+          znaków wskazujący wiersz, w którym będziemy wprowadzać polecenia.
+          Znak zachęty może przyjmować różną formę:
+        </p>
+        <ul>
+          <li><code class="code-inline">użytkownik@host:ścieżka$</code> - 
+            <code class="code-inline">użytkownik</code> - nazwa użytkownika,
+            <code class="code-inline">host</code> - nazwa komputera,
+            <code class="code-inline">ścieżka</code> - obecna ścieżka
+            (czym jest ścieżka, będzie za chwilę). Tego typu symbol zachęty
+            stosowany jest w dystrybucjach opartych na GNU/Linux Debian takich
+            Linux Mint (Mint oparty jest na Ubuntu, a Ubuntu na GNU/Linux
+            Debian) czy Ubuntu.</li>
+          <li><code class="code-inline">[użytkownik@host:katalog]$</code> -
+            <code class="code-inline">użytkownik</code> i
+            <code class="code-inline">host</code> podobnie jak wyżej,
+            <code class="code-inline">katalog</code> - katalog w którym się
+            obecnie znajdujemy, z tego typu znakiem zachęty spotkamy się
+            w dystrybucjach RHEL/Fedora/CentOS oraz Arch Linux.</li>
+          <li><code class="code-inline">bash-wersja$</code> - Originalny symbol
+            zachęty powłoki BASH, <code class="code-inline">wersja</code>
+            przedstawia wersję wykorzystywanej powłoki, spotkamy go
+            w ręcznych instalacjach powłoki (kompilacji kodu źródłowego)</li>
+          <li><code class="code-inline">$</code> - symbol zachęty
+            wykorzystywany w celu zaoszczędzenia miejsca w wierszu polecenia.</li>
+        </ul>
+        <p>
+          W tych symbolach jeden element jest stały jest to znak dolara
+          (<strong>$</strong>), oznacza on że polecenia wydawane będą jako
+          zwykły użytkownika, innym symbolem jest znak krzyżyka
+          (<strong>#</strong>), który mówi nam że polecenia będą uruchamiane
+          przez superużytkownika. Najprostsze polecenie jakie możemy wydać
+          jest użycie polecenia <strong>echo</strong>, które zwraca na
+          standardowe wyjście podajny mu jako argument ciągu znaków:
+        </p>
+<pre class="code-block">
+$ echo Witaj świecie.
+</pre>
+        <p>
+          W przykładach w tym materiale, jeśli polecenia ma zostać wydane z
+          uprawnieniami zywkłego użytkownika, przed poleceniem będzie
+          pojawiać się znak dolara (<strong>$</strong>), a jeśli polecenie ma 
+          być uruchomione z wyższymi uprawnieniami, będą one poprzedzone 
+          znakiem krzyżyka (<strong>#</strong>) oznaczający uprawnienia 
+          użytkownika <em>root</em>.
+        </p>
+        <h3 id="2.2.1.catcommand">2.2.1. Polecnie cat</h3>
+        <p>
+          Polecenie <strong>cat</strong> wypisuje na standardowe wyjście
+          podane w argumentach pliki jeden po drugim dokonując tym samym
+          połączenia (konkatenacji - stąd nazwa polecenia) na jednym
+          strumieniu zawartości tych wszystkich plików.
+        </p>
+<pre class="code-block">
+$ cat plik1 plik2 plik3 ...
+</pre>
+        <h3 id="2.2.2.stdinstdout">2.2.2. Standardowe wyjście i standardowe
+        wejście</h3>
+        <p>
+          Użyłem powyższego polecenia <em>cat</em>, aby nakreślić kontekst dla
+          omówienia dwóch podstawowcyh strumieni. Linux wykorzystuje strumień
+          wejściowy do odczytu danych, a strumień wyjściowy do ich zapisu. 
+          Źródłem strumienia wejściowego może być plik, urządzenie, terminal czy
+          strumień wyjściowy innego procesu. 
+        </p>
+        <p>
+          Strumień wejściowy możemy zaobserować poprzez uruchomienie polecenia
+          <em>cat</em> bez żadnego pliku. Program nie zwróci od razu znaku
+          zachęty, ponieważ oczekuje na dane. Możemy wpisać co kolwiek, a po
+          naciśnięciu klawisza <em>enter</em> polecenie powtórzy ten wpisany
+          tekst. Z racji tego iż nie podaliśmy mu żadnego pliku polecenie
+          zaczęło korzystać ze strumienia <strong>standardowego wejścia</strong>,
+          przekazanego
+          mu przez jądro, w tym przypadku był to terminal, którym zostało
+          uruchomione to polecenie. Aby zakończyć to polecenie należy wciśnąć
+          kombinacje klawiszy <em>Ctrl+d</em>, która oznacza koniec 
+          danych ze standardowego wejścia. 
+        </p>
+        <p>
+          Ze <strong>standardowym wyjściem</strong> jest podobnie, jądro
+          przezkazuje strumień standardowego wyjścia procesom, do którego
+          mogą one zapisywać swoje dane. Polecenie <em>cat</em> zawsze 
+          wypisuje swoje
+          dane na standardowe wyjście, które przez uruchomienie polecenia w
+          terminalu jest do niego podłączone. Dzięki temu mogliśmy zobaczyć
+          wypisywane przez polecenie dane.
+        </p>
+        <p>
+          Standardowe wyjście oraz standardowe wejście możemy zapisać
+          skrótowo <strong>stdout</strong> oraz <strong>stdin</strong>.
+          Takich nazw również należy się spodziewać w wszelakiej dokumentacji.
+        </p>
+        <p>
+          Prócz wspomanianych strumieni istnieje jeszcze trzeci strumień
+          wejścia-wyjścia - <strong>standardowy strumień błędów</strong>.
+          Opiszę go nieco później.
+        </p>
+        <p>
+          Strumienie są dość elastycznym mechanizem, można je zmusić do
+          odczytywania i zapisywania danych z innych miejsc niż terminal.
+          O przekierowaniach strumienii będzie nieco poźniej w tym rozdziale.
+        </p>
+        <h2 id="2.3.basicscommands">2.3. Podstawowe polecenia</h2>
+        <p>
+          Poniżej znajduje się pogrupowane przedstawienie najbardziej
+          podstawowych poleceń niezbędnych do pracy w powłoce systemu Linux.
+        </p>
+        <ul>
+          <li>polecenie <strong>ls</strong> - wypisuje zawartość katalogu.
+            Najważniejsze opcje:
+            <ul>
+              <li><strong>-a</strong> - powoduje wyświetlenie wszystkich
+              elementów, łącznie z tzw. <em>dot-files</em> (plikami ukrytymi,
+              plikami konfiguracyjnymi</li>
+              <li><strong>-l</strong> - wyświetlenie zwartości katalogu w
+              postaci kilku kolumnowej tabeli zawierającej m.in uprawnienia,
+              czas ostatniej modyfikacji plików, wielkość czy przypisanie 
+              pliku, katalogu do użytkownika oraz grupy.
+            </ul></li>
+          <li>polecenie <strong>cp</strong> - kopiujej pliki
+            Najważniejsze opcje:
+            <ul>
+              <li><strong>-p</strong> - zachowuje atrybuty kopiowanych plików,
+                na przykład takie jak uprawnienia czy przypisanego właściela i
+                grupę</li>
+              <li><strong>-r</strong> - kopiowanie rekurencyjne, kopiuje całe
+                katalogi wraz z podkatalogami oraz ich zawartością.</li>
+              <li><strong>-v</strong> - włącza komunikaty diagostyczne,
+                polecenie wypisuje co, gdzie kopiuje. Normalnie program nie
+                zwraca nic poza znakiem zachęty po zakończonym kopiowaniu.</li>
+            </ul></li>
+          <li>polecenie <strong>mv</strong> - w najprostszym przypadku
+            polecenie służy do zmiany nazwy pliku, jednak gdy drugim
+            argumentem będzie katalog, plik zostanie przeniesiony do tego
+            katalogu. Najważniejsze opcje:
+            <ul>
+              <li><strong>-v</strong> - włącza komunikaty diagnostyczne,
+                identycznie jak w przypadku <em>cp</em>.</li>
+            </ul></li>
+          <li>polecenie <strong>touch</strong> - aktualizuje czas modyfikacji
+            pliku, jeśli plik nie istnieje to zostanie utworzony pusty plik o
+            podanej w argumencie nazwie.</li>
+          <li>polecenie <strong>rm</strong> - polecenie służy do kasowania
+            plików. Kombinacja opcji <strong>-rf</strong> wykorzystywana jest
+            kasowania całych katalogów z podkatalogami. Najważniejsze opcje:
+            <ul>
+              <li><strong>-r</strong> - umożliwia, kasowanie rekurencyjne,
+                całych katalogów z podkatalogami.</li>
+              <li><strong>-f</strong> - przed każdym kasowaniem pliku polecenie
+                pyta czy jesteśmy pewni, że chcemy skasować ten plik. Ta opcja
+                pomija to pytanie wymusząjąc tak jakby kasowanie.</li>
+            </ul></li>
+          <li>polecenie <strong>echo</strong> - polecenie wypisuje ciąg znaków
+            podany jako argument na standardowe wyjście. Najważniejsze opcje:
+            <ul>
+              <li><strong>-n</strong> - ta opcja wyłącza przechodzenie
+                do nowej linii, po wypisaniu ciągu znaków.</li> 
+            </ul></li>  
+        </ul>
+        <h2 id="2.4.commandsworksondir">Polecenia działające na katalogach</h2>
+        <p>
+          Uniksy w tym i Linux, korzystają ze standardu hierarchi katalogów,
+          aby utrzymać w porządku dane przestrzeni użytkownika. Za początkowy
+          katalog uznaje się <strong>katalog główny</strong> oznaczany prawym 
+          ukośnikiem lub
+          slashem (<strong>/</strong>), wewnątrz tego katalogu znajdują się
+          pod katalogi, przechowujące konkretny rodzaj czy typ plików zgodny
+          z ich przeznaczeniem.
+        </p>
+        <p>
+          Droga do konkretnego katalogu nosi nazwę <strong>ścieżki</strong>.
+          Jeśli ścieżki zaczynają się od <em>/</em>, czyli od katalogu głównego
+          mamy doczynienia ze <strong>ścieżką bezwzględną</strong>. Elementy 
+          katalogów na
+          ścieżkach katalogi mogą być również wyrażane z pomocą jednej lub 
+          dwóch kropek.
+          Dwie kropki (<strong>..</strong>) oznaczają katalog nadrzędny
+          względem aktualnego katalogu, zaś jedna kropka oznacza
+          (<strong>.</strong>) aktualny katalog. Ścieżki nie zawierające
+          slasha na początku, czyli nie zaczynające się od katalogu głównego
+          są wówczas określane mianem <strong>ścieżki względnej</strong>.
+        </p>
+        <ul>
+          <li>polecenie <strong>cd</strong> - polecenie służy do zmiany
+            aktualnego katalogu, jako argument przyjmuje katalog, do którego
+            checemy przejść, równie dobrze możemy przenieść się w dowolne
+            miejsce w systemie plików (w katalogu głównym) podając jako
+            argument ścieżkę. Nie podanie argumentu spowowduje przejście do
+            katalogu domowego użytkownika.</li>
+          <li>polecenie <strong>mkdir</strong> - polecenie tworzy nowy katalog.
+            Jako argument przyjmuje nazwę katalogu lub ścieżkę. Najważniejsze 
+            opcje:
+            <ul>
+              <li><strong>-p</strong> - opcja tworzy katalogi nadrzędne podane
+                w ścieżce o ile te nie istnieją. Za pomocą odpowiednich
+                podstawień powłoki oraz tej opcji można tworzyć całe struktury
+                katalogowe.</li>
+            </ul></li>
+          <li>polecenie <strong>rmdir</strong> - usuwa katalog po warunkiem, że
+            jest on pusty. W przeciwnym razie polecenie zwróci błąd. Chcąc
+            usuwać całe katalogi z danymi oraz podkatalogami należy użyć
+            polecenia <em>rm -rf</em>.</li>
+        </ul>
+        <h3 id="2.4.1.globbing">2.4.1. Nazwy wieloznaczne.</h3>
+        <p>
+          Dzięki możliwością powłoki możemy porównywać proste wzorce z nazwami
+          plików w obrębie aktualnego katalogu roboczego (katalogu w którym
+          się znajdujemy) czynność ta nazywana jest rozwijaniem nazw lub
+          <em>globbingiem</em>. Jednym z elementów biorących udział w 
+          rozwiązywaniu nazw jest gwiazdka (<strong>*</strong>) oznaczająca
+          dowolną ilość dowolnych znaków. Dla przykładu poniższe polecenie:
+        </p>
+<pre class="code-block">
+$ echo *
+</pre>
+        <p>
+          Zwróci nazwy wszystkich plików i katalogów  znajdujących się w 
+          katalogu. Innym
+          znakiem wykorzystywanym przy nazwach wieloznacznych jest
+          znak zapytania (<strong>?</strong>) reprezentuje on jeden dowolny
+          znak, dla wzorca <em>b?at</em> pasującymi nazwami mogą być
+          <em>blat</em> oraz <em>brat</em>. Rozwinięcia nazw dokonuje powłoka
+          przed uruchomieniem, więc jeśli chcemy aby, któreś ze znaków 
+          wieloznacznych trafiło do polecnie to należy umieść je w pojedyńczych
+          cudzysłowach.
+        </p>
+        <h2 id="2.5.proxycommands">2.5. Polecenia pośredniczące</h2>
+        <ul>
+          <li>polecenie <strong>grep</strong> - wyszukuje wzorzec
+          w podanym pliku. Polecenie to korzysta z systemu wzorców nazwanych
+          <strong>wyrażeniami regularnymi</strong>. Najważniejszymi opcjami:
+          <ul>
+            <li><strong>-i</strong> - wyłącza rozróżnianie małych i
+            wielkich liter.</li>
+            <li><strong>-v</strong> - podwoduje odwrócenie wyszukiwania,
+            zwracane są wyniki nie pasujące do wzorca.</li>
+            <li><strong>-e</strong> - wykorzystuje rozszerzony zestaw 
+            instrukcji pozwalajacych na tworzenie wyrażeń regularnych.</li>
+            <li><strong>-o</strong> - opcja powoduje zwrócenie dokładnie
+            tylko tych znaków pasujących do wzorca. Normalnie polecenie zwraca
+            linię z elementami pasującymi do wzorca, w przypadku wielu plików
+            zwraca również nazwę pliku.</li>
+          </ul>
+          Tworzenie wyrażeń regularnych oraz więcej opcji tego polecenia
+          znajduje się na stronie podręcznika uruchamianej poleceniem:
+<pre class="code-block">
+$ man grep
+</pre>
+          Do najważniejszych wyrażeń, które każdy powinien znać należą:
+          <ul>
+            <li><strong>.*</strong> - oznaczające dowolną ilość dowolnych
+              znaków.</li>
+            <li><strong>.</strong> - oznacza jeden dowolny znak.</li>
+          </ul></li>
+          <li>polecenie <strong>less</strong> - wypisuje dane z pliku, lub
+            ze strumienia wykorzysując podział na strony. Jedna strona to jeden
+            ekran. Następne strony są wyświetlane za naciśnięciem <em>spacji</em>
+            stronę możemy cofnąć klawiszem <em>b</em>, zakończyć przeglądanie
+            danych klawiszem <em>q</em>. Dane możemy przeglądać linia po linii
+            używając strzałek. Możliwe jest również wyszukiwanie fraz w danych
+            za pomocą <em>/</em> (wyszukiwanie w przód) lub za pomocą 
+            <em>?</em> (wyszukiwanie w tył).</li>
+          <li>polecenie <strong>pwd</strong> - wyświetla obecny katalog
+            roboczy powłoki (świeżkę na której się znajdujemy). Polecenie
+            niepozorne choć przydatne, ze względu na dowiązania symboliczne
+            (będzie o nich w dalszej części materiału), które mogą przesłaniać
+            ścieżkę wyświetlaną w znaku zachęty. Najważnejsza opcja jest
+            uruchamiana, gdy nie ma żadnej opcji, więc jej opis pominę.
+            Warto dodać, że obecne systemy posiadają polecenie <em>pwd</em>
+            wbudowane w powłokę. Dlatego też opcja <strong>-P</strong>
+            rozwijająca fizyczne ścieżki nie jest automatycznie uruchamiana
+            w przypadku poprostu wydania polecenia <em>pwd</em>, prawdziwe
+            polecenie <em>pwd</em> uruchamiamy:
+<pre class="code-block">
+$ /usr/bin/pwd
+</pre>
+          </li>
+          <li>polecenie <strong>diff</strong> - wszukuje różnice pomiędzy
+            dowoma plikami tekstowymi. Polecenie to posiada wiele różnych opcji
+            formatowania danych wyjściowych, najbardziej czytelnym pozostaje
+            chyba użycie opcji <strong>-u</strong>. Polecenie wykorzystywane
+            programistów oraz system kontroli wersji git.</li>
+          <li>polecenie <strong>file</strong> - polecenie zwraca format pliku
+            podanego jako argument. W uniksach nie potrzeby stosowania
+            rozszerzeń plików, więc to polecenie może pomóc nam dowiedzieć
+            się co zawiera plik.</li>
+          <li>polecenie <strong>find</strong> i <strong>locate</strong> -
+            polecenia te służą do wyszukiwania plików w systemie. Polecenie
+            <em>find</em> wymaga podania katalogu po nazwie polecenia, nazwy
+            wyszukiwanego pliki po opcji <strong>-name</strong> oraz opcji
+            <strong>-print</strong>, która powoduje wyświetlenie na strumieniu
+            standardowego wyjścia nazw plików pasujących do wzorca podanego w
+            opcji <em>-name</em>. Polecenie <strong>locate</strong> na podobne
+            zastosowanie jak <em>find</em> działa jednak od niego szybciej
+            ponieważ bazuje na indeksie przygotowywanym co jakiś czas przez
+            system operacyjny. Może być ono bezużyteczne, kiedy szukamy nowych
+            plików, gdyż mogą być one nie ujęte jeszcze w indeksie.</li>
+          <li>polecenie <strong>head</strong> i <strong>tail</strong> -
+            te polecenia służa do prezentowania wycinka danych czy to ze
+            strumienia lub z pliku. W przypadku polecenia <em>head</em>
+            prezentowane jest <em>n</em> pierwszych linii, domyslnie 10;
+            z kolei polecenie tail prezentuje <em>n</em> koncowych linii.
+            Liczbę linii podajemy bezpośrednio po znaku myślnika
+            (<strong>-</strong>). Z tych dwóch poleceń polecenie <em>tail</em>
+            ma nieco większe zastosowanie niż polecenie <em>head</em>. Mozemy
+            wywołać to polecenie aby wyświetlić dane od linii, numer linii
+            podajemy po znaku plusa (<strong>+</strong>), inna właściwością
+            chyba najważniejszą jest wyświetlanie danych na żywo, używając
+            opcji <strong>-f</strong>, a następnie nazwy pliku lub myślnika
+            gdy dane pochodzą ze strumienia wyjściowego innego polecenia.</li>
+          <li>polecenie <strong>sort</strong> - układa wiersze z pliku
+            tekstowego w porządku alfabetycznym, jeśli na początku wierszy
+            znajdują się liczby to aby je posortować należy użyć opcji
+            <strong>-n</strong>, aby odwrócić sortowanie możemy użyć opcji
+            <strong>-r</strong>.</li>
+        </ul>
+        <h2 id="2.6.passwdandchsh">2.6. Zmiana hasła i powłoki</h2>
+        <p>
+          W celu zmiany hasła należy użyć polecenia <strong>passwd</strong>.
+          Polecenie poprosi o podanie obecnego hasła, po zatwierdzeniu go
+          zostaniemy poproszeni o nowe hasło i jego potwierdzenie (wpisanie
+          ponowne nowego hasła).
+        </p>
+        <p>
+          Zmiana aktywnej powłoki odbywa się za pomocą polecenia
+          <strong>chsh</strong>, albo użyć poleceń odpowiadających nazwom
+          innych powłok, kolejno <strong>ksh</strong> - Korn SHell,
+          <strong>tcsh</strong> - TENEX C SHell. Użycie tych poleceń w 
+          aktywnej powłoce, spowoduje uruchomienie podpowłoki. Zamkniecie
+          jej spowoduje powrót do pierwotnej powłoki.
+        </p>
+        <h2 id="2.7.dotfiles">2.7. Pliki z kropką</h2>
+        <p>
+          Przeglądając pliki nawet w własnym katalogu domowym możemy znaleźć
+          pliki, których nazwa zaczyna się od kropki. Nie które źródła mówią
+          tym o że te pliki są ukryte. Do takich wniosków może dojść,
+          ponieważ te pliki nie są domyślnie wyświetlane przez polecenie
+          <em>ls</em> bez opcji <em>-a</em> lub przez menedżery plików dostępne
+          w desktopowych wersja Linuksa. Jednak te pliki nie różnia się niczym
+          od inny plików, poza właśnie tym przypadkiem opisanym powyżej.
+          Oprócz plików, nazwy katalogów również mogą zaczynać się od kropki.
+          Za pomocą prostego wzorca możemy wyświetlić wszystkie <em>dot-files</em>,
+          jeśli wsród nich trafi się katalog, wówczas zostanie wyświetlona jego
+          nazwa a pod nią jego zawartość. 
+        </p>
+<pre class="code-block">
+$ ls .??*
+</pre>
+        <h2 id="2.8.shellandenvvars">2.8. Zmienne środowiskowe i powłoki</h2>
+        <p>
+          Powłoka może przechowywać zmienne tymczasowe, które mogą przechowywać
+          różne wartości, mogą one kontrolować zachowanie samej powłoki jedną
+          z takich zmiennych jest zmienna <strong>PS1</strong> zawierająca
+          znak zachęty. Takie zmienne najczęsćiej wykorzystywane są w 
+          skryptach powłoki i nazywane są <strong>zmiennymi powłoki</strong>.
+          Definicja zmiennych tego składa się z nazwy zmiennej, operatora
+          przypisania (znaku równości <strong>=</strong>) oraz wartości samej
+          zmiennej.
+        </p>
+<pre class="code-block">
+$ zmienna=12
+</pre>
+        <p>
+          Odwołać się do wartości zmiennej możemy w dowolnym momencie, podając
+          jej nazwę poprzedzoną znakiem dolara (<strong>$</strong>).
+        </p>
+<pre class="code-block">
+$ echo $zmienna
+</pre>
+        <p>
+          <strong>Zmienna środowiskowa</strong> jest podobna do zmiennej
+          powłoki, ale nie jest ściśle związana z powłoką, bowiem do pamięci
+          zmiennych środowiskowych systemach uniksopodobnych mają wszystkie
+          aplikacje, system operacyjny przezkazuje je do każdego programu
+          uruchomionego w powłoce, programy te nie mają jednak dostępu do
+          zmiennych powłoki. Zmienne środowiskowe definiuje się w ten sam 
+          sposób
+          jak zmienne powłoki, jedna aby taka zmienna stała się zmienną
+          środowiskową musi zostać przeniesiona do pamięci tych zmiennych
+          za pomocą polecenia <strong>export</strong>.
+        </p>
+<pre class="code-block">
+$ zmienna=21
+$ export zmienna
+</pre>
+        <p>
+          Nie które programy mogą wykorzystywać zmienne środowiskowe do
+          własnej konfiguracji. Dla przykładu niektóre programy uruchamiane
+          w powłoce korzystają ze zmiennej środowiskowej <em>EDITOR</em>
+          definiujące domyślny program do edycji plików tekstowych.
+          Wykorzystanie zmiennych środowiskowych zapewne jest opisane w
+          na stronie podręcznika programu.
+        </p>
+        <h2 id="2.9path">2.9. Ścieżka poleceń</h2>
+        <p>
+          Istnieje specjalna zmienna środowiskowa <strong>PATH</strong>,
+          przechowywująca katalogi, w których to powłoka będzie szukać
+          programów odpowiadających wpisanym poleceniom. Jeśli wśród
+          przeszukiwanych katalogów znajduje się kilka programów o tej samej
+          nazwie to powłoka uruchomi pierwszy przez nią znaleziony. Ścieżki
+          katalogów w tej zmiennej odzielone są dwukropkiem (<strong>:</strong>).
+          Posiadając swoje programy, możemy również umieść katalog z nim
+          wewnątrz zmiennej <em>$PATH</em>. Opcje dodanie katalogu są dwie
+          i mogą mieć wpływ na funkcjonowanie systemu. Możemy dodać nasz
+          katalog na początku zmiennej, wówczas powłoka zacznie od niego
+          poszukiwania, jednak należy pamiętąc przy tym, aby nazwy programów
+          nie pokrywały się istniejącymi dotychczas poleceniami.
+        </p>
+<pre class="code-block">
+$ PATH=kat:${PATH}
+</pre>
+        <p>
+          Na powyższym przykładzie <code class="code-inline">kat</code>, to 
+          nasz katalog z oprogramowaniem. Możemy jednak skorzystać
+          bezpieczeniejszego rozwiązania - dopisać nasz katalog na końcu listy
+          katalogów zmiennej <em>PATH</em>, wówczas nawet jeśli nasz program 
+          będzie
+          nazywać się jak jedno z instniejących już poleceń w systemie, nie
+          będzie miało to wpływu na działanie systemu.
+        </p>
+<pre class="code-block">
+$ PATH=${PATH}:kat
+</pre>
+        <p>
+          Na powyższych przykładach użyłem znaku dolara wraz z nawiasami
+          klamrowymi. Jest to sposób na separacje nazwy zmiennej od innych
+          znaków, po to aby powłoka nie potraktowała jak w przykładzie powyżej
+          ciągu znaków ":kat" jak części nazwy zmiennej. Przedstawione w
+          przykładach polecenia są nie groźne, jeśli uszkodzimy zawartość
+          zmiennej <em>PATH</em>, to należy zamknąć okno terminala i otworzyć
+          nowe. 
+        </p>
+        <h2 id="2.10.specialchars">2.10. Znaki specjalne</h2>
+        <p>
+          W systemach uniksopodbnych wiele znaków ma szczególne znaczenie.
+          Poniżej znajduje się tabela przedstawiająca wykorzystwane podczas
+          używania systemu znaki specjalne.
+        </p>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Znak</th>
+              <th>Nazwa</th>
+              <th>Opis</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><strong>*</strong></td>
+              <td>gwiazdka</td>
+              <td>Wyrażenie regularne, znak nazwy wieloznacznej</td>
+            </tr>
+            <tr>
+              <td><strong>.</strong></td>
+              <td>kropka</td>
+              <td>Aktualny katalog, ogranicznik nazwy pliku lub hosta</td>
+            </tr>
+            <tr>
+              <td><strong>!</strong></td>
+              <td>wykrzyknik</td>
+              <td>Negacja, historia poleceń</td>
+            </tr>
+            <tr>
+              <td><strong>|</strong></td>
+              <td>potok</td>
+              <td>Potoki poleceń</td>
+            </tr>
+            <tr>
+              <td><strong>/</strong></td>
+              <td>slash</td>
+              <td>Ogranicznik katalogów, polecenie szukania</td>
+            </tr>
+            <tr>
+              <td><strong>\</strong></td>
+              <td>backslash</td>
+              <td>Literały, makra (nigdy katalogi)</td>
+            </tr>
+            <tr>
+              <td><strong>$</strong></td>
+              <td>dolar</td>
+              <td>Oznaczenie zmiennych, koniec wiersza</td>
+            </tr>
+            <tr>
+              <td><strong>'</strong></td>
+              <td>pojedynczy cudzysłów</td>
+              <td>Ciągi znaków literałów</td>
+            </tr>
+            <tr>
+              <td><strong>`</strong></td>
+              <td>lewy cudzysłów</td>
+              <td>Podmiana polecenia</td>
+            </tr>
+            <tr>
+              <td><strong>"</strong></td>
+              <td>podwójny cudzysłów</td>
+              <td>Ciągi znaków pseudoliterałów</td>
+            </tr>
+            <tr>
+              <td><strong>^</strong></td>
+              <td>daszek</td>
+              <td>Negacja, początek wiersza</td>
+            </tr>
+            <tr>
+              <td><strong>~</strong></td>
+              <td>tylda</td>
+              <td>Negacja, skrót katalogu</td>
+            </tr>
+            <tr>
+              <td><strong>#</strong></td>
+              <td>krzyżyk</td>
+              <td>Komentarze, dyrektywy preprocesora, podmiany</td>
+            </tr>
+            <tr>
+              <td><strong>[]</strong></td>
+              <td>nawiasy kwadratowe</td>
+              <td>Zakresy</td>
+            </tr>
+            <tr>
+              <td><strong>{}</strong></td>
+              <td>nawiasy klamrowe</td>
+              <td>Bloki poleceń, zakresy</td>
+            </tr>
+            <tr>
+              <td><strong>_</strong></td>
+              <td>podkreślenie</td>
+              <td>Prosty zamiennik spacji</td>
+            </tr>
+          </tbody>
+        </table>
+        <p>
+          Często możemy napotkać symbol daszka (<strong>^</strong>) zastępujący
+          klawisz <em>Control</em>, przez co zapis <em>^C</em> jest równe
+          kombinacji klawiszy <em>Ctrl+C</em>.
+        </p>
+        <h2 id="2.11.commandlineedit">2.11. Edycja wiersza poleceń</h2>
+        <p>
+          Znak zachęty wskazuje wiersz polecenia, który możemy edytować
+          przesuwając kursor za pomocą strzałek. Chcąc powtórzyć jakąś czynność
+          nie musimy pisać na nowo tego polecenia, możemy wybrać je z historii
+          poleceń za pomocą strzałek w góre i w dół. Warto jednak obsługę
+          wiersza poleceń za pomocą strzałek odstawić na bok. Wykorzystując
+          skróty z poniższej tabeli, możemy nimi śmiało zastąpić strzałki. 
+          Istnieją ku temu dwa powody. 
+        </p>
+        <ul>
+          <li>Nie wszystkie klawiatury posiadają strzałki, lub ich użycie jest
+            strasznie nie konfortowe.</li>
+          <li>Wiele programów uniksowych (w tym i linuksowych) obsługuje się
+            za pomocą tzw. biblioteki <strong>GNU Readline</strong> (skróty
+            klawiszowe w tabeli poniżej), a nie za pomocą strzałek.</li>
+        </ul>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Klawisze</th>
+              <th>Operacja</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+               <td><em>Ctrl+b</em></td>
+               <td>Przesunięcie kursora w lewo</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+f</em></td>
+              <td>Przesunięcie kursora w prawo</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+p</em></td>
+              <td>Powrót do poprzedniego polecenia (lub przesunięcie kursora
+                w górę)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+n</em></td>
+              <td>Przejście do następnego polecenia (lub przesunięcie klawisza
+                w dół)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+a</em></td>
+              <td>Przesunięcie kursora na początek wiersza</td> 
+            </tr>
+            <tr>
+              <td><em>Ctrl+e</em></td>
+              <td>Przesunięcie kursora na koniec wiesza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+w</em></td>
+              <td>Usunięcie słowa poprzedzjącego kursor</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+u</em></td>
+              <td>Usunięcie tekstu od kursora do początku wiersza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+k</em></td>
+              <td>Usunięcie tekstu od kursora do końca wiersza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+Y</em></td>
+              <td>Wyklejanie usuniętego tekstu (na przykłda usuniętego
+                poleceniem <em>Ctrl+u</em>)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+h</em></td>
+              <td>Substytut klawisza <em>Backspace</em></td> 
+            </tr>
+            <tr>
+              <td><em>Ctrl+d</em></td>
+              <td>Substytut klawisza <em>delete</em></td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+j, Ctrl+m</em></td>
+              <td>Substytut klawisza <em>enter</em></td>
+            </tr>
+          </tbody>
+        </table>
+        <h2 id="2.12.texteditors">2.12. Edytory tekstu</h2>
+        <p>
+          Na Linuksie mamy podobną ilość edytorów tekstowych do wyboru jak w
+          przypadku systemów MS Windows czy Apple macOS. Jak nie więcej.
+          Co ciekawe macOS, również jest system uniksopodobnym. Więc to co
+          zostało omówione w tym rozdziale również będzie kompatybilne z tym
+          systemem. Wracając jednak do edytorów tekstu. Tak naprawdę to
+          istnieją dwa, na które warto zwrócić uwagę, oba są standardem jeśli
+          chodzi o edycje tekstu i oba wymagają nauki obsługi. Wybór
+          pozostawiam do roztrzygniecia Tobie. 
+        </p>
+        <ul>
+          <li><strong>GNU Emacs</strong> - edytor w którym można zrobić
+            wszystko, od pisania tekstów do wykorzystania go jako menedżer
+            okien. Jego obsługa nie jest zbyt szybka i często by się
+            wydawało proste czynności wymagają użycia kliku poleceń. Wydaje
+            mi się, że nie ma bardziej rozbudowanego uniksowego programu.
+            Pomoc w obsłudze tego edytora, możemy uruchomić naciskając
+            <em>Ctrl+H</em> następnie klawisz <em>t</em>.</li>
+          <li><strong>VIm</strong> - szybki edytor uruchamiany w terminalu,
+            choć można zainstalować wersję graficzną. Obsługuje się go trochę 
+            jak grę. VIm, jest nieco bardziej intuicyjny od Emacsa. Warto
+            dodać, że edytor ten bywa domyślnie doinstalowywany do wielu
+            dystrybucji jak i innych systemów uniksowych, choć tam może
+            występować w podstawowej wersji <strong>Vi</strong>. Chcąc
+            nauczyć się edytora <em>Vim</em>, możemy skorzystać z
+            z instalowanego wraz z edytorem tutoriala, uruchamianego poleceniem
+            <strong>vimtutor</strong>.</li>
+        </ul>
+        <p>
+          Jeśli potrzebujemy edytora, który jest wstanie zatąpić nam
+          środowisko graficzne, wybierzmy edytor <em>Emacs</em>. Jeśli jednak 
+          chcemy
+          poprostu edytować pliki, w każdym możliwym środowisku wybierzmy
+          edytor <em>Vim</em>. Osobiście jestem przyzwyczajony już do edytora
+          <em>Vim</em>.
+        </p>
+        <h2 id="2.13.gettinghelp">2.13. Uzyskiwanie pomocy</h2>
+        <p>
+          Dystrybucje Linuksa są rozporowadzane z dużą ilością różnej
+          dokumentacji. Informacje temat poleceń możemy znaleźć na stronach
+          podręcznika, wydając polecenie <strong>man</strong> i podając jako
+          argument interesujące nas polecenie. Na przykład:
+        </p>
+<pre class="code-block">
+$ man ls
+</pre>
+        <p>
+          W ten sposób uruchomimy stronę podręcznika polecenia <em>ls</em>.
+          Większosć stron podręcznika podaje suche informacje na temat
+          polecenia, nie ma co tam szukać jakiś samouczków. Opcje podawana są
+          usystematyzowany sposób (najczęściej alfabetyczny), nie które
+          strony podręcznika mogą zawierać przykłady.
+        </p>
+        <p>
+          Strony podręcznika możemy przeszukać pod kątem słowa kluczowego, za
+          pomocą opcji <strong>-k</strong>, polecenia <em>man</em>. Wynikiem
+          tego polecenie jest lista poleceń, oraz krótki opis zawierający
+          podane słowo kluczowe, ciekawa jest liczba podana w nawiasie obok
+          nazwy polecenia, jest to <strong>numer rozdziału</strong>.
+        </p>
+        <p>
+          Strony podręcznika są podzielone rozdziały oznaczone numerami, każdy
+          z nich zawiera innego rodzaju strony podręcznika. Rozdziały
+          zostały opisane w tabeli poniżej. 
+        </p>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Rozdział</th>
+              <th>Opis</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><strong>1</strong></td>
+              <td>Polecenia użytkownika</td>
+            </tr>
+            <tr>
+              <td><strong>2</strong></td>
+              <td>Niskopoziomowe wywołania systemowe</td>
+            </tr>
+            <tr>
+              <td><strong>3</strong></td>
+              <td>Dokunentacja wysokopoziomowych bibliotek Uniksa</td>
+            </tr>
+            <tr>
+              <td><strong>4</strong></td>
+              <td>Informacje o interfejsach urządzeń i sterownikach</td>
+            </tr>
+            <tr>
+              <td><strong>5</strong></td>
+              <td>Opisy plików (konfiguracji systemu)</td>
+            </tr>
+            <tr>
+              <td><strong>6</strong></td>
+              <td>Gry</td>
+            </tr>
+            <tr>
+              <td><strong>7</strong></td>
+              <td>Formaty plików, konwencje i kodowaniaa (ASCII, przyrostki itd)</td>
+            </tr>
+            <tr>
+              <td><strong>8</strong></td>
+              <td>Polecenia systemowe i serwery</td>
+            </tr>
+          </tbody>
+        </table>
+        <p>
+          Jak uzupełnienie tego materiału świetnie sprawdzą się rodziały
+          1,5,7 i 8. Wywołanie konkretnej strony a danego rozdziału wymaga
+          podania jego numeru jak pierwszego argumentu, wówczas polecenie
+          będzie wszukać informacji na temat podanego słowa w danym rodziale.
+          Świetnym przykładem może być, chęć sprawdzenia na stronach
+          podręcznika pliku <em>/etc/passwd</em>. Należy wydać polecenie:
+        </p>
+<pre class="code-block">
+$ man 5 passwd
+</pre>
+        <p>
+          Dość często wykorzystywanym sposóbem na uzyskanie informacji o
+          poleceniach mogą być same polecenia, sprawdźmy czy możemy je
+          uruchomić z opcją <strong>-h</strong> lub <strong>--help</strong>.
+        </p>
+        <p>
+          Projekt GNU jakiś czas temu zadecydował, że będzie używać innego
+          formatu plików pomocy niż strony podręcznika, format nazywana jest
+          <strong>info</strong> lub <strong>texinfo</strong>. Format ten
+          zawiera więcej informacji choć jest od niego bardziej skomplikowany.
+          Przypomina prostą stronę internetowa, otworzoną w terminalowej
+          przeglądarce. Tego typu pliki pomocy uruchamiane są za pomocą
+          polecenia <strong>info</strong>, po czym podaje mu się jako argument
+          interesujące nas polecenie. 
+        </p>
+        <p>
+          Nie które z pakietów umieszczają swoją dokumentację w katalogu
+          <em>/usr/share/doc</em> nie zwracając uwagi na format. Warto
+          pamiętać o tych miejscach szukając pomocy, oczywiście pozostaje na
+          do dyspozycji jeszcze internet.
+        </p>
+        <h2 id="2.14.shellio">2.14. Wejście i wyjście powłoki</h2>
+        <p>
+          Omawiając po krótce powłokę, wspomniałem o strumieniach standardowego
+          wejścia i wyjścia. Wiele poleceń używa wyjścia aby wypisywać
+          wyniki działa lub komunikaty diagonstyczne. Jeśli nie chcemy ich
+          widzieć lub nie nadąrzymy ich analizować możemy je przekierować
+          na przykład do pliku, za pomocą znaku przekierowania (<strong>&gt;</strong>).
+        </p>
+        <p>
+          Używając tego znaku musimy omówić sobie jedną ważną rzecz, znak ten
+          powoduje nadpisanie wszystkiego co znajduje się w pliku. Tego typu
+          czynność nazywana jest <strong>wymazywaniem</strong>
+          (ang. <em>clobbering</em>). Możemy jednak zablokwać to działanie
+          za pomocą odpowiednich ustawień powłoki, dla BASH wystarczy użyć
+          polecenia <code class="code-inline">set -C</code>. Poza blokowaniem
+          wymazywania, istnieje jeszcze jeden znak przekierowania, który
+          powoduje dopisanie przekierowanego wyjścia do pliku:
+          <strong>&gt;&gt;</strong>.
+        </p>
+        <p>
+          Za pomocą przekierowań możemy w prosty sposób połączyć wyjście
+          jednego polecenia z wejściem innego. Służy temu znak <strong>potoku</strong>
+          (<strong>|</strong>). Postawienie ponowej kreski, pomiędzy
+          poleceniami w wierszu polecenia połączy wyjście pierwszego z wejściem
+          drugiego.
+        </p>
+        <h3 id="2.14.1.stderr">2.14.1 Standardowy strumień błędów</h3>
+        <p>
+          Korzystając powyższych znaków przekierowania polecenia, dane
+          wyjściowe programów zostaną przekierowane np. do pliku. Ale
+          komunikaty diagnostyczne nadal są wyświetlane. Dzieje się to dlatego
+          iż komunikaty diagnostyczny wykorzystują trzeci dodatkowy strumień
+          <strong>standardowy strumień błędów</strong> zapisywany skrótowo
+          <strong>stderr</strong>, który podobnie do <em>stdout</em> jest
+          podłączony do terminala.
+        </p>
+        <p>
+          Do przekierowania tego strumienia musimy użyć identyfikatorów
+          strumienii jest to liczba, którą posługuje się jądro do rozrózniania
+          strumieni. W fachowej
+          literaturze bądź dokumentacji możemy natknąć się na termin
+          <strong>deskryptor pliku</strong>. Taki identyfikator dla <em>stderr</em>
+          ma wartość <strong>2</strong>, a dla <em>stdout</em> <strong>1</strong>.
+          Chcąc przekierować <em>stderr</em> do innego pliku musimy podać jego
+          identyfikator przed znakiem przekierowania. Innym przypadkiem jest
+          przekierowanie <em>stderr</em> do tego samego pliku co <em>stdout</em>,
+          wówczas najprostszym sposób jest podłączenie strumienia błedów do
+          standardowego wyjścia za pomocą znaku <strong>&gt;&amp;</strong>
+          podając przekierowywany strumień po lewej stronie znaku (przed nim)
+          a strumień docelowy po prawej (za nim).
+        </p>
+<pre class="code-block">
+$ ls /ffffffff &gt;p 2&gt;&amp;1
+</pre>
+        <h3 id="2.14.2.stdin">2.14.2. Przekierowanie standardowego wejścia</h3>
+        <p>
+          Przekierowanie standardowego wejścia występuję dość rzadko ponieważ
+          większość poleceń przyjmuje plik jako argument, jednak może zdarzyć
+          się potrzeba przekierowania wejścia do polecenia. Służy temu
+          <strong>znak przekierowania wejścia</strong> <strong>&lt;</strong>.
+        </p>
+        <h2 id="2.15.readingerrors">2.15. Odczytywanie komunikatów o błędach</h2>
+        <p>
+          Prędzej czy później gdzieś podczas naszej pracy z powłoką zdarzy
+          się błąd. Ważne jest aby umieć go odczytać i prawidłowo z
+          interpretować.
+        </p>
+        <p>
+          Sam komunikat składa się przeważnie z nazwy polecenia oraz
+          komunikatu błędu, w nie których przypadkach w komunikacie
+          znajduje się nazwa pliku, jednak dotyczy specyficznych komunikatów
+          o błędach. Poniżej znajduje się
+          lista, błędów z którym będziemy się spotykać podczas pracy z systemem 
+          Linux. 
+        </p>
+        <ul>
+          <li><strong>No such file or directory</strong>
+            (<em>nie ma takiego pliku lub katalogu</em>) - występuje gdy
+            plik lub katalog podany jak argument nie istnieje. Innym powodem
+            występowania takiego błędu może być błędnie zapisana nazwa
+            polecenia w skrypcie.</li>
+          <li><strong>File exists</strong> (<em>plik istnieje</em>) - ten
+            problem występuje w momencie gdy próbujemy stworzyć katalog o
+            nazwie pliku, który już istnieje.</li>
+          <li><strong>Not a directory</strong> (<em>nie jest katalogiem</em>),
+            <strong>Is a directory</strong> (<em>jest katalogiem</em>) - błąd
+            występuje w momencie gdy probujemy użycie pliku jak katalogu lub
+            katalogu jak pliku.</li>
+          <li><strong>No space left on device</strong> (<em>brak miejsca w 
+            urządzeniu</em>) - Na pamięci masowej, której próbujemy zapisać
+            dane brakuje wolnego miejsca.</li>
+          <li><strong>Permission denied</strong> 
+            (<em>niewystarczające uprawnienia</em>) - pojawienie się tego błędu
+            może mieć dwa powody, pierwszy to zapis lub odczyt informacji z
+            pliku, do którego nie mamy żadnych uprawnień; drugim jest próba
+            uruchomienia pliku/programu bez ustawionego bitu wykonania. O
+            uprawnieniach będzie w dalszej części tego rodziału.</li>
+          <li><strong>Operation not permitted</strong> (<em>brak zezwolenia
+            na wykonanie operacji</em>) - błąd występuje w momencie gdy
+            spróbujemy zakończyć proces nie należący do nas.</li>
+          <li><strong>Segmentation fault</strong> (<em>błąd segmentacji</em>) - 
+            błąd programisty. Program, który uruchomiliśmy próbował
+            użyskać dostęp do wycinka pamięci, którego nie miał żadnych
+            uprawnień i jego działanie zostało przerwane przez jądro. 
+            Najczęsciej polskie tłumaczenie tego błędu to
+            <em>Naruszenie ochrony pamięci</em>.</li>
+          <li><strong>Bus Error</strong></li>  (<em>błąd magistrali</em>) błąd
+            podobny do <em>Naruszenia ochrony pamięci</em>, jednak w tym
+            przypadku chodzi o dostęp do pamięci w sposób niewłaściwy, a nie
+            dostęp do innego obszaru pamięci.</li>
+        </ul>
+        <p>
+          Jeśli natrafimy na jeden z dwóch ostatnich błędów, to przyczyną mogą
+          być dane przekazane do programu, których on się nie spodziewał.
+        </p>
+        <h2 id="2.16.manipulatingprocesses">2.16. Przeglądanie procesów i
+          manipulowanie nimi</h2>
+        <p>
+          Każdy proces jest programem. Jądro pododobnie jak użytkowników 
+          procesy widzi za pomocą liczbowych identyfikator - 
+          <strong>process ID</strong> - <strong>PID</strong>. Za pomocą
+          polecenia <strong>ps</strong> możemy wylistować wszystkie procesy
+          uruchomione w powłoce. Domyślnie wynik polecenia podzielony jest na
+          cztery kolumny.
+        </p>
+        <ul>
+          <li><strong>PID</strong> - identyfikator procesu</li>
+          <li><strong>TTY</strong> - urządzenie terminala, na którym działa
+            dany proces.</li>
+          <li><strong>STAT</strong> - stan procesu, np. <strong>S</strong>
+            oznacza uśpieje procesu, zaś <strong>R</strong> - jego dzialanie.
+            Wszystkie oznaczenia znajdują się na stronie podręcznika 
+            polecenia.</li>
+          <li><strong>CMD</strong> - treść polecenia, warto jednak zaznaczyć,
+            że procesy mogą ją zmieniać.</li>
+             
+        </ul>
+        <p>
+          Polecenie <em>ps</em>, możemy obsługiwać za pomocą opcji zapisanych w
+          trzech stylach, jednak najbardziej powszechnym jest styl BSD, i to
+          zapis opcji w tym stylu przedstawie.
+        </p>
+        <ul>
+          <li><strong>ps x</strong> - wyświetla wszystkie procesy uruchomione
+            przez aktualnego użytkownika.</li>
+          <li><strong>ps ax</strong> - wyświetla wszystkie procesy działące
+            w systemie.</li>
+          <li><strong>ps u</strong> - wyświetla bardziej szczegółowe informacje
+            o procesach.</li>
+          <li><strong>ps w</strong> - podaje pełne nazwy poleceń, nie
+            ograniczając się do pojedyńczego wiersza.</li>
+        </ul>
+        <p>
+          Tak jak w przypadku innych poleceń, w poleceniu <em>ps</em>, również
+          możemy łączyć opcje, dla przykładu chcąc wyświetlić wszystkie
+          procesy w systemie wraz ze szczegółami należy wydać polecenie
+          <code class="code-inline">ps aux</code>.
+        </p>
+        <p>
+          Wyświetlenie informacji na temat, konkertnych procesów polega na
+          podaniu po opcjach identyfikatora procesu. 
+        </p>
+        <h3 id="2.16.1.processkilling">2.16.1. Przerywanie działania procesów</h3>
+        <p>
+          Możemy zakończyć działanie procesu poprzez wysłanie do niego
+          <strong>sygnału</strong> za pomocą polecenia <strong>kill</strong>.
+          Wykorzystują to polecenie, jądro systemu proszone jest wysłanie 
+          sygnału do wybranego procesu. Domyślnie wysyłanym sygnałem jest 
+          <strong>TERM</strong>, a polecenie do swojego działania potrzebuje
+          tylko identyfikatora <em>PID</em>. 
+        </p>
+        <p>
+          Proces możemy zatrzymać wysyłając do niego sygnał <strong>STOP</strong>.
+          po nazwie sygnału podajemy <em>PID</em>, tak zatrzymany proces da się
+          wznowić za pomocą sygnału <strong>CONT</strong>. Nazwy sygnałów
+          podajemy po myślniku (<strong>-</strong>).
+        </p>
+        <p>
+          Naciśnięcie kombinacji <em>Ctrl+c</em> podczas działania programu w
+          powłoce, jest równoznaczne z wysłaniem sygnału <strong>INT</strong>
+          (ang. <em>Interrupt</em> - przerwanie).
+        </p>
+        <p>
+          Jedną z metod zakończenia procesu jest natychmiastowe zakończenie
+          jego pracy oraz usunięcie go siłą z pamięci, jest to osiągalne
+          poprzez wysłanie do niego sygnału <strong>KILL</strong>. Jest to
+          ostateczność, gdy dany proces nie odpowiada na inne sygnały. Inne
+          sygnały dają procesom możliwość poprzątania po sobie.
+        </p>
+        <p>
+          Oczywiście nie należy przerywać pracy dowolnym procesom, kiedy nie
+          wiemy co robią.
+        </p>
+        <h3 id="2.16.2.jobcontol">2.16.2. Kontrola zadań</h3>
+        <p>
+          Powłoki posiadają mechanizm dzięki, któremu możemy zatrzymywać oraz
+          wznawiać prace procesów za pomocą kombinacji <em>Ctrl+z</em> oraz
+          poleceniami <strong>fg</strong>, <strong>bg</strong>. Ten mechanizm
+          nazywa się <strong>kontolą zadań</strong>. Podczas działania procesu
+          w powłoce, możemy wysłać sygnał <strong>TSTP</strong> (podobny do
+          sygnału STOP), a następnie kiedy zechcemy do niego wrócić to
+          wystarczy wydać polecenie <em>fg</em>, które wznowi działanie
+          polecenia w terminalu, lub polecenia <em>bg</em> wznawiającego
+          działanie procesu w tle.
+        </p>
+        <p>
+          Podobne działanie ma program <em>GNU Screen</em>, który jest
+          multiplekserem terminala, a co najlepsze jesteśmy wstanie odłączyć
+          sesję programu od pierwszego planu i pozostanie ona w
+          niezmienionej postaci, tak długo jak włączony jest komputer.
+        </p>
+        <h3 id="2.16.3.processinbg">2.16.3. Procesy działające w tle</h3>
+        <p>
+          Uruchamiając polecenie w powłoce dostęp do znaku zachęty, a co za tym
+          idzie wolnego wiersza polecenia otrzymujemy dopiero po zakończeniu
+          działania programu. Jednak możemy odłożyć wykonanie polecenia do tła,
+          poczym od razu uzyskamy dostęp znaku zachęty. Jest to przydatna
+          funkcją, gdy uruchamiamy polecenie, którego wykonanie może
+          zająć trochę czasu. Wykonanie odkładamy do tła dopisując
+          ampersand (<strong>&amp;</strong>) na końcu polecenia (jako ostatni
+          argument). Działanie takiego programu
+          może trwać nawet po naszym wylogowaniu. Jeśli proces zakończy
+          działanie zostaniemy o tym poinformowani.
+        </p>
+        <p>
+          Problem związanym z procesami działającymi w tle jest, możliwe
+          pobieranie informacji z standardowego wejścia. Jeśli nie
+          przewidzieliśmy takiego zachowania programu, to wówczas może zostać
+          on zatrzymany lub zakończony. Można go wznowić za pomocą polecenia
+          <em>fg</em> o ile został zatrzymany. Innym problemem jest wypisywanie
+          danych przez proces w tle na standardowe wyjście oraz strumień błędów.
+          Przed uruchomieniem takiego polecenia należy przekierować te
+          strumienie, ponieważ podczas pracy w terminalu z innymi aplikacjami
+          dane ze strumieni mogą zaburzać ich wyświetlanie. Jeśli powłoka 
+          będzie dziwnie się zachowywać, wystarczy wydać polecenie 
+          <strong>reset</strong> i wszystko wróci do normy.
+        </p>
+        <h2 id="2.17.filemodandpermissions">2.17. Tryb pliku i uprawnienia</h2>
+        <p>
+          Każdy plik na Uniksie (więc na Linuksie też), posiada komplet
+          <strong>uprawnień</strong> określajacy czy można go odczytać, 
+          zapisać do niego lub go
+          uruchomić. Pierwsza kolumna wyniku polecenia <code class="code-inline">ls -l</code>
+          zawiera tryb pliku. Dane trybu możemy podzielić na cztery części
+          <strong>Typ</strong>, <strong>Uprawnienia użytkownika (właściciela)</strong>,
+          <strong>Uprawnienia grupy</strong>, <strong>Uprawnienia pozostałych
+          użytkowników.</strong>.
+        </p>
+        <p>
+          Pierwszy znak to typ pliku, jesli występuję w nim myślnik (<strong>-</strong>),
+          to mamy doczynienia ze zwykłym plikiem, innym typem pliku może być
+          litera <strong>d</strong> oznaczająca katalog.
+        </p>
+        <p>
+          Pozostałe znaki, definiują uprawnienia. Dzieli się je na trzy grupy
+          wypisane powyżej, po trzy znaki na każdą z nich. W grupie (zestawie
+          uprawnień, przeznaczonym dla konkretnej grupy lub osoby) mogą
+          wystąpić 4 rodzaje znaków.
+        </p>
+        <ul>
+          <li><strong>r</strong> - oznacza, że plik można czytać.</li>
+          <li><strong>w</strong> - oznacza, że do pliku można pisać.</li>
+          <li><strong>x</strong> - oznacza, że plik można uruchomić.</li>
+          <li><strong>-</strong> - oznacza, brak uprawnienia.</li>
+        </ul>
+        <p>
+          Mówiąc o użytkowniku w pierwszym rodziale, wspomniałem że może być
+          on właścicielem pliku i do niego należy pierwszy zestaw uprawnień.
+          Drugi zestaw określa uprawnienia dla grupy, jaka została przypisana
+          temu plikowi, z tych uprawnień będzie korzystać każdy użytkownik tej
+          grupy, próbujący uzyskać dostęp do pliku. Trzeci grupa, należy do
+          pozostałych użytkowników systemu. Użytkownika <em>root</em> nie
+          obejmują żadne z powyższych grup, choć to może zależć od konfiguracji
+          systemu, mimo to superużytkownik może sobie zmieniać dowolnie
+          uprawnienia.
+        </p>
+        <p>
+          Nie wymieniony na powyższej liście dodatkowym bitem (o uprawnieniach
+          możemy mówić jak o bitach, np. "potrzebuje bitu odczytu aby odczytać
+          dane z pliku") jest bit <strong>s</strong> - wybierz identyfikator
+          użytkownika. Pojawia się on zamiast bitu wykonywania <em>x</em> i
+          tyczy się wyłącznie plików wykonywalnych. Programy z ustawionym tym
+          bitem zawsze uruchamiają się z uprawnieniami ich właściciela bez
+          znaczenia, kto uruchamia ten program. Wiele programów korzysta z tego
+          rozwiązania, aby uzyskać uprawnienia superużytkownika i móc zapisywać
+          dane w różnych plikach systemowych.
+        </p>
+        <h3 id="2.17.1.modifypermissions">2.17.1. Modyfikacja uprawnień</h3>
+        <p>
+          Do zamiany uprawnień wykorzystamy polecenie <strong>chmod</strong>,
+          jako pierwszy podaje się zbiór uprawnień, a następnie bit uprawnienia
+          ze znakiem "+" jeśli chcemy dodać ten bit lub "-" jeśli chcemy ten 
+          bit
+          usunąć. Zbiór uprawnień podajemy za pomocą pierwszych liter 
+          angielskich
+          nazw <strong>u</strong> (ang. <em>user</em>)- użytkownika/właściciel,
+          <strong>g</strong> (ang. <em>group</em>) - grupa, 
+          <strong>o</strong> (ang. <em>others</em>)- pozostali użytkownicy 
+          systemu.
+        </p>
+<pre class="code-block">
+$ chmod go+r test.sh
+</pre>
+        <p>
+          Zbiory uprawnień można łączyć ze sobą, tak jak na powyższym
+          przykładzie lub jeśli chcemy dodać bit do wszystkich zbiorów to
+          możemy je pominąć jak na poniższym przykładzie.
+        </p>
+<pre class="code-block">
+-rw-r--r-- 1 xf0r3m xf0r3m 26 03-08 13:13 test.sh
+$ chmod +x test.sh
+-rwxr-xr-x 1 xf0r3m xf0r3m 26 03-08 13:13 test.sh
+</pre>
+        <p>
+          Przy plikach osobistych, nie warto dawać za dużych oprawnień
+          pozostałym użytkownikom. Chociaż obecnie może mieć to jedynie
+          znaczenie, gdy z serwera korzysta wielu wyspecjalizowanych 
+          użytkowników.
+        </p>
+        <p>
+          Innym sposobem na zmianę uprawnień jest użycie liczb, gdzie każda
+          z trzech liczb określa uprawnienia dla jednego zbioru. Liczby te są
+          sumami bitów, które reprezentowane są przez poszczególne wartości.
+        </p>
+        <ul>
+          <li><em>r</em> - <strong>4</strong></li>
+          <li><em>w</em> - <strong>2</strong></li>
+          <li><em>x</em> - <strong>1</strong></li>
+          <li><em>-</em> - <strong>0</strong></li>
+        </ul>
+<pre class="code-block">
+$ chmod 644 test.sh 
+</pre>
+        <p>
+          Uprawnienia właściciela mają wartość <code class="code-inline">6</code>.
+          co jest równe <em>4+2</em> - <em>u+rw</em>, grupa oraz pozostali mają
+          <code class="code-inline">4</code> co jest identyczne z zapisem
+          <em>go+r</em>. Liczby wykorzysywane tutaj pochodzą z oktalnego 
+          systemu liczbowego. 
+        </p>
+        <p>
+          Zmiana uprawnień nosi nazwę <strong>bezwzględnej</strong>, ponieważ
+          zmieniane są uprawnienia wszystkich grup.
+        </p>
+        <p>
+          Odnośnie uprawnień to istnieje bardzo ważna zależność pomiędzy bitami
+          odczytu oraz wykonania. Nadając katalogowi domowemu uprawnienia
+          <em>rwxr--r--</em> czy <em>744</em>. Pozostali użytkownicy będą
+          mogli odczytać zawartości katalog, ale nie uzyskają dostępu do pliku
+          podając go w jakimś poleceniu na ścieżce, do tego potrzebny jest 
+          jeszcze bit wykonania. 
+        </p>
+        <p>
+          Za pomocą polecenia <strong>umask</strong>, możemy zdefiniować
+          domyślne uprawnienia dla plików. Polecenie to przyjmuje jako 
+          argument te uprawnienia w postaci bezwględnej, które mają zostać
+          usunięte z nowoutworzonych plików i katalogów. Wydanie polecenia
+          umask:
+        </p>
+<pre class="code-block">
+$ umask 022
+</pre>
+        <p>
+          Spowoduje, że nowoutworzone pliki i katalogi będą mięc uprawnienia
+          w postaci <em>rwxr-xr-x</em> lub <em>755</em>. Może wydawać się zbyt
+          liberalne, więc możemy ustawić argument polecenia nas <em>077</em>, 
+          wówczas
+          wszystkie utworzone pliki i katalogi będą wyłącznie dla nas. 
+          Polecenie
+          <em>umask</em>, czesto występuje w plikach konfiguracyjnych powłoki.
+        </p>
+        <h3 id="2.17.2.symlinks">2.17.2. Dowiązania symboliczne</h3>
+        <p>
+          Dowiązanie syboliczne to jest alias będący plikiem wskazującym na
+          inny pliki lub katalog. Można uciec się do jednego słowa, że
+          dowiązanie symboliczne jest poprostu skrótem.
+        </p>
+        <p>
+          Jeśli dowiązanie wskazuje na katalog, to przejście do dowiązania
+          przeniesie nas w miejsce, na które wskazuje. Cel dowiązania nie
+          musi nawet istnieć, jeśli jednak spróbuje przejść pod takie
+          dowiązanie wówczas uzyskamy typowy błąd, o tym że katalog nie
+          istnieje. Dowiązania uniemożliwają również sprawdzenie 
+          charakterystyki
+          wskazywanego elementu, nie będzie wiadomo czy jest to plik, katalog
+          czy inne dowiązanie. Wiele połączonych ze sobą dowiązań symbolicznych
+          nazywane jest <strong>łańcuchem dowiązań</strong>
+        </p>
+        <p>
+          Dowiązania symboliczne tworzone są za pomocą polecenia <strong>ln</strong>
+          z opcją <strong>-s</strong> (<strong>Ważne, aby użyć tej opcji</strong>).
+          Argumentami jest na początku <strong>cel</strong> a poźniej nazwa
+          dowiązania. Zachowanie kolejności argumentów jest ważne, ponieważ
+          możemy utworzyć dowiązanie, które prowadzi do nikąd i wprowadza
+          bałagan (być może w plikach systemowych).
+        </p>
+        <p>
+          Mimo swoich wad dowiązanią są wygodną metodą na współdzielenie plików
+          oraz dodatkowo rozwiązują kilka drobnych problemów.
+        </p>
+        <h2 id="2.18.archivesandcompression">2.18. Archiwizowanie i
+        kompresowanie danych</h2>
+        <p>
+          Przesyłając duża ilość małych plików przez sieć czy tez na pamięć
+          masową, możemy odczuć że trwa to wieki, na pewno trwa to dłużej niż
+          przesłanie jednego dużego pliku. Tutaj przedstawię sposoby na
+          stworzenie
+          jednego większego pliku z całego katalogu, przy czym użyjemy jeszcze
+          kilku algorytmów kompresii, przez co zaoszczędzimy na czasie i trochę
+          na zajmowanym miejscu. 
+        </p>
+        <h3 id="2.18.1.tarprogram">2.18.1. Program tar</h3>
+        <p>
+          Pierwsze narzędzie będzie służyć do tworzenia archiwum. Archiwa
+          łączą pliki i katalogi w jeden plik. <strong>Tar</strong> jest 
+          standardowym program do archiwizacji na uniksach. 
+          Tworzenie archwium za pomocą <em>tar</em> wymaga kilku
+          opcji. Natomiast składania polecenia jest następująca:
+        </p>
+<pre class="code-block">
+$ tar -cvf archiwum.tar plik1 plik2...
+</pre>
+        <p>
+          Opcja <code class="code-inline">-c</code> mówi programowi, że
+          tworzone będzie nowe archiwum, opcja <code class="code-inline">-v</code>
+          włącza komunikaty diagnostyczne wyświetlać one będą po kolei pakowane
+          do archiwum pliki; opcja <code class="code-inline">-f</code>
+          przekazuje programowi informacje o tym, że archwium będzie plikiem.
+          Domyślnie <em>tar</em> tworzył archiwa na taśmach. Obecnie pominięcie
+          tej opcji kończy pracę programu z komunikatem o błędzie. Możemy 
+          natomiast użyć <em>stdout</em> podajac zamiast nazwy archiwum
+          myślnik (<strong>-</strong>). Póki co to archiwum nie jest jeszcze 
+          skompresowane.
+        </p>
+        <h4>Rozpakowywanie pliku</h4>
+        <p>
+          Rozpakowawanie różni się tylko jedną opcją - zamiast <em>-c</em> jest
+          <strong>-x</strong>. Następnie podajemy pozostałe opcje, a na końcu
+          nazwę pliku archiwum.
+        </p>
+        <h4>Wyświetlenie zawartości archiwum</h4>
+        <p>
+          Wypakowanie całego archiwum może nie być do końca porządane, załóżmy
+          że potrzebujemy tylko jednego pliki. Za pomocą polecenia <em>tar</em>
+          z odpowiednim przełącznikiem możemy wyświetlić listę plików w 
+          archiwum. Zamiast <em>-x</em>, używamy
+          <strong>-t</strong> reszta pozostaje taka sama, jeśli archiwum jest
+          duże to możemy podłączyć wyjście <em>tar</em> potokiem do polecenia
+          <em>less</em>. Samego wypakowania dokonujemy podając wypakowywanego
+          pliku za nazwą archiwum.
+        <p>
+        <p>
+          Ostanią dość istotną opcję jest <strong>-p</strong>, która powoduje
+          zachowanie oryginalnych atrybutów plików, jakie miały podczas
+          pakowania. Kiedy superużytkownika używa <em>tar</em>, ta opcja jest
+          domyślnie włączona.
+        </p>
+        <h3 id="2.18.2.gzipprogram">2.18.2. Program gzip</h3>
+        <p>
+          Program <strong>gzip</strong> (<em>GNU zip</em>) jest standardowym 
+          narzędziem kompresującym w systemach uniksowych. Pliki skompresowane
+          za jego pomocą otrzymują rozszerzenie <strong>.gz</strong>.
+          Dekompresuje się je za pomocą polecenia <strong>gunzip</strong>, jako
+          argument podaje się nazwę pliku. Natomiast kompresji dokonuje za
+          pomocą polecenia <strong>gzip</strong>, podając plik do 
+          skompresowania jako argument. 
+        </p>
+        <h3 id="2.18.3.compressedarchives">2.18.3. Skompresowane archiwa
+          <em>tar.gz</em></h3>
+        <p>
+          Obsługę skompresowanych archwów przy użyciu <em>gzip</em>,
+          rozpoczniemy od rozpakowania takiego archiwum. Nie ma sensu używania
+          do tego dwóch osobnych poleceń, jest to z resztą marnowanie zasobów.
+          Chcąc rozpakować skompresowane <em>gzip</em> archiwum, należy użyć
+          polecenia <em>tar</em> a po opcji
+          <em>-x</em> dodać, opcję <em>-z</em> następnie pozostałe czyli
+          <em>-vf</em> i na końcu podać nazwę archiwum. Tak jak na przykładzie: 
+        </p>
+<pre class="code-block">
+$ tar -xzvf archiwum.tar.gz
+</pre>
+        <p>
+          Przy tego typu archiwach, możemy spodziewać się rozszerzenia
+          <strong>.tgz</strong>. Są to te same archiwa, jak te mające 
+          rozszerzenie <em>tar.gz</em>.
+        </p>
+        <p>
+          Przy wyświetlaniu zawartości takiego archiwum, zamieniamy opcję
+          <strong>-x</strong> na <strong>-t</strong>. A chcąc takie archwiwum
+          utworzyć to opcję <strong>-x</strong> na opcję <strong>-c</strong>
+          oraz podać katalog lub listę plików, która ma zostać umieszczona w
+          archiwum po jego nazwie.
+        </p>
+        <h3 id="2.18.4.othercompression">2.18.4. Inne metody kompresji</h3>
+        <p>
+          Poza archiwami spakowanymi za pomocą <em>gzip</em>, możemy też
+          spotkać archiwa spakowane za pomocą <strong>bzip2</strong> oraz
+          <strong>xz</strong>. W przypadku <em>bzip2</em>, to programem
+          dekompresującym jest <strong>bunzip2</strong>, a opcją programu
+          <em>tar</em> jest <strong>-j</strong> (mała litera j). Jeśli
+          natrafimy na archiwum skompresowane <em>xz</em>, to programem
+          dekompresującym jest <strong>unxz</strong>, a opcją programu
+          <em>tar</em> jest <strong>-J</strong> (wielka litera j). 
+        </p>
+        <p>
+          Część dystrybucji wyposażona jest w program <em>unzip</em>
+          pozwalający na rozpakowanie plików <em>.zip</em> przygotowanych
+          pod systemem MS Windows, jak i samo rozpakowywujących się plików
+          <em>.exe</em>. 
+        </p>
+        <h2 id="2.19.filesystemhierarchy">2.19. Hierarchia katalogów</h2>
+        <p>
+          Struktura katalogów głównego, jest utworzona na
+          podstawie <strong>standardu hierarchii systemu plików</strong>,
+          określającego jakie podkatalogi ma zawierać katalog główny, oraz
+          co te podkatalogi mają przechowywać. Poniżej opisano na ten czas
+          najważniejsze z nich.
+        </p>
+        <ul>
+          <li><strong>/bin</strong> - przechowuje pliki binarne przygotowane
+            przez kompilator języka C, w nowocześniejszych systemach mogą to 
+            być
+            skrypty powłoki. W nim przechowywane są te najprostsze polecenia
+            jak <em>cp</em>.</li>
+          <li><strong>/dev</strong> - przechowuje pliku urządzeń.</li>
+          <li><strong>/etc</strong> - katalog zawierający najważniejsze pliki
+            konfiguracji systemu. Znajdują się tutaj pliki haseł, konfiguracji
+            uruchamiania systemu, urządzeń, sieci i innych elementów systemu.</li>
+          <li><strong>/home</strong> - zbiorczy katalog, katalogów domowych
+            użytkowników. Standard wśród wszystkich nowoczesnych uniksów.</li>
+          <li><strong>/lib</strong> - katalog przechowywujący biblioteki.
+            Te pliki przechowują kod, który może być wykorzystywany przez 
+            pliki wykonywalne. Biblioteki możemy podzielić na statyczne lub
+            współdzielone. Tylko biblioteki współdzielone powinny znajdować
+            się w tym katalogu, pozostałe pliki tego typu znajdują się
+            w katalogu <em>/usr/lib</em>.</li>
+          <li><strong>/proc</strong> - udostępnia statystyki o systemie w 
+            postaci interfejsu plików i katalogów.
+          </li>
+          <li><strong>/sys</strong> - ten katalog jest podobny do katalogu
+            <em>/proc</em>, z tym, że tworzy interfejs dla urządzeń oraz
+            systemu. Wiecej informacji na ten temat, znajduje się w następnym
+            rozdziale.
+          </li>
+          <li><strong>/sbin</strong> - w tym katalogu zapisane są systemowe
+            pliki wykonywalne. Programy znajdujące się w katalogach
+            <em>/sbin</em> przeznaczone są do zarządzania systemem, dlatego
+            ten katalog nie występuje na ścieżce zwykłego użytkownika a wiele
+            narzędzi będzie działać tylko z kontem <em>root</em>.
+          </li>
+          <li><strong>/tmp</strong> - w tym katalogu możemy umieszczać pliki
+            tymczasowe, którymi nikt się nie będzie przejmować. Każdy
+            użytkownik może zapisywać i odczytywać pliki z katalogu w tym
+            katalogu, ale nikt nie ma dostępu do plików zapisanych przez innych
+            użytkowników. Nie które programy wykorzystują, ten katalog jako
+            przestrzeń roboczą. Nie należy zapisywać ważnych danych do tego
+            katalogu, gdyż jego zawartość jest przez wiekszość dystrybucji 
+            czyszczona podczas uruchamiania systemu, inne mogą usuwać 
+            starsze pliki co jakiś czas.</li>
+          <li><strong>/usr</strong> - W tym katalogu znajdziemy rozbudowaną,
+            strukturę katalogów, bardzo podobną to katalogu głównego. W tym
+            katalogu zapisana jest większa części systemu Linux.</li>
+          <li><strong>/var</strong> - podkatalog zawierający "zmienne" dane
+            zapisywane przez programy w czasie swojego działania. Tutaj 
+            znajdują się m.in. pliki dzienników systemowych.</li>
+        </ul>
+        <h3 id="2.19.1.othermainsubdirs">2.19.1. Pozostałe katalogi główne</h3>
+        <ul>
+          <li><strong>/boot</strong> - przechowuje plik ładujące jądro systemu
+          w czasie uruchamiania komputera. W większości dystrybucji w tym
+          katalogu przechowywane są właściwe pliki jądra oraz początkowego
+          systemu plików w pamięci RAM. Początkowy system plików pamięci RAM
+          zostanie omówiony w dalszej materiału.</li>
+          <li><strong>/media</strong> - w wielu dystrybucjach jest to główny
+          punkt przyłączania wszystkich mediów wymiennych, takich jak
+          karty pamięci Flash.</li>
+          <li><strong>/opt</strong> - może przechowywać dodatkowe
+          oprogramowanie firm trzecich. W wielu systemach katalog <em>/opt</em>
+          nie jest wykorzystywany.</li>
+        </ul>
+        <h3 id="2.19.2.usrdirectory">2.19.2. Katalog /usr</h3>
+        <p>
+          To właśnie w katalogu <em>/usr</em> znajduje się większość programów
+          i danych przestrzeni użytkownika, a są one rozlokowane po jego
+          podkatalogach. Poniżej znajduje się opis co znajduje się w 
+          poszczególnych podkatalogach tego katalogu:
+        </p>
+        <ul>
+          <li><strong>bin</strong> - większość, jak nie wszystkie
+            ogólnodostępne programy w systemie.</li>
+          <li><strong>include</strong> - przechowuje pliki nagłówkowe
+            wykorzystywane przez kompilator języka C.</li>
+          <li><strong>info</strong> - zawierają strony dokumentacji
+            <em>GNU</em> info.</li>
+          <li><strong>local</strong> - miejsce gdzie administratorzy mogą
+            mogą instalować swoje oprogramowanie, katalog ten może zawierać
+            podobną identyczną strukturę, jak katalog <em>/usr</em> lub
+            katalog główny.</li>
+          <li><strong>man</strong> - przechowuje strony podręcznika
+            systemowego.</li>
+          <li><strong>share</strong> - kiedyś ten katalog był katalogiem
+            współdzielonym między komputerami, obecnie stracił na znaczeniu.
+            Mimo to dalej przechwouje informacje, przeważnie są to pliki ikon, 
+            pliki zawierające znaki
+            towarowe dystrybucji oraz inne dane z których może korzystać wiele
+            programów. Ten katalog może zawierać podkatalogi takie jak
+            <em>man</em> oraz <em>info</em>.</li>
+        </ul>
+        <h3 id="2.19.3.kernelplace">2.19.3. Umiejscowanie jądra w systemie</h3>
+        <p>
+          Wspomniałem już że plik jądra znajduje się w katalogu <em>/boot</em>,
+          plik ten rozpoczyna się od nazwy <strong>vmlinuz</strong>, po tych
+          znakach
+          mogą wystąpić inne inforamcje oznaczające jego wersje. Po załadowaniu
+          jądra przez program rozruchowy, sam plik przestaje być
+          potrzebny. W trakcie pracy systemu operacyjnego jądro wykorzystuje
+          najróżniejsze ładowane i usuwane dodatkowo modułu. <strong>Ładowane
+          moduły jądra</strong> umieszczane są w katalogu <em>/lib/modules</em>.
+        </p>
+        <h2 id="2.20runitasroot">2.20. Uruchamianie poleceń przez superużytkownika</h2>
+        <p>
+          Korzystając z linuksa na naszym osobistym komputerze, przyjdzie taki
+          moment że będziemy musieli skorzystać z konta użytkownika 
+          <em>root</em>. Aby to zrobić możemy przelogować się na jego konto
+          wykonać potrzebne czynności a następnie się wylogować. Ta czyność
+          przyniosła by zamierzony efekt ale nie jest bez wad. Dlatego też
+          możemy skorzystać z polecenia <strong>sudo</strong>, które
+          pozwoli, na uruchomienie polecenia podanego jako arugment 
+          z uprawnieniami
+          superużytkownika. Jeśli polecenie nie występuje w systemie, to jest
+          dobry czas aby przelogować się na użytkownika <em>root</em>, i je
+          zainstalować. Polecenie po zainstalowaniu nie zadziała samo w sobie
+          potrzebne jest jeszcze określenie, którzy użytkownicy mogą używać
+          tego polecenia i co za jego pomocą mogą zrobić. Za to odpowiada
+          pliki <strong>/etc/sudoers</strong>.
+        </p>
+        <h3 id="2.20.1.sudoersfile">2.20.1. Plik /etc/sudoers</h3>
+        <p>
+          Samo polecenie sudo ma bardzo duża ilość opcji, jednak na tym
+          etapie nie skorzystamy z większości z nich. Najprostszym sposobem
+          na konfiguracje pliku <em>/etc/sudoers</em> jest odnalezienie w pliku
+          linii rozpoczynającej się pod słowa <em>root</em> a następnie
+          pod tą linią wpisać linię rozpoczynjącą się nazwy użytkownika oraz
+          dopisaniu kilku opcji, tak jak na poniższym przykładzie.
+        </p>
+<pre class="code-block">
+user ALL=(ALL) ALL
+</pre>
+        <p>
+          Pierwsze <code class="code-inline">ALL</code>, oznaczna dowolny
+          komputer. Drugie
+          <code class="code-inline">(ALL)</code> w nawiasach oznacza, że możemy
+          wydać polecenie jako dowolny użytkownik, być może spotkamy się
+          z takim zapisem w nawiasie (<em>ALL:ALL</em>), oznacza ono dowolnego
+          użytkownika i dowolną grupę. Trzecie <code class="code-inline">ALL</code>
+          oznacza dowolne polecenie.
+        </p>
+        <p>
+          Jeśli drażnić nas będzie ciągłe wpisywanie haseł, to możemy przed
+          trzecim <em>ALL</em> w konfiguracji umieścić opcję 
+          <strong>NOPASSWD</strong>, pamiętając aby pomiędzy te opcje wstawić
+          dwukropek (<strong>:</strong>) bo tak naprawdę określamy jakie
+          polecenia mają być uruchamiane bez podawania hasła.
+        </p>
+        <h2 id="2.21.summary">2.21. Podsumowanie</h2>
+        <p>
+          Po przeczytaniu tego rodziały wydaje mi się, że każdy ma solidne
+          podstawy obsługi systemu Linux z poziomu powłoki. Powłoka jest
+          jednym ze stałych komponentów dystrybucji, a wiele z nich dalej
+          obstaje przy BASH-u, jako domyślnej powłoce.
+        </p>
+        <h1 id="3.devices">3. Urządzenia</h1>
+        <p>
+          Odkąd powstał system Linux, w sposobach prezentowania urządzeń
+          użytkownikowi zachodziło wiele zmian. Na początku tego rozdziału
+          omówimy sobie tradycjny system <strong>sysfs</strong>. Aby potem
+          zająć się omówieniem systemu <strong>udev</strong>, pozwalającego 
+          programom przestrzeni użytkownika automatycznie konfigurować oraz
+          używać nowych urządzeń. Podczas normalnego użytkowania systemu
+          rzadko będziemy mieć okazję do zarządzania urządzeniami. Nasza
+          interakcja z urządzeniami będzie ograniczać się do obsługi pamięci
+          masowych i korzystania najstarszego i naprostszego interfejsu jakim
+          jest katalog <em>/dev</em>. Mimo to, warto jednak wiedzieć w systemie
+          co jest od czego. 
+        </p>
+        <h2 id="3.1.devicefiles">3.1. Pliki urządzeń</h2>
+        <p>
+          Jądro udostępnia wiele urządzeń pod postacią plików, co daje nam
+          możliwość prostej manipulacji nimi. Te pliki są często nazywane
+          <strong>węzłami urządzeń</strong>. Korzystać z urządzeń możemy
+          za pomocą zwykłych operacji na plikach. Tego typu rozwiązanie nie
+          jest bez wad dlatego też nie wszystkie urządzenia lub ich funkcje
+          są udostępnianie w ten sposób.
+        </p>
+        <p>
+          Pliki urządzeń są przechowywane w katalogu <strong>/dev</strong>.
+          A najprostszym sposobem interakcji z urządziem jest przekierowanie
+          wyniku jakiegoś polecenia do urządzenia <strong>/dev/null</strong>.
+          Urządzenie to jest miejscem na nie potrzebne nam dane ze strumieni,
+          ponieważ cokolwiek trafi do tego urządzenia, jest przez jądro
+          poprostu ignorowane.
+        </p>
+        <p>
+          Wyświetlając sobie zawartość katalogu w bardziej szczegółowej liście
+          może zauważyć dziwne oznaczenia w trybie pliku. Litery te określają
+          rodzaje urządzeń a wśród nich możemy wyszczególnić:
+        </p>
+        <ul>
+          <li><strong>Urządzenia blokowe - b</strong> - Procesy mogą odczytywać
+            dane z urządzeń blokowych przy użyciu bloków o stałej wielkości.
+            Pamięci masowe są przykładem urządzeń blokowych. Łatwo dzieli się 
+            je na bloki, a ogólna wielkość
+            takiego urządzenia jest stała i można ją zindeskować, co daje
+            możliwość jądru na dostępu do dowolnego bloku danych.</li>
+          <li><strong>Urządzenia znakowe - c</strong> - Urządzenia znakowe
+            działają w oparciu o strumienie danych. Do takich urządzeń można
+            zapisywać i odczytywać pojedyńcze znaki. Jądro zazwyczaj wykonuje
+            operacje odczytu i zapisu na fizycznym urządzeniu. Drukarki są 
+            przykładami urządzeń znakowych. Warto wspomnieć, że jądro nie
+            jest w stanie ponownie odczytać danych ze strumienia po przekazaniu
+            ich dalej do procesu.</li>
+          <li><strong>Urządzenia potokowe - p </strong> - tzw.
+            <strong>nazwane potoki</strong> są to urządzenia podobne do
+            urządzeń znakowych z tą jednak różnicą, że na drugim końcu
+            strumienia wejścia-wyjścia nie znajduje się fizyczne urządzenia ale
+            inny proces.</li>
+          <li><strong>Urządzenia gniazdkowe - s</strong> - tzw. <strong>gniazda</strong>
+            są interfejsami specjalnego przeznaczenia i służa komunikacji
+            międzyprocesowej. Mogą występować poza katalogiem <em>/dev</em>.</li>
+        </ul>
+        <p>
+          Inną dość rzucającą się w oczy informacją na listingu katalogu, są
+          dwie liczy odzielone przecinkiem zamiast rozmiaru pliku, jest
+          <strong>numer główny</strong> i <strong>numer poboczny</strong>.
+          Te numer ułatwiają jądru identyfikacje urządzeń. Dla przykładu
+          partycje tego samego dysku mają ten sam <em>numer główny</em> ale
+          inny <em>numer poboczny</em>.  
+        </p>
+        <p>
+          Nie wszystkie urządzenia mają swoje pliki, takim przykładem są
+          interfejsy sieciowe. Jądro wykorzystuje dla nich inny interfejs
+          wejścia-wyjścia.
+        </p>
+        <h2 id="3.2.sysfsdevicepath">3.2. Ścieżka urządzeń sysfs</h2>
+        <p>
+          Ze względu na uproszczoną interakcje z urządzeniami poprzez 
+          odwołowywanie się do pliku w katalogu <em>/dev</em> oraz fakt, że
+          jądro systemu nadaje plikom z tego katalogu nazwy na podstawie
+          koleności wykrywania urządzeń podczas uruchamiania systemu,
+          wewnątrz jądra zaimplementowano interfejs <strong>sysfs</strong>.
+          <em>Sysfs</em> jest ujednoliconym sposobem prezentacji urządzeń 
+          bazującym
+          na atrybutach sprzętowych, mający formę struktury katalogów i plików.
+          Główny katalogiem tego systemu jest katalog <strong>/sys/devices</strong>.
+          Przykładowa ścieżka dla pierwszego dysku SATA mającego swój plik
+          <em>/dev/sda</em> może wyglądać następująco:
+        </p>
+<pre class="code-block">
+/sys/devices/pci0000:00/0000:00:1f:2/host0/target0:0:0/0:0:0:0/block/sda
+</pre>
+        <p>
+          Warto tutaj zaznaczyć iż, scieżki systemu <em>sysfs</em> nie służą 
+          uzyskaniu dostępu do urządzeń, umożliwają przeglądanie informacji
+          oraz zarządzanie urządzeniami. Dane zawarte na plikach na ścieżkach
+          <em>sysfs</em> powinny być odczytywane przez programy nie przez
+          ludzi.
+        </p>
+        <p>
+          Chcąc sprawdzić scieżkę <em>sysfs</em> dla dowolnego urządzenia z
+          katalogu <em>/dev</em> należało by uzyć programu systemu <em>udev</em>
+          <strong>udevadm</strong>.
+        </p>
+<pre class="code-block">
+$ udevadm info --query=all --name=/dev/sda
+</pre>
+        <p>
+          Wykonując to polecenie dowiemy się przy okazji ile danych można 
+          uzyskać informacji z systemu <em>udev</em>.
+        </p> 
+        <h2 id="3.3.ddcommand">3.3. Polecenie dd</h2>
+        <p>
+          Polecenie <strong>dd</strong> jest dość prostym, aczkolwiek 
+          przydatnym narzędziem jeśli
+          choodzi o prace z urządzeniami znakowymi czy blokowymi. Jedyną
+          rzeczą, którą robi to polecenie jest odczyt danych z pliku 
+          wejściowego lub ze strumienia i zapisanie go do wyjściowego pliku
+          lub strumienia, przy okazji dokonując pewnych konwersji. Najczęsciej
+          używane przeze mnie polecenie znajduje się poniżej. 
+        </p>
+<pre class="code-block">
+$ sudo dd if=/dev/zero bs=1M of=/dev/sdX count=1
+</pre>
+        <p>
+          Polecenie wykorzystuje uprawnienia superużytkownika, aby uzyskać
+          dostęp do urządzenia blokowego. Samo polecenie zapisuje jeden
+          blok o wielkości 1M za pomocą zer z pliku <em>/dev/zero</em> 
+          (nieskończony strumień zer), co powoduje usunięcie tablicy partycji
+          (o której będzie w następnym rodziale).
+        </p>
+        <p>
+          Poniżej zostaną opisane najważniejsze opcje programu <em>dd</em>,
+          ich format różni się od innych programów uniksowych. Do przypisania
+          wartości opcją używa się tutaj znaku równości (<strong>=</strong>).
+        </p>
+        <ul>
+          <li><strong>if=plik</strong> - plik wejściowy. Domyślnie stosowane
+            jest standardowe wejście.</li>
+          <li><strong>of=plik</strong> - plik wyjściowy. Domyślnie stosowane
+            jest standardowe wyjście.</li>
+          <li><strong>bs=rozmiar</strong> - rozmiar bloku danych. Polecenie
+            przesyła wiele bloków naraz, więc możemy użyć wielokrotności 
+            takich jak: bajt - <em>B</em>, kilobajt - <em>K</em>, megabajt -
+            <em>M</em>, gigabajt - <em>G</em> i tak dalej.</li>
+          <li><strong>ibs=rozmiar</strong>, <strong>obs=rozmiar</strong> - 
+            rozmiar blok wejściowego oraz bloku wyjściowego, jeśli nie możliwe
+            jest stosowanie dla plików wejściowych oraz wyjściowych tego
+            samego rozmiaru bloku.</li>
+          <li><strong>count=liczba</strong> - liczba kopiowanych bloków.</li>
+          <li><strong>skip=liczba</strong> - powoduje pominięcie pierwszych
+            <em>liczba</em> bloków danych. Nie są one kopiowane do pliku
+            wyjściowego.</li>
+        </ul>
+        <p>
+          Przy korzystaniu z <em>dd</em>, należy uważać gdyż literówka w 
+          poleceniu wystarczy, aby uszkodzić system lub spowodować utratę
+          ważnych dla nas danych.
+        </p>
+        <h2 id="3.4.namingsummary">3.4. Podsumowanie nazewnictwa urządzeń</h2>
+        <p>
+          Do pracy z urządzeniami potrzebujemy jego nazwy. W systemie istnieje
+          kilka metod pozwalających na ustalenia nazwy urządzenia.
+        </p>
+        <ul>
+          <li>Odpytanie systemu <em>udev</em>, za pomocą polecenia <em>udevadm</em>.</li>
+          <li>Przeszukanie katalogu <em>/sys</em>.</li>
+          <li>Wyświetlenie plików dziennika jądra za pomcą polecenia <em>dmesg</em>,
+              w plikach dziennika znajdują się jego ostatnie komunikaty w tym
+              informacje o znalezionych urządzenia i nadanych im nazwach.</li> 
+          <li>Jeśli to dysk i jest on widoczny w systemie to możemy skorzystać
+              z polecenia <em>mount</em>, chyba że nasz system nie montuje
+              samodzielnie partycji, to w tym przypadku możemy skorzystać z
+              polecenia <strong>fdisk</strong> z opcją <strong>-l</strong>.</li>
+          <li>Ostatni sposób działa tylko dla urządzeń blokowych oraz znakowych.
+              W katalogu <em>/proc/devices</em> znajduje się zestawienie 
+              urządzeń reprezentowanych przez <em>numer główny</em> oraz przez
+              przypisany im sterownik. Wystarczy użyć <em>numeru głównego</em>
+              jako wyrażenia regulanego i zastosować go na listingu katalogu
+              <em>/dev</em>.</li>
+        </ul>
+        <p>
+          Dzisiaj praca z urządzeniami na Linuksie sprowadza się głównie do
+          partycjonowania dysku, więc aby znależć właściwe urządzenie wystarczy
+          użyć polecenia <em>fdisk -l</em>.
+        </p>
+        <p>
+          Na poniższej liście znajdują się najczęściej wykorzystywane na
+          Linkusie konwencje nazwenicze.
+        </p>
+        <ul>
+          <li><strong>Dyski twarde SATA - /dev/sd*</strong> - Nazewnictwo
+            dysków pochodzi od protokołu SCSI, mimo iż same urządzenia SCSI
+            wyszły z użycia. To protokół mający świetne zdolności adaptacyjne
+            cały czas działa we współczesnych systemach. Nazwa np. <em>/dev/sda</em>
+            odnosi się do całego dysku. Partycje oznaczne są dodatkowo liczbą
+            np. <em>/dev/sda1</em>. Pamięci masowe ze złączem USB również 
+            wykorzysują podsystem SCSI do komunikacji z komputerem dla tego też
+            dyski tego typu również mogą występować jak <em>/dev/sd*</em>.</li>
+          <li><strong>Napędy CD i DVD - /dev/sr*</strong> - Napędy optyczne
+            tak samo jak dyski korzystają z SCSI. Jednak te urządzenia są tylko
+            do odczytu. Jeśli chcielibyśmy skasować zawartość płyty, lub na
+            niej coś nagrać, to należało by się odwołać do ogólnego urządzenia
+            którego nazwa może byc na przykład taka: <em>/dev/sg0</em>. Raczej
+            jednak do nagrywania płyt będziemy wykorzystywać specjalne 
+            oprogramowanie.</li>
+          <li><strong>Dyski twarde PATA - /dev/hd*</strong> - w starszych
+            wersjach jądra, dyski były przedstawione za pomocą innych nazw.
+            Obecnie dyski PATA również wykorzystują SCSI, więc ich nazwy nie
+            będą się różnić od dysków SATA.</li>
+          <li><strong>Terminale - /dev/tty1, /dev/pts/*, /dev/tty</strong> -
+            Terminale są urządzeniami przeznaczonymi do przesyłania znaków
+            pomiędzy system a urządzeniem wejscia-wyjścia, co najczęściej
+            ma celu wyświetlanie tekstu na ekranie terminala. Pseudoterminale
+            posiadają wyszystkie funkcję fizycznych terminali, jednak jądro
+            nie komunikuje się z fizycznym urządzniem, a z programowym 
+            interfejsem wejscia-wyjścia takim jak okno powłoki. Urządzenie
+            <em>/dev/tty1</em> to pierwsza wirtualna konsola, a
+            <em>/dev/pts/0</em> to pierwsze okno powłoki. Linux do działania
+            nie potrzebuje klasycznego interfejsu użytkownika, jaki znamy
+            z innych systemów operacyjnych. Nie potrzebuje okien, paska zadań,
+            menu "Start" i innych elementów graficznych. Równie dobrze może
+            działać jak system 'DOS' w tzw. <strong>trybie tekstowym</strong>.
+            Praca w tym trybie pozwala na wykorzystanie komputera znacznym
+            stopniu.
+            Jedyne czego nie będziemy w stanie zrobić to skorzystać z czego
+            kolwiek co wymaga wyświetlania graficznego wymagającego pokazania
+            na ekranie czegoś więcej niż teskt i 8 podstawowych kolorów. 
+            <strong>Tryb graficzny</strong>
+            zawiera wszystkie te rzeczy znane z innych systemów operacyjnych a
+            wymienione zostały one powyżej, choć to wszystko zależy od
+            uruchomionego menadżera okien. Pierwsza wirtualna
+            konsola jest pierwszym ekranem powłoki w trybie tesktowym, okna
+            powłoki mogą wystąpić w środowisku graficznym po uruchomieniu
+            odpowiedniego programu <em>Terminal</em> lub w przypadku trybu 
+            tesktowego multipleksera terminala. Multipleksery są powielaczami, 
+            pozwalającymi
+            podzielić konsolę na kilka mniejszych "okien", w których możemy
+            uruchomić kolejną powłokę. Zaś urządzenie <em>/dev/tty</em>, jest
+            odniesienie procesu do właściwego terminala, jeżeli program
+            odczytuje i zapisuje dane do terminala.</li>
+          <li><strong>Porty szeregowe - /dev/ttyS*</strong> - są specjalnymi
+            urządzeniami terminalowymi pozwalającymi na komunikację z różnej
+            maści sprzętem wykorzystując do tego oprogramowanie, które pozwoli
+            skonfigurowanie komunikacji. Porty szeregowe otrzymują w systemie
+            nazwy kolejno: <em>/dev/ttyS0</em> itd. w zależności od tego ile
+            mamy portów zainstalowanych w komputerze. Do połączenia za pomocą
+            portu szeregowego można wykorzystać adaptery USB, te urządzenia 
+            mogą posiadać następujące nazwy: /dev/ttyUSB* lub /dev/ttyAMC*.
+            Modemy sieci komórkowych mogą występować w systemie pod postacią
+            adapterów USB portów szeregowych.</li>
+          <li><strong>Porty równoległe - /dev/lp0, /dev/lp1</strong> - służyły
+            do podłączenia drukarek wykorzystujących port LPT. Obecenie
+            zostały zastąpione przez porty USB. Drukarki mogą wymagać
+            dodatkowych znaków sterujących, dlatego też do drukowania lepiej
+            wykorzystać serwer druku CUPS, niż pisanie bezpośrednio do tego
+            portu.</li>
+          <li><strong>Urządzenia audio - /dev/dsp, /dev/audio, /dev/snd/*</strong> -
+            Na Linuksie dostępne są dwa zestawy urządzeń odpowiadająych za
+            dźwiek. Starszy, rzadziej spotykany system <em>OSS</em>
+            korzystający z urządzeń <em>/dev/dsp</em> oraz <em>/dev/audio</em> 
+            i nowszysz spotykany w większości dystrybucji <em>ALSA</em>
+            używający urządzeń w katalogu <em>/dev/snd</em>. System dzwięku
+            na Linuksie może być dwuwartstwowy, ponieważ do dyspozycji mamy
+            serwer pośredniczący <em>PulseAudio</em>, główną jego zaletą jest
+            łatwa możliwość przełącznia wyjść dzwięku oraz proste zarządzanie
+            całym podsystem dźwięku z poziomu jednego panelu. Wykorzystanie
+            samego systemu <em>ALSA</em> jest wystarczające, jednak
+            nie zbyt wygodne, ale oczywiście co kto lubi.</li>
+        </ul>
+        <h3 id="3.4.1.makedev">3.4.1. Tworzenie plików urządzeń</h3>
+        <p>
+          We współczesnych systemach nie ma potrzeby samodzielnego tworzenia
+          urządzeń, jednak czasami w specyficznych konfiguracjach może dość
+          do potrzeby utworzenia urządzenia. Osobiście spotkałem się z takim
+          przypadkiem konfigurując VPN na dystrybucji Alpine Linux, należało
+          osobiście utworzyć urządzęnie znakowe TUN. 
+        </p>
+        <p>
+          Urządzenie tworzymy za pomocą polecenia <strong>mknod</strong>,
+          podając nazwę urządzenia, jego rodzaj i w zależności od rodzaju
+          <em>numer główny</em> oraz <em>numer poboczny</em> (w przypadku
+          nazwanych potoków, nie trzeba podawać <em>numery głównego</em> i
+          <em>numeru pobocznego</em>.
+        </p>
+        <h2 id="3.5.udev">3.5 System udev</h2>
+        <p>  
+          Zarządzanie plikami urządzeń jest jedną z cech jądra, która
+          mogła działać w przestrzeni użytkownika. Jądro tylko gdyby wykryło
+          nowe urządzenie wysłało by powiadomienie do procesu
+          <em>udevd</em>. Proces ten zbadał by charakterystykę urządzenia,
+          utworzył dla niego odpowiedni plik, a na koniec przewprowadził 
+          jego inicjację. Niestety to tylko teoria. 
+        </p>
+        <p>
+          Rozwiązanie tego typu nie uwzględnia kilku problemów. Pliki urządzeń
+          są potrzebne już na wszczesnych etapach uruchamiania, zatem proces
+          <em>udev</em> musiał by zostać uruchomiony bardzo wcześnie, nie może
+          mieć żadnych zależności wobec plików urządzeń i uruchomić się
+          błyskawicznie, aby nie spowalniać procedury rozruchu systemu.
+        </p>
+        <h3 id="3.5.1.devtmpfs">3.5.1. System plików devtmpfs</h3>
+        <p>
+          System plików (będzie o tym w dalszej części materiału)
+          <strong>devtmpfs</strong>, został opracowany w celu rozwiąznia
+          problemów z dostęp do urządzeń w czasie uruchamiania systemu. W razie
+          gdy jądro będzie potrzebować pliku urządzenia to utworzy je oraz
+          powiadamia o tym fakcie system <em>udev</em>, który zamiast zajmować
+          się tworzeniem pliku przystępuje do inicjacji urządzenia i informuje
+          o tym pozostałe procesy. Po za tym proces <em>udev</em> tworzy kilka
+          dowiązań symbolicznych w katalogu <em>/dev</em>, które bardziej
+          szczegółowo identyfikują urządzenie, wyniki tego działania możemy
+          obejrzeć w katalogu <em>/dev/disk/by-id</em>.
+        </p>
+        <p>
+          System <em>udev</em>, tworzy nazwy dowiązań bazdując na typie
+          interfejsu, nazwie producenta, informacji o modelu, numerze seryjnym
+          oraz partycji. Proces pobiera te informacji na podstawie reguł
+          systemu <em>udev</em>, jednak nie będziemy się tym tutaj zajmować.
+        </p>
+        <h1 id="4.disksandfs">4. Dyski i systemy plików</h1>
+        <p>
+          Dyski w systemach Linux przedstawiane są jako urządzenia blokowe z
+          nazwami pochodzącymi od podsystemu SCSI - <em>/dev/sdX</em>. Z punktu
+          widzenia systemu na dysku znajduje się wiele warstw oraz 
+          komponentów. Wybrane częsci dysku możemu zaalokować na partycje,
+          które system prezentuje w taki sam sposób jak dyski, dodają liczbę
+          na końcu nazwy dysku. Wystąpienia partycji na dysku przechowywane
+          są w <strong>tablicy partycji</strong>.
+        </p>
+        <p>
+          Jądro systemu umożliwia dostęp do całego urządzenia (dysku) oraz do
+          partycji dzięki osobnym plikom urządzeń.
+        </p>
+        <p>
+          Każdy dysk musi posiadać chociażby jedną partycję, aby był użyteczny
+          w systemie, z kolei taka partycja musi zostać sformatowana pod
+          wybrany system plików, aby mogła przez chowywać jakie kolwiek dane.
+          <strong>System plików</strong> możemy określić mianem bazy danych
+          przechowywującej informacje na temat plików i katalogów.
+        </p>
+        <h2 id="4.1.partitioning">4.1. Partycjonowanie dysków</h2>
+        <p>
+          Partycjonowanie dysku, odbywa się w oparciu o schematy. <strong>
+          Schematy partycjonowania</strong> okreslają ilość możliwych do
+          utworzenia na dysku partycji oraz ewentualne dodatkowe informacje
+          przechowywane w tablicy partycji. Wśród obecnie stosowanych możemy
+          wyróżnić takie schematy jak <strong>MBR</strong> oraz <strong>GPT</strong>.      
+        </p>
+        <p>
+          Na Linuksie dostępnych jest wiele narzędzi partycjonujących dysk,
+          jedne są obsługiwane jak z poziomu środowiska graficznego inne
+          zaś z poziomu terminala. Osobiście używam programu <strong>fdisk</strong>
+          i to na nim skupię się jeśli chodzi o partycjonowanie. Program ten
+          ma dwie istotne zalety. Po pierwsze nic nie zostanie zapisane do
+          momentu gdy nie wydamy polecenia (Tak, w <em>fdisk</em> wydaje się
+          polecenia, ale są one ograniczone do wpisania jednej litery i
+          naciśnięcia klawisza <em>enter</em>); po drugie w pakiecie <em>fdisk</em>
+          zawarty jest również program <strong>sfdisk</strong> (co prawda z
+          nieco dziwną składnią), ktory umożliwia manipulowanie dyski z poziomu
+          pojedynczych polecenie (w przypadku <em>fdisk</em> wykorzystywany 
+          jest tryb interaktywny), przez co możemy użyć <em>sfdisk</em> w 
+          skrypcie.
+        </p>
+        <h3 id="4.1.1.listingpartitiontable">4.1.1. Przeglądanie tablicy partycji</h3>
+        <p>
+          Przy użyciu polecenia:
+        </p>
+<pre class="code-block">
+$ sudo fdisk -l
+</pre>
+        <p>
+          możemy wyświetlić zawartość tablicy partycji wszystkich dysków w
+          systemie, Jeśli zaś interesuje nas wybrane urządzenie możemy wpisać
+          jego nazwę po opcji <code class="code-inline">-l</code>. Informacja
+          zwracana przez polecenie zawiera informacje o schemacie
+          partycjonowania w polu <em>Disklabel type:</em> oraz tabele
+          przedstawiającą nazwę urządzenia, informacje o ustwionej fladze
+          rozruchu, początku, końcu i rozmiarze podanym w sektorach (informacja
+          ile wynosi sektor znajduje się w linii <em>Sector size</em>) oraz 
+          identyfikatorze i nazwie typu partycji. Identyfikatory można wypisać
+          podczas nadawania typu. 
+        </p>
+        <p>
+          Schemat partycjonowania MBR nazwany jest <em>fdisk</em> <strong>dos</strong>.
+          Identyfikator dysk jest krótszy. W przypadku tablicy partycji
+          <em>GPT</em> identyfikator dysku zawiera ciągu znaków odzielone
+          spacjami, nie występują w tabeli identyfikatory typów partycji
+          ponieważ są tak duże jak identyfikator dysku (podczas ustalania
+          wybierane są z wyświetlonej listy) oraz może wystąpić dodatkowa
+          kolumna przechowywująca etykietę partycji. Jednak główną różnicą
+          wśród tych schematów jest zarządzanie miejscem na dysku. Dyski z
+          tablicami MBR mogą mieć maksymalną pojemność do 2TB, jeśli użyjemy
+          wiekszego, to stosując tego typu partycję pozbędziemy się pozostałej
+          części dysku, kolejny minus dla tego rodzaju to możlwość tworzenie
+          maksymalnie czterech <strong>partycji podstawowych</strong>
+          (zwykłych partycji na dane), jeśli 
+          chcielibyśmy
+          więcej owszem możemy jednak, musimy użyć jedno miejsce na 
+          <strong>partycję rozszerzoną</strong>
+          bedącą kontenerem dla dysków logicznych. W przypadku
+          GPT raczej maksymalna wielkość dysku nie jest póki co osiąglna 
+          (9,4 mld TB) a partycji podstawowych możemy utworzyć, aż 128. To są
+          tak naprawę za i przeciw, które decydują o użytym schemacie.
+        </p>
+        <h3 id="4.1.2.modifypartition">4.1.2. Modyfikowanie tablicy partycji</h3>
+        <p>
+          Modyfikowanie tablicy partycji należy rozpocząć, od zastanowienia się
+          na temat przydatności danych, które znajduja się obecnie na dysku.
+          Ponieważ modyfikowanie tablicy partycji, często będzie wiązać się z
+          potrzebą reformatowania modyfikowanej partycji. W stopniu podstawowym
+          skupimy się tworzeniu oraz usuwaniu partycji. Modyfikowanie tablicy
+          za pomocą <em>fdisk</em>, jest dość łatwe, polega na interaktywnym
+          wydawaniu poleceń oraz odpowiadniu na pytania programu, dlatego też
+          dla urozmaicenia użyjemy <strong>sfdisk</strong> zamiast wymienionego
+          wcześniej programu. Dla przykładu stworzymy dysk do klasycznej
+          instalacji systemu Linux z tablicą partycji typu MBR. Za dysk testowy
+          może posłużyć nam pendrive, karta pamięci lub plik na dysku. Ja
+          skorzystam z pliku. 
+        </p>
+        <p>
+          Plik przygotowuje za pomocą polecenia <em>dd</em> poznanego w
+          poprzednim rozdziale.
+        </p>
+<pre class="code-block">
+$ sudo dd if=/dev/zero bs=1M of=vhd.img count=8192
+</pre>
+        <p>
+          Zapisanie 8GB zer może chwilę potrwać. Po utworzeniu pliku przechodzę
+          do jego inicjalizacji.
+        </p>
+<pre class="code-block">
+$ echo "label:dos" | sudo sfdisk vhd.img
+</pre>
+        <p>
+          Polecenia <em>sfdisk</em> muszą pochodzić ze strumienia lub z
+          wcześniej przygotowanego skryptu. Polecenie tworzy na dysku
+          tablice partycji typu MBR. Kolejne polcenie będą już poleceniami
+          właściwymi tworzącymi partycje na naszym dysku.
+        </p>
+        <p>
+          Polecenia <em>sfdisk</em> składają się z czterech pól:
+        </p>
+        <ul>
+          <li><strong>początkowy sektor</strong> - w pierwszym polu wskazujemy
+            od którego sektora na dysku ma zaczynia się partycja. Pierwsza
+            partycja zawsze zaczyna się od drugiego megabajtu dysku. Wartość
+            ta jest najczęściej pomijana i pozostawiana do decyzji programowi.</li>
+          <li><strong>wielkość partycji</strong> - wielkość partycji podajemy
+            zapisując na początku znak plusa (<strong>+</strong>) następnie
+            podając jej wielkość w wygodnej dla nas wielkrotności bajtu,
+            pamiętając że zapisując jednostkę, używamy tylko pierwszej litery
+            (dla GB nie jest GB tylko G).</li>
+          <li><strong>typ partycji</strong> - typ partycji określany jest za 
+            pomocą pojedyńczej litery dla zywkłej partycji na dane Linuksa
+            jest to <strong>L</strong>, dla przestrzeni wymiany (będzie o niej
+            za chwilę) jest <strong>S</strong>, a dla partycji rozszerzonej
+            jest to <strong>E</strong>.</li>
+          <li><strong>flaga rozruchowa</strong> - flaga rozruchowa była
+            stosowana dawniej, obecnie straciła na znaczeniu. I jej obecność
+            może służyć zaznaczeniu partycji przechowywującej podkatalog
+            <em>/boot</em> katalogu głównego.</li> 
+        </ul>
+        <p>
+          Po utworzeniu pierwszej partycji, każda kolejna będzie wymagać 
+          podania podania opcji <strong>-a</strong>,  która spowoduje
+          wykorzystanie wcześniej utworzonej tablicy partycji oraz jej numeru 
+          po opcji <strong>-N</strong> przed wskazaniem
+          poleceniu urządzenia. Zatem pierwszą partycję tworzymy za pomocą
+          poniższego polecenia:
+        </p>
+<pre class="code-block">
+$ echo ",+7G,L,*" | sudo sfdisk vhd.img
+</pre>
+        <p>
+          Pierwszej partycji przydzielono większość miejsca na dysku, będzie
+          ona przechowywać katalog główny. Resztę miejsca wykorzystamy na
+          partycję rozszerzoną, a wewnątrz niej utworzymy dysk logiczny będący
+          partycją wymiany.
+        </p>
+<pre class="code-block">
+$ echo ",,E," | sudo sfdisk -a -N 2 vhd.img
+$ echo ",,S," | sudo sfdisk -a -N 5 vhd.img
+</pre>
+        <p>
+         Teraz możemy wyświetlić sobie tablice dysku, który partycjonowaliśmy.
+         Zwróćmy uwagę na to, że wystarczy odpowiedni numer partycji aby
+         utworzyć dysk logiczny. Pominięcie rozmiaru spowoduje zaalokowanie
+         pozostałego wolnego miejsca. Tak przygotowane partycje są gotowe do
+         sformatowania pod wybrany system plików. 
+        </p>
+        <h4>Usuwanie partycji</h4>
+        <p>
+          Eksperymentując poraz pierwszy z <em>sfdisk</em> może nam coś nie
+          wyjść dlatego też zamiast rozpoczynać partycjonowanie od nowa możemy
+          źle przygotowaną partycję usunąć. Wydając polecenie <em>sfdisk</em>
+          opcję <strong>--delete</strong> następnie nazwę urządzenia oraz
+          numer partycji, którą chcemy usunąć.
+        </p>
+        <p>
+          Korzystając z <em>sfdisk</em> pozbawiamy się bufora, ponieważ 
+          program ten zmienia tablicę partycji z każdą modyfikacją. Jeśli
+          chcemy tylko sprawdzić jak będą wyglądać pewne zmiany to lepiej
+          użyć polecenia <em>fdisk</em>. Pomoc uruchamiana jest
+          za pomocą polecenia <strong>m</strong> po uruchomieniu programu.
+        </p>
+        <h2 id="4.2.filesystems">4.2. Systemy plików</h2>
+        <p>
+          Systemy plików umożliwiają zamianę prostego urządzenia blokowego
+          w sktrukturę plików i katalogów zarozumiałą dla końcowego użytkownika.
+          Dawniej służyły głównie przchowywaniu plików jednak obecne ich
+          funkcje umożliwiają wykorzystanie ich jako interfejsów systemowych
+          w takich katalogach jak <em>/proc</em> czy <em>/sys</em>.
+        </p>
+        <p>
+          Normalnie systemy plików są implementowane w jądrze systemu, jednak
+          rozwiązana zastosowane w następcach Uniksa, takich jak <em>Plan 9</em>.
+          umożliwiły stworzenie systemów plików działających w przestrzeni
+          użytkownika, tzw. <strong>FUSE</strong>. Dzięki tej funkcji możemy
+          zapisywać dane na nośnikach z takim system plików jak NTFS.
+        </p>
+        <p>
+          Istotną funkcję jeśli chodzi o sposób działania systemów plików, jest
+          wykorzystanie <strong>VFS</strong>, który standaryzuje dostęp do
+          plików i katalogów dla aplikacji użytkownika, dlatego też Linux 
+          obsługuje tak wiele systemów plików.
+        </p>
+        <h3 id="4.2.1.fstypes">4.2.1. Typy systemów plików</h3>
+        <p>
+          Mimo iż Linux, może obsługiwać chyba wszystkie możliwe systemy plików,
+          to większość z nich wymaga dodatkowego oprogramowania. Natywnie 
+          obsługiwane systemy plików Linuksa znajduje się na liście poniżej.
+        </p>
+        <ul>
+          <li><strong>EXT4</strong> (<em>Czwarty rozszerzony system plików</em>)
+              - domyślny i najpopularniejszy system plików dla linuksa, 
+              wyposarzony w pliki dziennika, znane z <em>ext3</em> oraz
+              zwiększone limity związane z wielkością plików oraz ilością
+              podkatalogów w katalogu względem wersji trzeciej. W przyszłości
+              może zostać zastąpiony przez <em>btrfs</em> lub <em>xfs</em>.</li>
+          <li><strong>iso9660</strong> - standardowy system plików stosowany na
+              płytach CD-ROM.</li>
+          <li><strong>FAT</strong> - rodzina systemów plików znan z wczesnych
+              wersji systemu MS Windows, obecnie wykorzystywana przez pamięci
+              flash, jak pendrive oraz karty pamięci.</li>
+          <li><strong>HFS+</strong> - system plików stosowany w starszych
+              wersjach systemu Apple macOS. Zastąpiony prze APFS. Wykorzystanie
+              partycji system HFS+, jest jedyną możliwością przenaszalności
+              plików pomiędzy współczesnymi Macami a Linuksem.</li> 
+        </ul>
+        <h3 id="4.2.2.createfs">4.2.2. Tworzenie systemu plików</h3>
+        <p>
+          Tworząc partycje w poprzednim punkcie pozostało jeszcze sformatować
+          pod konkretny system plików, aby można było przechowywać na nich
+          informacje. System plików tworzony jest za pomocą polecenia
+          <strong>mkfs</strong>. Polecenie ma inną nieco inna składnię,
+          ponieważ żądany system plików podaje się po kropce w nazwie polecenia
+          np. <strong>mkfs.ext4</strong>. Jako argument podajemy nazwę
+          urządzenia partycji.
+        </p>
+<pre class="code-block">
+$ sudo mkfs.ext4 /dev/sda1
+</pre>
+        <p>
+          Podczas formatowania partycji program wyświetla komunikaty
+          diagnostyczne. Wśród nich znajdują się liczby oddzielone do siebie
+          przecinkami. Te liczby to kopie zapasowe <em>superbloku</em>.
+          <strong>Superblok</strong> to najwyższy poziom bazy danych systemu
+          plików, jest on na tyle ważny że program tworzy kilka jego kopii.
+          Numery bloków zawierających kopie <em>superbloku</em> należy zachować
+          ponieważ może być ona potrzebna do ewentualnego odzyskiwania danych.
+        </p>
+        <p>
+          Przyglądając się samemu programowi <em>mkfs</em> dojedziemy do 
+          wniosku, że jest to swojego rodzaju interfejs do całego zbioru 
+          programów tworzących systemy plików. Nie które wystąpienia tego
+          interfejsu są dowiązaniami sybolicznymi do innych programów.
+          np <code class="code-inline">mkfs.ext4</code> wskazuje na 
+          program <strong>mke2fs</strong>, będący głównym programem do służącym
+          do tworzenia systemów plików z rodziny EXT, warto o tym pamiętać
+          ponieważ możemy natknąć się na systemy bez polecenia <em>mkfs</em>.
+        </p>
+        <h3 id="4.2.3.mountfs">4.2.3. Montowanie systemów plików</h3>
+        <p>
+          Proces dołączania systemu plików w uniksach nazywany jest
+          <strong>montowaniem</strong>. Aby zamontować w systemie jakiś system
+          plików należy użyć polecenia <strong>mount</strong>, użyć tego
+          polecnia bez żadnej opcji spowoduje wyświetlenie podmonotowanych
+          systemów plików. Montowanie jak i późniejsze odmontowywanie wymagają
+          uprawnień superużytkownika.
+        </p>
+        <p>
+          Każdy wpis to jedno montowanie systemu plików, wpisy zwierają kolejno
+          nazwę urządzenia, docelowe miejsce montowania, typ systemu
+          oraz opcje specyficzne dla systemu.
+        </p>
+        <p> 
+          Montowanie systemu plików odbywa się za pomocą tego samego polecenia,
+          jednak wymaga podania kilku argumentów, kolejno: 
+        </p>
+        <ul>
+          <li><strong>nazwy urządzenia</strong></li>
+          <li><strong>typ systemu plików</strong></li>
+          <li><strong>punktu montowania</strong> - katalogu docelowego dla
+            montowanego systemu plików.</li>
+          <li><strong>opcje specyficzne dla systemu plików</strong> - opcje
+            są podawane jak wartość opcji <strong>-o</strong> polecenia. Nie
+            zawsze trzeba podawać opcje systemu plików.</li>
+        </ul>
+        <p>
+          Montując systemy takie jak EXT, czy któryś z FAT możemy pominąć 
+          rodzaj podczas montowania, program sam to ustali. Jednak montowanie
+          udziałów sieciowych <strong>CIFS</strong>, wymaga podania typu aby
+          program <em>mount</em> mógł rozpoznać wartości zapisane w
+          argumentach.
+        </p>
+        <p>
+          Po skończeniu prac z system plików, możemy go odmontować za pomocą
+          polecenia <strong>umount</strong>. Polecenie wymaga podania albo
+          urządzenia albo punktu montowania jako argumentu.
+        </p>
+        <h3 id="4.2.4.uuid">4.2.4. Identyfikator UUID systemu plików</h3>
+        <p>
+          Montowanie systemu plików wymaga podania nazyw urządzenia. Pliki
+          konfiguracyjne odpowiedzialne za automatyczne montowanie systemów
+          plików w systemie podczas jego startu, nie mogą polegać na tych 
+          samych nazwach urządzeń co użytkownicy, ponieważ są one ustalane
+          pod czas startu systemu, i ich nazwy zależą od kolejności
+          wykrycia ich przez jądro. W takich plikach używa się
+          <strong>identyfikatorów UUID</strong> swoistych numerów seryjnych
+          systemów plików nadawanych podczas formatowania. Listę urządzeń
+          wraz z UUID-ami, możemy wywołać za pomocą polecenia:
+        </p>
+<pre class="code-block">
+$ sudo blkid
+</pre>
+        <p>
+          Identyfikatorów możemy używać nie tylko z plikami konfiguracyjnymi
+          jak <em>/etc/fstab</em>, ale równie przy polecniu mount zamiast
+          klasycznej nazwy urządzenia. Jednak posługiwanie się tak długim i
+          skomplikowanym ciągiem znaków nie jest za wygodne.
+        </p>
+        <p>
+          Polecenie <em>blkid</em> może zwracać w polu <em>UUID</em> numery
+          identyfikacyjne innych systemów plików takich jak na przykład FAT,
+          gdzie UUID-em jest numer seryjny woluminu FAT. Oczywiście takie
+          identyfikatory możemy używać podczas konfiguracji pliku
+          <em>/etc/fstab</em>.
+        </p>
+        <p>
+          UUID musi być unikatowy, dlatego też jeśli zasła potrzeba skopiowania
+          całego systemu plików, to należy zmienić ten identyfikator aby
+          odróżnić kopię od oryginału.
+        </p>
+        <h3 id="4.2.5.diskcache">4.2.5. Buforowanie dysku i systemu plików</h3>
+        <p>
+          Uniksy w tym i Linux nie zapisują wszysktkich zmian w systemie
+          plików po otrzymaniu takiego żądania. Zmiany przechowywane są w
+          pamięci RAM od momentu kiedy jądro będzie mogło swobodnie zapisać
+          je na dysku.
+        </p>
+        <p>
+          W momencie odmontowywania systemu plików jądro automatycznie
+          synchronizuje zawartość dysku. Jeśli z jakiego powodu nie będziemy
+          mogli odmontować systemu plików to wówczas możemy wydać polecenie
+          <strong>sync</strong>, które wymusza zapisanie na dysku wszyskich
+          zmian w systemie plików. Oczywiście w wiekszej liczbie przypadku
+          problemów z odmonotowaniem systemu plików jest proces używający
+          któregoś z plików na dysku.
+        </p>
+        <p>
+          Jądro dysponują całą serią mechanizmów wykorzystujących pamięć RAM
+          do buforowania danych odczytywanych z dysków, przez co jeśli proces
+          wielokrotnie będzie odczytywać dane z tego samego pliku, jądro nie
+          będzie musiało odwoływać się do danych na dysku przez każde dane do
+          procesu z bufora, oszczędzając tym samym czas i zasoby.
+        </p>
+        <h3 id="4.2.6.mountoptions">4.2.6. Opcje montowania</h3>
+        <p>
+          Polecenie <em>mount</em> posiada dużą ilość opcji. Jest ona tak duża
+          że wprowadzenie opcji długich wynikało z obowiązku aniżeli wygody,
+          ponieważ nazwyczajniej zaczynało tych liter w alfabecie brakować.
+          Z posród opcji krótkich - jedno literowych możemy wyróżnić
+          najważniejsze:
+        </p>
+        <ul>
+          <li><strong>-r</strong> - powoduje zamontowanie systemu plików w
+            trybie tylko do odczytu.</li>
+          <li><strong>-n</strong> - powoduje nie modyfikowanie pliku
+            <em>/etc/mtab</em> (plik zawiera zamontowane obecnie systemy plików,
+            wydanie polecenia <em>mount</em> bez żadnych opcji powoduje
+            wyświetlenie zawartości tego pliku). Opcja ta pozwala na 
+            zamontowanie systemu plików w momencie gdy system plików zawierjący
+            katalog główny, a co za tym idzie plik <em>/etc/mtab</em> jest
+            zamknotowany w trybie tylko do odczytu, bowiem nie zapisanie zmian
+            w tym pliku spowoduje niepowodzenie montowania.</li>
+          <li><strong>-t</strong> - umożliwia podanie systemu plików.</li>
+        </ul>
+        <p>
+          Opcje długie podawane wraz z opcjami specyficznymi dla systemu plików
+          po opcji <em>-o</em>. Z opcji długich możemy wyróżnić takie jak:
+        </p>
+        <ul>
+          <li><strong>exec, noexec</strong> - włącza i wyłącza możliwość
+            uruchamiania programów w danym systemie plików.</li>
+          <li><strong>suid, nosuid</strong> - włącza i wyłącza możliwość
+            korzystania z bitu <em>suid</em> przez programy.</li>
+          <li><strong>ro</strong> - montuje system plików w trybie tylko do
+            odczytu.</li>
+          <li><strong>rw</strong> - mountuje system plików w trybie pełnego
+            dostępu.</li>
+        </ul>
+        <h3 id="4.2.7.remount">4.2.7. Pownowne montowanie systemu plików</h3>
+        <p>
+          W trakcie odzyskiwania danych może zajść potrzeba ponownego
+          zamontowania systemu plików w celu zmiany opcji montowania.
+          Najczęściej chodzi o przełączenie systemu plików zawierającego
+          katalog główny z trybu tylko do odczytu w tryb pełnego dostępu.
+          Ponownemu montowaniu służy opcja <strong>remount</strong>.
+        </p>
+        <h3 id="4.2.8.fstabfile">4.2.8. Tablica systemów plików /etc/fstab</h3>
+        <p>
+          Plik <strong>/etc/fstab</strong> przechowuje informacje o systemach
+          plików oraz ich punktach montowania, dzięki czemu montuje te systemy
+          podczas uruchamiania systemu. Każdy wiersz tego pliku przechowuje
+          informacje o jednym systemie plików i jest podzielony na sześć pól.
+        </p>
+        <ul>
+          <li><strong>Nazwa urządzenia lub UUID</strong> - dla dysków stosowane
+            są identyfikatory UUID, jednak napęd optyczny w
+            tym pliku, zapisywany jest nazwą urządzenia. Urządzeniem tylko do 
+            odczytu napędu optycznego zazwyczja będzie <em>/dev/sr0</em>.</li>
+          <li><strong>Punkt monotowania</strong> - katalog docelowy dla
+            montowanego systemu plików.</li>
+          <li><strong>Typ systemu plików</strong></li>
+          <li><strong>Opcje</strong> - list długich opcji rodzielonych
+            przecinkami.</li>
+          <li><strong>Informacje o kopiach bezpieczeństwa dla programu 
+              <em>dump</em></strong> - w tym polu zawsze należy podawać 0.</li>
+          <li><strong>Kolejność sprawdzania spójność systemów plików</strong> -
+              systemowi plików zawierającemu katalogów zawsze podajemy wartość
+              1. Oznacza to sprawdzenie tego systemu w pierwszej kolejności.
+              Pozostałym możemy podać wartość 2 lub 0, gdzie 2 oznacza 
+              sprawdzenie tych systemów po systemie oznaczonym wartością 1.
+              Każdy kolejny system przychowywujący jakieś dane oznacza się
+              2. Po sprawdzeniu systemu z jedynką, program będzie sprawdzać
+              po kolei systemy z dwójką. Natomiast 0 oznacza pominięcie 
+              sprawdzania systemu przez program <em>fsck</em>.</li> 
+        </ul>
+        <p>
+          Posiadając odpowiednie wpisy w plik <em>/etc/fstab</em>, możemy
+          montować system plików podając poleceniu mount tylko punkty
+          montowania co może być wygodne podczas montowania systemów plików
+          dużą ilością opcji.
+        </p>
+        <p>
+          Istnieje kilka opcji które mają zastosowanie tylko w omawianym przez
+          nas pliku.
+        </p>
+        <ul>
+          <li><strong>defaults</strong> - włącza domyślne ustawienie polecenia
+            <em>mount</em> dając tym samym największe uprawenienia.</li>
+          <li><strong>errors</strong> - ta opcja ma zastosowanie tylko dla
+            systemów z rodziny EXT, pozwala na ustalenia zachowania systemu
+            w momencie problemów z montowaniem systemu plików. Do wyboru mamy
+            takie możliwości jak: <em>continue</em> - wygeneruj kod błędu i 
+            kontynuuj pracę; <em>remount-ro</em> - zamontuj ponownie w trybie
+            tylko do odczytu; <em>panic</em> - zatrzymaj system.</li>
+          <li><strong>noauto</strong> - opcja nakazuje pominąć wpis podczas
+            automatycznego montowania systemów plików.</li>
+          <li><strong>user</strong> - pozwala na podmontowanie tego systemu
+            za pomocą polecenia <em>mount</em> bez potrzeby uprawnień 
+            superużytkownika - podmontować ten system plików może każdy
+            użytkownik.</li>
+        </ul>
+        <h3 id="4.2.9.fscapacity">4.2.9 Pojemność systemu plików</h3>
+        <p>
+          Sprawdzenia zajętości systemu plików możemy dokonać za pomocą
+          polecenia <strong>df</strong>. Polecenie to domyślnie zwraca
+          wszelkie wartość w postaci kilobajtów, które nie są zbyt czytelne dla
+          człowieka. Aby przeskalować jednostki możemy posłużyć się opcją
+          <strong>-h</strong>. Polecenie wyświetla wynik swojego działania
+          w postaci pięciu kolumn przedstawiających kolejno system plików,
+          jego rozmiar, użyte miejsce, dostępne miejsce, stopień użycia w
+          procentach oraz punkt montowania. W przypadku użycia programu bez
+          podanej opcji rozmiar systemu nosi nazwę <em>1K-bl</em> jest to
+          wielkość systemu plikach w jednokilobajtowych blokach.
+        </p>
+<pre class="code-block">
+$ df -h
+</pre>
+        <p>
+          Jeśli przjrzymy się na chwilę wynikom działania tego polecenia,
+          możemy dość do wniosku, że albo mamy doczynienia z błędem albo
+          tolerancja błędu przybliżenia jest bardzo. Otóż nie. Kilku gigabajtów
+          brakuje ze względu na to, że zostały <strong>zarezerwowane</strong>
+          i są do dyspozycji superużytkownika w momencie wyczerpania się
+          miejsca na danym systemie plików, aby zapewnić systemówi dalsze
+          funkcjonowanie oraz umożliwić administratorowi odzyskanie chociaż
+          części miejsca na dysku.
+        </p>
+        <h3 id="4.2.10.fsrescue">4.2.10. Sprawdzanie i naprawnia systemu plików</h3>
+        <p>
+          Jądro do pracy systemu musi mieć pewność, że zamontowane systemy
+          plików są pozbawione błędów. Błędy systemów plików mogą powodować
+          utratę danych lub załamanie systemu. Najczęstszym powodem
+          występowania błędów w systemie plików, są zaniki zasialania
+          komputera spowodowane ludzką niewiedzą lub czynnikami środowiskowymi.
+          Najnowszej generacji systemy plików wykorzystują pliki dziennika,
+          dzięki, przerwanie działania systemu w wyniku różnych czynników
+          nie doprowadza do katastrofy to są przypadki gdzie i one zawodzą.
+        </p>
+        <p>
+          Narzędzie przeznaczone do sprawdzania oraz naprawy systemu plików 
+          nazywa się <strong>fsck</strong>. <em>Fsck</em> podobobnie do
+          <em>mkfs</em> uruchamia odpowiedni dla użytego na partycji systemu
+          plików. Program w trybie interaktywnym uruchamiamy wydając polecenie
+          <em>fsck</em> następnie podając nazwę urządzenia.
+        </p>
+<pre class="code-block">
+$ fsck /dev/sdb1
+</pre>
+        <p>
+          Nie wolno uruchamiać programu na zamontowanym systemie plików, gdyż
+          grozi to utratą danych oraz załamaniem systemu. Inaczej sprawa ma się
+          gdy system plików jest w trybie tylko do odczytu.
+        </p>
+        <p>
+          W trybie interaktywnym program będzie zwracać raport z kolejnych
+          etapów, jeśli napotka jakiś problem program zapytanie o usunięcie
+          błędu. W wyniku błedów w systemie plików może zdarzyć się, że
+          pewne pliki zostaną pozbawione nazwy (nazwy plików są w uniksach
+          elementami systemu plików). Program kiedy napotka na taki to zostanie
+          on przeniesiony do katalogu <strong>lost+found</strong> z nazwą 
+          odpowiadającą numerowi identyfikacyjnemu z systemu plików (węzła
+          <em>i-node</em>). Rzeczywistą nazwę musimy ustalić samodzielnie
+          na podstawie analizy jego zawartości.
+        </p>
+        <p>
+          Program <strong>e2fsck</strong> - właściwy program <em>fsck</em> dla
+          rodziny systemów plików EXT, posiada opcję <strong>-p</strong>
+          zajmującą się naprawą drobnych błędów. Program zatrzyma się wówczas
+          tylko wtedy gdy napotka poważny błąd. Jeśli mamy podejrzenie, że coś
+          się dzieje z system plików, to możemy sprawdzić system plików bez
+          dokonywania w nim żadnych modyfikacji, korzystając z opcji
+          <strong>-n</strong>. Co w przypadku uszkodzenia <em>superbloku</em>?
+          Podstawową bazę danych możemy odbudować za pomocą opcji
+          <strong>-b</strong> po opcji należy podać lokalizację kopii 
+          superbloku (numer sektora podawany przez <em>mkfs</em> podczas
+          tworzenia systemu plików). W przypadku gdy zapomnieliśmy spisać te
+          numery, możemy spróbować je odzyskać wydając polecenie <em>mke2fs</em>
+          wraz z opcją <strong>-n</strong> dla urządzenia. Należy upewnić się, 
+          że na pewno użyliśmy tej opcji jej pominięcie sformatuje partycję. 
+        </p>
+        <p>
+          Istnieją przypadki uszkodzeń, które wykraczają po za sferę programową
+          program <em>fsck</em>, nie jednokrotnie pokazał mi, że by się
+          wydawało katastrofę, naprawiał pojedyńczym domyślnym uruchomieniem.
+          Jeśli nasze systemy dyskowe przechowują ważne informacje, to
+          najlepszą ochroną jest <strong>kopia zapasowa</strong> warto je
+          robić. Lepiej jest wymieć dysk, zainicjalizować dysk i przegrać dane
+          niż liczyć na to, że może coś się uda odzyskać. Może się uda, jakieś
+          szanse istnieją. Jeśli posiadamy kopię, to szanse przekraczają 90%
+          reszta to ich aktualność.
+        </p>
+        <h3 id="4.2.11.specialfs">4.2.11. Systemy plików o specjalnym znaczeniu</h3>
+        <p>
+          Nie wszyskie systemy plików służą zapisywaniu informacji na
+          fizycznych nośnikach, nie które z nich mogą służyć jako intefejsy
+          systemowe lub przezentować informacje systemowe. Takimi systemami
+          są:
+        </p>
+        <ul>
+          <li><strong>proc</strong> - system montowany w katalogu <em>/proc</em>,
+            Zawiera katalogi odpowiadające każdemu z procesów w systemie ich
+            nazwy pochodzą od <em>PID</em>-u procesu. Pliki opisują różne
+            aspekty procesów. Na Linuksach katalog ten przechowuje wiele
+            dodatkowych informacji o jądrze systemu i sprzecie.</li>
+          <li><strong>sysfs</strong> - system montowany w katalogu <em>/sys</em>.
+            Omawiany był w poprzednim rozdziale.</li>
+          <li><strong>tmpfs</strong> - montowany w katalogu <em>/run</em> oraz
+            innych miejsach. Za pomocą tego systemu możemy przekształcić pamięć
+            systemową w coś w rodzaju przestrzeni dyskowej, za pomocą dwóch
+            paramerów (<em>size</em> oraz <em>nr_block</em>) możemy określić
+            jego wielkość podczas montowania. Nie należy przesadzać z zapisem 
+            danych do tego systemu, możemy doprowadzić do braku pamięci i 
+            załamania systemu.</li>
+        </ul>
+        <h2 id="4.3.swapspace">4.3. Przestrzeń wymiany</h2>
+        <p>
+          Za pomocą przestrzeni na dysku jesteśmy wstanie powiększyć ilość
+          użytkowej pamięci operacyjnej. System będzie automatycznie przenosić
+          strony pamięci (obszary) na dysk i z dysku, wykorzystująca tzw.
+          pamięć wirtualną. Operacja przenoszenia stron pamięci na dysk i
+          z powrotem nosi nazwę <strong>wymiany</strong> 
+          (ang. <em>swapping</em>), ponieważ polega na wymianie nieaktywnych
+          stron w pamięci z aktywowany zanajdującymi się aktualnie na dysku.
+          Przestrzeń, w której zapisywane są strony pamięci nazywa się
+          przestrzenią wymiany.
+        </p>
+        <h3 id="4.3.1.swappartition">4.3.1. Wykorzystanie partycji jako 
+          przestrzeni wymiany.</h3>
+        <p>
+          Wykorzystanie partycji jako przestrzeni wymiany jest standardową
+          procedurą wykonywaną podczas instalacji systemu. Wiele dystrybucji
+          zwraca uwagę na to, gdy brakuje <strong>partycji wymiany</strong>.
+          Partycja wymiany może nie być nigdy wykorzystana, jednak chroni
+          system przed załamianiem gdy zaczyna brakować pamięci RAM. 
+        </p>
+        <p>
+          Podczas modyfikowania tablicy partycji, utworzyliśmy dysk logiczny,
+          który posłuży jako przestrzeń wymiany. Przestrzeń wymiany należy
+          sformatować, tak jak każdą partycje, jednak już nie za pomocą
+          polecenia <em>mkfs</em>, ale <strong>mkswap</strong> podając 
+          nazwę urządzenia jako parametr.
+        </p>
+<pre class="code-block">
+$ sudo mkswap /dev/sda5
+</pre>
+        <p>
+          Partycję wymiany możemy montować automatycznie w systemie za pomocą
+          wpisu w pliku <em>/etc/fstab</em>. Poniżej znajduje się wpis, który
+          można wykorzystać w instalacji. Zgaduje jednak, ża zainstalowana
+          przez nas dystrybucja Linuksa do Mint, Ubuntu lub Kali więc raczej
+          taki wpis znajduje się już tym pliku.
+        </p>
+<pre class="code-block">
+UUID="..."  none  swap  sw  0 0
+</pre>
+        <p>
+          Przestrzeń wymiany możemy włączać oraz wyłączać na żądanie za pomocą
+          poleceń <strong>swapon</strong> oraz <strong>swapoff</strong> 
+          podając urządzenie lub plik jako argument.
+        </p>
+        <h3 id="4.3.2.swapfile">4.3.2. Wykorzystanie pliku jako przestrzeni
+          wymiany</h3>
+        <p>
+          Jeśli nie mamy dostępnego wolnego miejsca na dysku, możemy wówczas
+          stworzyć plik, który będzie służyć nam za przestrzeń wymiany.
+          Aktywujemy go, wówczas gdy ilość wolnej pamięci RAM, będzie
+          niebezpieczenie niska. Aby utworzyć taki plik, musi on posiadać
+          żądaną przez nas wielkość. Najprościej zapisać do niego określoną 
+          liczbę zer z strumienia. 
+        </p>
+<pre class="code-block">
+$ sudo dd if=/dev/zero bs=1M of=swap.img count=2048
+</pre>
+        <p>
+          Polecenie to zapisze dwa gigabajty zer do pliku
+          <code class="code-inline">swap.img</code>. Taki plik będziemy mogli 
+          potraktować jak dysk lub partycję. Chciałbym tutaj również zaznaczyć,
+          że w tym momencie spotykamy się w praktyce z jedną z fundamentalnych
+          zasad Uniksów otóż <strong>"Wszystko jest plikiem"</strong>.
+          Taki plik pozostaje jeszcze sformatować jako partycję wymiany.
+        </p>
+<pre class="code-block">
+$ sudo mkswap swap.img
+</pre>
+        <p>
+          Przygotowaną w ten sposób przestrzeń możemy uruchomić za
+          pomocą polecenia <em>swapon</em>.
+        </p>
+        <h3 id="4.3.3.swapsize">4.3.3. Jak dużej przestrzeni wymiany potrzeuje?</h3>
+        <p>
+          Odpowiedź na to pytanie nie jest trudna do sformułowania. Otóż
+          powszechnie przyjeło się, że przestrzeń wymiany powinna mieć wielkość
+          dwukrotności zainstalowanej pamięci RAM. Biorąc pod uwagę to, że
+          obecnie jesteśmy w posiadaniu dysków o bardzo dużej pojemności to
+          jest to nawet śmieszna wartość, jednakże to przekonanie poważnie
+          podważyło upowszechnienie się dysków SSD, które już dużych wartości
+          nie muszą mieć. Weźmy sprzęt wbudowany (tzw. <em>embedded</em>) lub
+          sprzęt mobilny, nie mówię tu o telefonach, ale np. chrombookach czy
+          rozwiązaniach typu HP Stream. To tym przypadku przestrzeni dyskowej
+          może być za mało jak na 8GB swapu. Weźmy również pod uwagę fakt iż
+          prawdopodbnie nie skorzystamy z przestrzeni wymiany używając
+          Linuksa na współczesnym sprzęcie. Więc wydaje mi się, że najbardziej
+          optymalną wielkości swapu będzie <strong>1GB</strong>. Na poparcie 
+          dodam że wiele
+          instalatorów właśnie tyle alokuje podczas automatycznego 
+          partycjonowania. 
+        </p>
+        <h2 id="4.4.fsfuture">4.4. Przyszłość systemów plików</h2>
+        <p>
+          Jedną z zauważalnych zmian w komputerach jest odejście powoli od
+          dysków talerzowych na rzecz dysków SSD, więc możemy spodziewać się
+          systemów domyślnie zoptymalizowanych pod kątem ich pełnego, 
+          właściwego
+          wykorzystania. Zauważymy lub już jesteśmy świadkami odchodzenia od
+          rodziny systemu plików EXT, na rzecz takich systemów jak 
+          <em>brtfs</em>, który obecnie jest domyślnym systemem dla takich
+          dystrybucji jak Fedora. Alternatywą dla tego systemu będzie
+          system plików <em>xfs</em>. Ich porównanie możemy znaleźć w
+          internecie.
+        </p>
+        <h1 id="5.startingkernel">5. Uruchamianie jądra Linux</h1>
+        <p>
+          W tym rodziale rozpoczeniemy przyglądanie się procedurze uruchamiania
+          systemu operacyjnego, z czego ten fragment materiału poświęcimy na
+          procedurę uruchamiania jądra, programy rozruchowe oraz praktyczną
+          konfigurację najpopularniejszego programu rozruchowego jakim nie
+          wątpliwie jest GRUB.
+        </p>
+        <p>
+          Procedura uruchamiania systemu wygląda w następujący sposób:
+        </p>
+        <ol>
+          <li>System BIOS lub firmware (w przypadku UEFI) ładuje program
+            rozruchowy z dysku i uruchamia go.</li>
+          <li>Program rozruchowy szuka na dysku obrazu jądra, następnie ładuje
+            go do pamięci i uruchamia.</li>
+          <li>Jądro inicjuje wszystkie urządzenia wraz ze sterownikami</li>
+          <li>Jądro montuje partycję z katalogiem głównym.</li>
+          <li>Jądro uruchamia program o nazwie <em>init</em>, proces tego
+            programu zawsze ma <em>PID</em> o wartości 1. Od momentu startu
+            procesu typu init, rozpoczyna się uruchamianie przestrzeni
+            użytkownika.</li>
+          <li>Za pomocą programu <em>init</em> uruchamiane są pozostałe
+            elementy systemu (różnego rodzaju usługi).</li>
+          <li>Na koniec uruchamiany jest proces pozwalający się zalogować do
+            systemu.</li>
+        </ol>
+        <p>
+          W tym rozdziale skupimy się na punktach tej listy od 2 do 4.
+          Pozostałe z nich, po za pierwszym (pierwszy wykracza po za ramy
+          merytoryczne, tego materiału) omówimy w następnym rozdziale.
+        <p>
+        <p>
+          Niestety możliwość identyfikowania poszczególnych etapów uruchamiania
+          systemu jest osiągalna w zależności od dystrybucji. Te przeznaczone
+          na desktopy, ukrywają wiele informacji na temat pierwszych etapów
+          rozruchu systemu pod graficznymi ekranami, zawierającymi logo
+          dystrybucji oraz pasek postępu. Jeśli spotkamy się z takim ekranem,
+          to wówczas możemy naciśnać klawisz <em>ESC</em>, aby wyświetlić
+          komunikaty wypisywane podczas uruchamiania systemu. Umiejętość
+          identyfikacji poszczególnych etapów może pomoć w ewentualnych
+          problemach podczas rozruchu.
+        </p>
+        <h2 id="5.1.dmesg">5.1. Komunikaty rozruchowe</h2>
+        <p>
+          Większość systemów uniksopodobnych generuje wiele komunikatów
+          diagnostycznych. Część z nich pochodzi o samego jądra, pożniej
+          pojawiają się komunikaty z poźniejszych etapów uruchamiania.
+          Komunikaty te nie są zbyt przyjazne zwykłemu użytkownikowi, a
+          dystrybuje dążą do tego aby być jak najbardzie przyjazne dla
+          użytkownikowi nietechnicznemu, dlatego też ukrywają je za wyżej
+          wspomnianymi ekranami, drugą ważną rzeczą jest ciągły rozwój
+          jądra oraz sprzętu przez to systemy uruchamiają się tak szybko, że
+          nawet mając te komunikaty przed oczami zdołalibyśmy za nimi
+          nadąrzyć.
+        </p>
+        <p>
+          Na szczęście są one zapisywane w plikach dziennika w katalogu
+          <em>/var/log</em> oraz nie tylko, poniżej znajduje się lista miejsc,
+          w których możemy szukać komunikatów rozruchowych.
+        </p>
+        <ul>
+          <li>Pliki dziennika systemu, takie jak: <strong>/var/log/kern.log</strong>,
+            oraz <strong>/var/log/messages</strong> rownież zawierają 
+            komunikaty
+            diagnostyczne jądra oraz nie których usług systemowych.</li>
+          <li>Polecenie <strong>dmesg</strong> przyczym należy pamiętać, że
+            trzeba przepuścić jego wyście przez polecenie
+            <em>less</em>. Danych na pewno będzie więcej niż może pomieścić
+            jeden ekran. Polecenie ty wykorzystuje <em>bufor cykliczny</em>
+            jądra mający ograniczoną wielkość, jednak w nowoczesnych jądrach
+            jest on na tyle duży, że może przechowywać komunikaty rozruchowe
+            przez dłuższy czas.</li>
+        </ul>
+        <p>
+          Nie wszystkie etapy są uwzględnione w wyżej wymienionych miejscach,
+          część z nich może być wypisywana jedynie na konsole przez co przepada
+          bezpowrotnie. Programy typu init nowszej generacji mogą
+          przechwytywać te komunikaty a następnie zapisywać je za pomocą swoich
+          rozwiązań protokołowania (prowadzenia plików dziennika).
+        </p> 
+        <h2 id="5.2.kernelinitandbootoptions">5.2. Inicjowanie jądra i opcje rozruchu</h2>
+        <p>
+          Podczas rozruchu systemu jądro uruchamiane jest następującej 
+          kolejności.
+        </p>
+        <ul>
+          <li>Sprawdzenie procesora</li>
+          <li>Sprawdzenie pamięci</li>
+          <li>Rozpoznawanie magistrali urządzeń</li>
+          <li>Rozpoznawanie urządzeń</li>
+          <li>Konfigurowanie uzupełniających podsystemów jądra (sieci itp.)</li>
+          <li>Montowanie partycji z katalogiem głównym</li>
+          <li>Uruchomienie przestrzeni użytkownika</li>
+        </ul>
+        <p>
+          Jednym z etapów inicjacji jądra jest montowanie katalogu głównego.
+          Generalnie to nic w tym nazwyczajnego oczywiście gdy potrzebne do 
+          tego komponenty są wbudowane w jądro. Jeśli jednak te modułu
+          są w postaci odrębnych modułów, może wówczas zajść potrzeba
+          załadowania ich przed zamontowaniem głównego katalogu. Tym właśnie
+          zajmuje się <strong>początkowych system plików w pamięci RAM - initramfs</strong>.
+        </p>
+        <p>
+          Zakończenie inicjacji i przekazanie uruchamiania procesu <em>init</em>
+          możemy zaobserować w komunikatach diagnstycznych szukając poniższej
+          linii.
+        </p>
+<pre class="code-block">
+Freeing unused kernel memory: ... freed
+</pre>
+        <p>
+          W tym momencie jądro zwalnia zaalokowaną nie używaną pamięć.
+        </p>
+        <h2 id="5.3.kernelparameters">5.3. Parametry jądra</h2>
+        <p>
+          Parametry jądra pozwajają na określenie jego zachowania, na przykład
+          ilość komunikatów diagnostycznych lub podają opcje właściwe dla
+          sterowników urządzeń. Parametry jądra użyte przy jego uruchamianiu
+          dostępne są pliku  <strong>/proc/cmdline</strong>.
+        </p>
+<pre class="code-block">
+BOOT_IMAGE=/vmlinuz-4.19.0-19-amd64 root=UUID=59382884-accb-4106-9d25-44d1ba914530 ro quiet
+</pre>
+        <p>
+          Na parametry mogą składać się pojedyńcze słowa jak np.
+          <code class="code-inline">ro</code> czy <code class="code-inline">quiet</code>
+          lub opcje w formacje <em>klucz=wartość</em>. Opcja <strong>root</strong>
+          jest najważniejszą opcją, ponieważ bez niej jądro nie będzie mogło
+          odnaleźć plików programu typu <em>init</em> i uruchomić go. W
+          większości dystrybucji będzie UUID systemu plików zawierającego 
+          katalog główny.
+        </p>
+        <p>
+          Warto zwrócić uwagę również na opcję <code class="code-inline">ro</code>,
+          która nakazuje jądru zamontować system plików w trybie tylko do
+          odczytu. Ta czynność umożliwi bezpieczene sprawdzenie systemu plików
+          przez program <em>fsck</em>.
+        </p>
+        <p>
+          Jeśli jądro nie rozumie jakiegoś parametru to zostanie on 
+          przezkazany do programu <em>init</em>. Przykładem jest wartość
+          <em>-s</em>, który nakaże uruchomić przestrzeń użytkownika w trybie
+          pojedyńczego użytkownika.
+        </p>
+        <h2 id="5.4.bootloaders">5.4. Programy rozruchowe</h2>
+        <p>
+          Zadaniem <strong>programu rozruchowego</strong> jest załadowanie
+          jądra do pamięci i uruchomienie go z odpowiednimi parametrami. Dla 
+          linuksa dostępnych jest
+          wiele bootloaderów, poniżej znajduje się przedstawiająca je lista.
+        </p>
+        <ul>
+          <li><strong>GRUB</strong> - standardowy program rozruchowy większości
+            dystrybucji Linuksa.</li>
+          <li><strong>LILO</strong> - jeden z pierwszych programów, obecnie
+            został zastąpiony GRUB-em, jednak dalej są dystrybucje takie
+            jak <strong>Slackware</strong> (trzecia najstarsza, funkcjonująca
+            do tej pory dystrybucja), które go używają.</li>
+          <li><strong>SYSLINUX</strong> - można go skonfigurować, tak aby
+            współpracował z wieloma różnymi systemami. Można go spotkać w
+            systemach wbudowanych, a jego pochodna ISOLINUX występuje na
+            obrazach płyt.</li>
+          <li><strong>coreboot</strong> - zamiennik systemu BIOS komputera,
+            coreboot charkteryzuje się wysoką wydajnością. Stosowany jest
+            w odblokowanych chromebookach.</li>
+          <li><strong>Linux Kernel EFISTUB</strong> - moduł jądra pozwalający
+            na załadowanie jądra bezpośrednio z partycji systemowej EFI/UEFI.</li>
+        </ul>
+        <p>
+          Z racji tego iż, duża liczba dystrybucji, korzysta z GRUB. To jego
+          omówimy sobie pod względem praktycznym. <em>Coreboot</em> stosuje
+          się jako zamiennik BIOS-u. A SYSLINUX raczej ma zastosowanie
+          specjalistyczne wykraczające po za ramy tego materiału.
+        </p>
+        <p>
+          Aby program rozruchowy mógł załadować do pamięci jądro systemu, musi
+          uzyskać dostęp do dysku. Nie posiadając żadnych sterowników
+          program rozruchowy uzyskuje dostęp do dysku na poziomie BIOS-u, za
+          pomocą adresowania <strong>Linear Block Addressing</strong> mimo
+          bardzo niskiej wydajności zapewnia ono uniwersalny dostęp do dysku.
+        </p>
+        <h3 id=5.4.1.linuxandsecureboot">5.4.1. Linux i Secure Boot</h3>
+        <p>
+          Na nowych komputerach korzystających z UEFI, mogliśmy spotkać się
+          przypadkiem, gdy komputer odmówił uruchomienia z płyty czy też z
+          pamięci flash. Wiele z nich wyświetlało monit o tym, że włączona
+          jest opcja <strong>bezpiecznego rozruchu</strong>. Opcja ta wymaga
+          podpisu przez zaufaną organizację programu rozruchowego, aby mógł
+          on być uruchomiony. Microsoft w ramach dystrybucji systemu Windows 8
+          wymógł na producentach sprzętu domyślne włącznie tej opcji.
+          Przyczyny nie są mi znane, chciaż podejrzewam chęć utrudnienia
+          instalacji innego systemu nawet Windows 7. Oczywiście tę opcję możemy
+          wyłączyć odszukując opcję w panelu sterowania fimwarem (w BIOSie). 
+          Jeśli obawiamy się o nasze bezpieczeństwo, to wyłączenie tej opcji
+          potrzebne jest wyłącznie na czas instalacji, ponieważ najnowsze
+          wersje programów rozruchowych są już podpisane, więc będą zostaną
+          zaaprobowane przez tę opcję. 
+        </p>
+        <h2 id="5.5.practicalusagegrub">5.5. Praktyczne użycie programu rozruchowego GRUB</h2>
+        <p>
+          GRUB jest obecnie najszerzej wykorzystywanym <em>bootloaderem</em>, 
+          dlatego też
+          warto poznać podstawy jego obsługi, bez owijania w bawełnę, bez
+          wertowania kolejnych kart książek z teorią na temat tego programu
+          rozruchowego. 
+        </p>
+        <h3 id="5.5.1.firstcontactwithgrub">5.5.1. Pierwszy kontakt z GRUBm</h3>
+        <p>
+          Po przejściu procedur testowych firmware naszego komputera bez
+          znaczenia czy jest to BIOS czy UEFI, pokaże nam się tabela z której
+          będziemy mogli wybrać jedną z opcji. Podobna do tej na poniższym
+          rysunku.
+        </p>
+        <p>
+          <img src="https://i.ibb.co/89wFqZ6/grub-boot-manager.png" alt="grub-boot-manager" border="0">
+        </p>
+        <p>
+          Przedstawiona na rysunku tabela może różnić się wyglądem ale
+          funkcjonalność pozostaje taka sama. Na samym dole jest napisane
+          <code class="code-inline">Wyróżniony wpis zostanie wykonany
+          automatycznie za 5s.</code>. Wyróżniony wpis to ten zaznaczony
+          na biało, a po pięciu sekundach zostanie on uruchomiony, ładując
+          system przy standardowych ustawieniach. Za pomocą strzałek możemy
+          poruszać się pod tabeli dokonując wyboru interesującego nas wpisu.
+          Wpis zawierający napis 
+          <code class="code-inline">Opcje zaawansowane dla systemu...</code>
+          jest podmenu zwierającym (najczęściej) wpisy ładujące system z
+          poprzednimi wersjami jądra. Wpis w tabeli możemy edytować
+          wybierając go strzałką następnie naciskając klawisz <em>e</em>. GRUB
+          daje nam możliwość załadowani systemu z własnego wiersz poleceń. Ta
+          opcja przeznaczona jest bardziej zaawansowanych czynności, takich
+          jak na przykład diagnostyka konfiguracji GRUB-a. W tym materiale
+          nie będziemy się jednak zajmować wierszem polecenia. Jeśli ruszymy 
+          się chociaż w menu
+          to odliczanie zostanie przerwane, więc aby załadować system trzeba
+          wybrać wpis. Naciśnięcie jakiego kolwiek klawisza w menu spowoduje
+          przerwanie odliczania. 
+        </p>
+        <h3 id="5.5.2.grubinstallationinbiosmode">5.5.2. Instalacja GRUB w trybie BIOS</h3>
+        <p>
+          Instalacja GRUB w tryb BIOS, jest banalnie prosta. Wystarczy użyć
+          dwóch poleceń. Zazwyczaj korzystając z mainstreamowych dystrybucji
+          przeznaczonych dla użytkowników desktopowowych, nigdy nie będziemy
+          musieli tego robić, ponieważ zrobi to za nas instalator. Natomiast
+          są dwa scenariusze, kiedy niezbędna będzie ponowna instalacja
+          programu GRUB.
+        </p>
+        <ul>
+          <li>Instalacja bardziej zaawansowanych dystrybucji takich jak Gentoo
+            czy Arch Linux</li>
+          <li>Przenoszenie systemu z jednego komputera na drugi za pomocą
+            programów do obrazowania, jak Norton Ghost czy Paragon Backup.</li>
+        </ul>
+        <p>
+          Pierwsze polecenie jest takie same dla każdej dystrybucji. Jako 
+          argument podajemy dysk (urządzenie główne - np. sda, sdb itp.).
+          Polecenie musi zapisać dane bezpośrednio na urządzeniu, więc
+          niezbędne będą uprawnienia administratora.
+        <p>
+<pre class="code-block">
+# grub-install /dev/sdX
+</pre>
+        <p>
+          Drugie polecenie zależy już od dystrybucji. Możemy wówczas
+          spotkać takie polecenie jak:
+        </p>
+<pre class="code-block">
+Debian / Ubuntu i pochodne:
+# update-grub
+Arch Linux i pochodne:
+# grub-mkconfig -o /boot/grub/grub.cfg
+</pre>
+        <p>
+          Drugie polecenie jest odpowiedzialne za wygenerowanie pliku
+          konfiguracyjnego. W przypadku GRUB jest to normalne, ponieważ
+          ze względu na jego skomplikowanie przygotowanie plików składowych
+          (będzie o tym później) spoczywa w rękach twórców samego GRUB-a lub
+          twórców dystrybucji. Użytkownik końcowy otrzymuje gotowe polecenie,
+          które stworzy taki plik konfiguracyjny za niego.
+          Polecenie z Arch Linux, jest dłuższe ale pochodzi bezpośrednio z
+          pakietu. Natomiast w przypadku Debiana i pochodnych mamy dostępne
+          narzędzie przygotowane przez dystrybucję, jest ono bez obsługowe
+          i uruchamia program do poszukiwania innych systemów operacyjnych na
+          innych dyskach podłączonych do komputera. Na Debianie i pochodnych
+          na pewno dostępne jest również to drugie polecenie, jednak lepiej
+          skorzystać z polecenia dedykowanego dla naszej dystrybucji. Ponieważ
+          to tak naprawdę jej twórcy zajmują się przygotowanie GRUB-a do użycia
+          co nie jest takie proste.
+        </p>
+        <h3 id="5.5.3.grubinstallationinefimode">5.5.3. Instalacja GRUB w trybie UEFI</h3>
+        <p>
+          Instalacja w trybie UEFI również składa się dwóch poleceń jednak
+          samo polecenie instalacyjne jest cieco dłuższe od tego z trybu BIOS.
+          Wymaga ona również więcej zachodu niż w trybie BIOS oraz może
+          zakończyć się niepowodzeniem. Tak się zdarza to, przy nie których
+          specyficznych sprzętach.
+        </p>
+        <p>
+          Polecenie instalacyjne wygląda w następująco:
+        <p>
+<pre class="code-block">
+# grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=debian
+</pre>
+        <p>
+          Instalacja GRUB w trybie uefi wymaga, aby podać docelowy system,
+          w tym przypadku jest <code class="code-inline">x86_64-efi</code>,
+          w trybie BIOS, nie trzeba było podawać docelowego systemu gdyż
+          w przypadku BIOS cel <em>i386-pc</em> jest celem domyślnym, kolejny
+          argumentem jest podanie punktu montowania partycji <em>efi</em>.
+          Taka partycja jest zazwyczaj montowana albo bezpośrednio w głównym
+          katalogu - <em>/efi</em> lub wewnątrz katalogu <em>/boot</em> -
+          <em>/boot/efi</em>. Ostatnim argumentem jest
+          <code class="code-inline">--bootload-id</code> i tutaj panuje pewnego
+          rodzaju niewiadoma. Bo jeśli korzystamy instalujemy program 
+          rozruchowy
+          pod Arch Linuxem, to <em>bootloader-id</em> to <strong>GRUB</strong>.
+          z kolei pod Debianem musi być to <strong>debian</strong>. Te nazwy
+          wynikają z faktu potrzeby podpisania programu rozruchowego aby
+          mógł on być uruchamiany z włączoną opcją bezpiecznego rozruchu. Warto
+          dodać, że to co podamy w tej opcji będzie wyświetlane w
+          <em>boot menu</em> komputera. Jeśli chcemy użyć jakiejś
+          niestandardowej nazwy i nie za bardzo przejmujemy się 
+          <em>secure bootem</em>,
+          to wówczas możemy użyć opcji <em>--no-uefi-secure-boot</em>.
+        </p>
+        <p>
+          Do w pełni zainstalowanego GRUB-a potrzebujemy tylko pliku
+          konfiguracyjnego. Do tego celu możemy wykorzystać polecenia podane
+          w punkcie odnośnie instalacji GRUB w trybie BIOS.
+        </p>
+        <h3 id="5.5.4.changegruborder">5.5.4. Zmiana koleności w menu GRUB</h3>
+        <p>
+          Aby zamknąć już temat GRUB-a, przjedziemy do ostatniego zagadnienia.
+          Rozważmy taki przypadek. Mamy jeden komputer w domu, z którego nie
+          korzystamy tylko my. Mamy pozwolenie na wydzielenie pozostałej wolnej
+          części dysku (w duży uproszczemiu) i obok Windows 10 chcemy
+          zainstalować jakąś dystrybucje Linuksa. Załóżmy, że instalacja się
+          powiodła. Niestety mamy problem, gdyż współużytkownicy komputera
+          narzekają, że jak uruchamia się komputer to uruchamia się Linux a nie
+          Windows. Uruchamiając komputer widzisz, że początkowym i domyślnym
+          wyborem w menu GRUB-a jest Linux, a Windows z kolei znajduje się na
+          samym końcu listy.
+        </p>
+        <p>
+          Pierwsza myśl jest przychodzi nam do głowy to ręczna edycja pliku
+          GRUB-a. Na pewno jest jakieś rozwiązanie. Zatem wyedytowaliśmy plik
+          zapisaliśmy zmiany i póki co jest spokój. Wszyscy zadowoleni,
+          korzystają z komputera. Któregoś dnia siedząc przy komputerze i
+          korzystając z naszej dystrybucji, zostajemy poinformowani o tym, że
+          są nowe aktualizacje. Instalujemy je zatem. Aktualizacje się 
+          zainstalowały, zauważyliśmy że była również aktualizacja jądra.
+          Dobra, wyłączamy komputer. Następnego dnia gdy nasz współużytkownik
+          komputera chce skorzystać z niego, znów mu się uruchamia Linux a
+          nie Windows. Jaki z tego morał? Instalacja nowego jądra wymaga 
+          z aktualizowania pliku konfiguracjnego GRUB-a, aby można było
+          korzystać ze świerzo zainstalowanego jądra automatycznie po ponownym
+          uruchomieniu komputera, więc nie należy ręcznie zmieniać ręcznie
+          pliku konfiguracjnego GRUB-a ponieważ aktualizacja czy to jądra
+          czy samego programu rozruchowego nadpisze te zmiany.
+        </p>
+        <p>
+          Sposobów wykonania tej czynności jest kilka, ja znam jedną. Jak wiemy
+          plik konfiguracjny jest tworzony z plików składowych. Pliki te 
+          znajdują się w katalogu <em>/etc/grub.d</em>, oto listing tych plików
+          z mojego komputera:
+        </p>
+<pre class="code-block">
+00_header
+05_debian_theme
+10_linux
+20_linux_xen
+30_os-prober
+30_uefi-firmware
+40_custom
+41_custom
+README
+</pre>
+        <p>
+          Jeśli obserwowaliśmy generowanie pliku konfiguracjnego GRUB-a, to już
+          powinniśmy znaleźć potrzebny nam plik. A jeśli nie to przyjrzyjmy się
+          nazwom tych plików. Mamy
+          <code class="code-inline">header, debian_theme, linux, linux-xen</code>
+          i <code class="code-inline">os-prober</code>. <em>OS</em> to akronim
+          od <em>Operating System</em>, z kolei <em>prober</em> oznacza to 
+          samo co <em>der Untersucher</em> po niemiecku, czyli kontroler/badacz.
+          Czyli chodzi o kontrolera systemów operacyjnych. Jeśli wpiszemy
+          <em>os-p</em> w wierszu polecenia i naciśniemy tab, dowiemy się, że
+          istnieje nawet takie polecenie, wyszukaniu strony podręcznika dla
+          wiem że jest narzędzie odpowiedzialne za poszukiwanie innych systemów
+          operacyjnych na wszystkich dyskach komputera. Więc znamy już część
+          konfiguracji GRUB-a odpowiedzialną za Windows. Teraz jak zmienić
+          kolejność? Otóż przed każdą z tych nazw stoi liczba, wystarczy
+          zmienić nazwę, tak aby ten plik znajdował się przed plikiem
+          <code class="code-inline">10_linux</code>. 
+        </p>
+<pre class="code-block">
+$ sudo mv /etc/grub.d/30_os-prober /etc/grub.d/09_os-prober
+</pre>
+        <p>
+          Teraz trzeba już tylko wygenerować nowy plik GRUB-a. Rozwiązanie
+          powinno być odporne aktualizacje. Nie jest to może najpopularniejsze
+          rozwiązanie, ale działa.
+        </p>
+        <h2 id="5.6.usagerefindasbootmanager">5.6. Wykorzystanie rEFInd jako menedżera rozruchu</h2>
+        <p>
+          Instalacja GRUB-a w trybie UEFI może się nie powieść, gdyż jednym z
+          jego etapów jest zapisanie w pamięci firmware-u informacji o nowym
+          programie rozruchowym o nazwie podanej podanej w parametrze
+          <em>bootloader-id</em>. Z błedem jak ja się spotkałem by: 
+        </p>
+<pre class="code-block">
+Could not prepare boot variable: No space left on device
+</pre>
+        <p>
+          Nie które firmware mają ograniczoną ilość pamięci przechowywującej
+          wskazania programów rozruchowych. Mimo usunięcia jednej ze zmiennych
+          problem dalej występował. Usunięcie wszystkich spowodowało tak
+          jakby uziemienie komputera, ponieważ nie był on wstanie uruchomić
+          się z żadnego podpiętego dysku. Przełączenie trybu na BIOS, na tym
+          sprzęcie nie było możliwe. Na sprzęcie tej samej klasy oraz tego
+          samego producenta, ale nowszym spotkałem się z problemem z takim
+          problemem, iż system zainstalował się poprawnie nawet GRUB w trybi
+          UEFI, ale system nie był wstanie wystartować z wbudowanej pamięci,
+          ani z system zainstalowanym w trybie UEFI ani w trybie BIOS.
+        </p>
+        <p>
+          Rozwiązanie może i jest proste, niestety może nie za bardzo
+          estetyczne oraz wymaga użycia dodatkowego pendrive-a. Pamięć USB nie
+          musi być duża, wystarczy 1GB. Polega ono na użyciu odrębnego
+          mendżera rozruchu jakim jest <strong>rEFInd</strong>. Program ten
+          przeszukuje dyski w poszukiwaniu systemów operacyjnych i
+          uruchamia je.
+        </p>
+        <p>
+          Sama dystrybucja przy wykorzystaniu programu <em>rEFInd</em> może
+          być zainstalowana trybie BIOS.
+          W środowisku LiveCD instalujemy pakiet <strong>refind</strong>. 
+          Podczas instalacji zostanie nam wyświetlony monit z pytaniem czy
+          zainstalować <em>rEFInd</em> na partycji ESP. Wybieramy opcję
+          <strong>No</strong>.
+        </p>
+<pre class="code-block">
+# apt update
+# apt install refind
+</pre>
+        <p>
+          Po zainstalowaniu, tworzymy na dysku USB 1 jedną partycję pod system
+          plików FAT32, następnie należy ją sformatować.
+        </p> 
+<pre class="code-block">
+# dd if=/dev/zero bs=1M of=/dev/sdX count=1
+# echo ',,b,' | sfdisk /dev/sdX
+# mkfs.vfat -F32 /dev/sdXY
+</pre>
+        <p>
+          W powyższym przykładzie <code class="code-inline">X</code> to litera
+          porządkowa dysku, z kolei <code class="code-inline">Y</code> to 
+          liczba partycji. Partycji nie musimy montować. Poniższe polecenie
+          zainstaluje na przygotowanym dysku program <em>rEFInd</em>. 
+        </p>
+<pre class="code-block">
+# refind-install --usedefault /dev/sdXY --alldrivers
+</pre>
+        <p>
+          Po zainstalowaniu programu, możemy zrestartować komputer a następnie
+          w ustawienia UEFI, ustawić kolejkę rozruchu tak, aby komputer
+          startował z pendrive-a, na którym zainstalowaliśmy <em>rEFInd</em>.
+          W menu powinien pojawić się wpis z Linuksem zainstalowanym naszym
+          dysku. 
+        </p>
+        <h1 id="6.startinguserspace">6. Uruchamianie przestrzeni użytkownika</h1>
+        <p>
+          Istotnym momentem podczas startu systemu operacjnego jest
+          uruchomienie przez jądro procesu <em>init</em> oznacza to, że pamięć
+          oraz procesor są gotowe normalnej pracy. Po za tym uruchomie tego
+          programu może przynieść również korzyść dydaktyczną, pozwalając
+          obserwować montowanie różnych komponentów w gotowy do pracy system.
+          Budowa programów typu <em>init</em> jest bardzie modułowa, więc jeśli
+          chcielibyśmy zmienić coś w tym procesie (uruchamiania przestrzeni
+          użytkownika) nie potrzebujemy umiejętności niskopoziomowego
+          programowania oraz trzymania się ściśle określonej ścieżki, jak ma to
+          miejsce w przypadku jądra. Uruchamianie przestrzeni użytkownika 
+          zostało przedstawione na poniższej liście kroków: 
+        </p>
+        <ol>
+          <li>Jądro uruchamia program typu <em>init</em>.</li>
+          <li>Uruchamiane są usługi niskiego poziomu takie jak <em>udevd</em> 
+              czy <em>syslogd</em>.</li>
+          <li>Sieć zostaje skonfigurowana.</li>
+          <li>Uruchamiane zostają pozostałe usługi jak (<em>cron</em>, 
+              <em>cups</em>, itp.)</li>
+          <li>Startują aplikacje wyskokiego poziomu, ekrany logowania oraz
+              środowiska graficzne.</li>
+        </ol>
+        <h2 id="6.1.initprocess">6.1. Proces init</h2>
+        <p>
+          Głównym zadaniem procesu typu <strong>init</strong> jest uruchamianie,
+          zatrzymywanie i ponowne uruchamianie procesów istotnych dla pracy 
+          całego systemu, chciaż jego najnowsze implementacje mają o wiele
+          więcej zadań, to jest to program jak każdy inny. Możemy go znaleźć
+          w katalogu /sbin. W dystrybucja Linuksa ma zastosowanie kilka różnych
+          implementacji procesu <em>init</em>. Na poniższej liście znajdują się
+          te wciąż używane.
+        </p>
+        <ul> 
+          <li><strong>System V init</strong> - tradycyjna wersja tego procesu
+            obecnie została wyparta z użycia w dystrybucjach głównego nurtu, co
+            przez nie których uznane za zły zabieg. Dalej rozwiajane są
+            dystrybucje, które są forkami tych głównych, ale opierają się, nie
+            tylko o <em>sysvinit</em> ale dają możliwość wyboru innego procesu
+            typu <em>init</em> niż <em>systemd</em>.</li>
+          <li><strong>systemd</strong> - najnowsza implementacja tego procesu,
+            wykorzystywana w głównych dystrybucjach.</li>
+          <li><strong>runit</strong> - alternatywa dla <em>systemd</em>, ma
+            zastoswanie nie tylko dla dystrybucji Linuksa ale innych systemów
+            zgodnych ze standardem POSIX. Jego działanie opiera się o 3 etapy.
+            Wykorzystywany jest w dystrybucjach, takich jak AntiX oraz Void
+            Linux.</li>
+          <li><strong>OpenRC</strong> - alternatywa dla <em>systemd</em>,
+            stosowana przez takie dystrybucje jak Gentoo oraz Alpine Linux. 
+            Ma on podobne możliwości do <em>systemd</em>.</li>
+        </ul>
+        <h2 id="6.2.runlevels">6.2. Poziomy uruchomienia</h2>
+        <p>
+          <strong>Poziomem uruchomienia</strong> nazywamy stan maszyny, w
+          którym na dany moment uruchomione są wybrane komponenty. Są one
+          oznaczne liczbą od 0 do 6. Podczas pracy systemu, większość czasu
+          spędzamy na tylko na jednym poziomie uruchomienia, z momencie 
+          zamykania systemu lub uruchamiania go ponownie przełączamy się na
+          inny poziom odpowiedzialny za zatrzymanie pracy jądra oraz poprawne
+          zakończenie pracy usług. Na poziomach uruchomienia bazuje tradycjny 
+          <em>sysvinit</em>.
+        </p>
+        <p>
+          Za pomocą poniższego polecenia możemy, sprawdzić na jakim poziomie
+          uruchomienia się znajdujemy:
+        </p>
+<pre class="code-block">
+$ who -r
+</pre>
+        <p>
+          Polecenie zwraca również moment załączenia wyświetlanego poziomu.
+        </p>
+        <p>
+          Poziomy uruchomienia służą okreslaniu stanu systemu operacyjnego.
+          Może on być stanie uruchamiania, zamykania, trybie konsoli
+          (serwery, instalacje bez środowiska graficznego), trybie awaryjny
+          (tryb pojedyńczego użytkownika, będzie o tym pod koniec rozdziału).
+          5 poziom uruchomienia oznacza najczęściej w pełnii uruchomiony system
+          wraz z trybem graficznym.
+        </p>
+        <p>
+          Dzisiaj poziomy uruchomienia są domeną programu <em>sysvinit</em>.
+          Dystrybucje z <em>systemd</em> wykorzystują je, aby zapewnić
+          obsługę z usług, które nadal korzystają ze skryptów <em>sysvinit</em>.
+        </p>
+        <h2 id="6.3.initidentify">6.3. Rozpoznawanie programu typu init.</h2>
+        <p>
+          Identyfikacja programu typu init polega, na przeczytaniu
+          oprogramowania oferowanego przez dystrybucje. Jeśli program typu
+          <em>init</em> nie jest wyszczególniony, możemy przyjąć ze jest to
+          <em>systemd</em>. Wiele dystrybucji posiada w swoich cechach 
+          wymienioną informacje o tym że używa innego programu typu 
+          <em>init</em> niż <em>systemd</em>.
+        </p>
+        <h2 id="6.4.introductiontochoosedinitprograms">6.4. Wprowadzenie do wybranych programów typu init</h2>
+        <p>
+          Ze względu na fakt, jak ograniczonych ram tego materiału. Nie będę
+          szczegółowo zagłebiał się w tematykę omawianych tutaj programów typu
+          <em>init</em>. Opisze ich zalety, na czym opiera się ich
+          działanie, jakich plików używają oraz co najważniejsze dla nas na
+          tym etapie w jaki sposób możemy zarządzać usługami przy użyciu tych
+          programów. Pierwszym jaki procesem typu <em>init</em> jaki poruszę
+          z racji popularności jest <em>systemd</em>. 
+        </p>
+        <h3 id="6.4.1.systemd">6.4.1. Systemd</h3>
+        <p>
+          <strong>Systemd</strong> wykonując swoje zadania osiąga
+          <strong>cel</strong>. Cel jest defiowany przez nas wraz z wszystkimi
+          zależnościami (wymaganiami) oraz z góry ustalonym momentem
+          realizacji tego celu. Następnie system rozwiązuje wszystkie
+          zależności oraz wykonuje postawione przed nim zadanie. Wynika z tego
+          jedna z jego cech, możemy opoźnić np. start usługi do momentu gdy
+          będzie ona niezbędna. 
+        </p>
+        <p>
+          Poza obsługą usług, której wszyscy oczekują od programu <em>init</em>,
+          <em>systemd</em> stara się z integrować ze sobą wiele klasycznych
+          usług takich jak <em>cron</em> czy <em>inetd</em>.
+        </p>
+        <p>
+          Podczas uruchamiania usług <em>systemd</em> nie kieruje się żadną
+          kolejnością, co więcej większość jego konfiguracji stara unikać
+          jakiej kolwiek sekwencyjności, nawet pod czas spełniania zależności. 
+          Takie działanie pozwala na zachowanie
+          dużej dozy elastyczności w procesie uruchamiania systemu.
+        </p>
+        <p>
+          W zanadrzu swoich możliwości <em>systemd</em> może: montować systemy
+          plików, monitorować gniazda sieciowe czy uruchamiać zegary. Takie
+          rodzaju funkcje w tej impementacji programu typu <em>init</em>
+          nazywane są <strong>jednostkami</strong> (ang. <em>units</em>). A
+          operacja uruchomienia takiej jednostki nazywana jest
+          <strong>aktywowanie</strong>. Typ jednostek <em>systemd</em> dostępne
+          są na stronie podręcznika: <em>systemd(1)</em> (1 w nawiasie to numer
+          rozdziału).
+        </p>
+        <p>
+          Każda jednostka może mieć zależności wobec innej jednostki. Może
+          wymagać lub chcieć jej działania na potrzeby zadania, które sama
+          realizuje. Zależności są definiowane w plikach jednostek dostępnych
+          w dwóch miejscach, w konfiguracji globalnej skierowanej do całego
+          systemu - <strong>/usr/lib/systemd/system</strong> oraz w definicjach
+          lokalnych - <strong>/etc/systemd/system</strong>. Jeśli będziemy
+          musieli wprowadzić jakieś zmiany w konfiguracji to zalecanym miejscem
+          jest katalog definicji lokalnych. Rozwiązywanie zależności 
+          najczęściej polega na uruchomieniu samej jednostki, wobec której
+          ważna dla nas jednostka jest zależna. Liczy się czy natomiast czy
+          daną jednostkę udało się aktywować lub czy jednostka jest już
+          uruchomiona w trakcie uruchamiania naszej jednostki, tego typu
+          uwarunkowania definiowane przez typy zależności. Poza zależnościami
+          wobec innych jednostek, mogą występować również zależności bazujące
+          na stanie (istnieje, nie istnieje, jest niepusty) elementów takich
+          jak ścieżka, katalog czy plik.
+        </p>
+        <p>
+          Uruchomienie jednostki nazywane jest aktywowaniem. Dlaczego nie
+          włączeniem? Otóż, aby uruchomić należy ją aktywować poniższym
+          poleceniem:
+        </p>
+<pre class="code-block">
+$ sudo systemctl start unit.service
+</pre>
+        <p>
+          To czy każdą jednostkę możemy tak sobie uruchomić zależy od jej
+          zależności. Zależności można definiować na odwrót, użwając sekcji
+          <em>[Install]</em>, a wewnątrz niej typów zależności:
+          <strong>RequiredBy</strong> oraz <strong>WantedBy</strong>,
+          najczęściej wykorzystywana jest ta druga opcja. Za pomocą tej sekcji
+          oraz wymienionych zależności, jednostki instalowane są w celach.
+          Większość usług wykorzystywanych w linuksach, posiadają zależność
+          <em>WantedBy</em> ustawioną na cel <em>multi-user.target</em>. Jest
+          to spowodowane tym, że samo istnienie pliku jednostki może powodować
+          jej aktywacje, co w przypadku usług sieciowych nie jest porządane.
+          Zatem włączenie jednostki, jest w przypadku <em>systemd</em>
+          równoznaczne z włączeniem jej do zależności jednostki zapisanej w
+          zależności odwrotnej (cele w <em>systemd</em>, też są jednostkami ale 
+          ich rola raczej ogranicza się do grupowanie różnego rodzaju innych
+          jednostek). Wydaje mi się, że wszystko rozjaśni się gdy zobaczymy
+          polecenie służące do włączania.
+        </p>
+<pre class="code-block">
+$ sudo systemctl enable unit.service
+</pre>
+        <p>
+          Dezaktywacja oraz wyłaczenie jednostki to kolejno:
+        </p>
+<pre class="code-block">
+#Dezaktywacja:
+$ sudo systemctl stop unit.service
+
+#Wyłączenie:
+$ sudo systemctl disable unit.service
+</pre>
+        <p>
+          Do obsługi <em>systemd</em> używamy pojedyńczego polecenia
+          <code class="code-inline">systemctl</code>, ma ono bardzo wiele opcji
+          jednak na poziomie podstawowym wystarczym to co napisałem powyżej
+          oraz sprawdzenie stanu jednostki poleceniem:
+        </p>
+<pre class="code-block">
+$ sudo systemctl status unit.service
+</pre>
+        <p>
+          Dawniej w czasch powszechnego panowania <em>sysvinit</em> oraz
+          obecnie w dystrybucja wykorzystujących ten rodzaj programu
+          typu <em>init</em>, gdy usługa definiowała zasób, z którego
+          korzystały inne usługi, to musiały one zostać opóźnione do momentu
+          uruchomienia usługi macierzytej oraz udostępnienia przez nią
+          zasobu. Za pomocą <em>systemd</em> możemy na podstawie dokumentacji
+          usługi utworzyć jednostkę zasobu. Taka jednostka zostanie uruchomiona
+          w momencie aktywowania jednostki macierzystej usługi. Dzięki temu
+          inne usługi korzystające z tego zasobu będą mogły zostać aktywowane
+          w tym samym czasie co ta usługa. Usługi nie zrócą żadnego błędu,
+          ponieważ zasób jest dostępny. W gdy coś spróbuje uzyskać dostęp do
+          tego zasobu, to zostanie zablokowane przez <em>systemd</em> do
+          momentu pełnego uruchomienia usługi i przekazania jej kontroli nad
+          zasobem. Jeśli podczas próby dostępu do zasobu napłyną jakieś dane
+          to zostaną one zbuforowane i przekazne do usługi, gdy przejmie ona
+          pieczę na zasobem. Cała ta procedura pozwala na znaczne
+          przyspieszenie uruchamiania systemu.
+        </p>
+        <p>
+          <em>Systemd</em> zapewnia pewien stopień zgodności z tradycyjnym
+          <em>sysvinit</em>, dla usług nie wspierających plików jednostek.
+          Ta funkcjonalność jest na tyle rozwinięta, że pozwala na podobne
+          zarządzanie taką usługą, jakoby miała ona plik jednostki.
+        </p>
+        <p>
+          Implementacja procesu typu <em>init</em> jaką jest <em>systemd</em>
+          jest na prawdę dość sporym tematem. Więc zostanie on poruszony
+          ponownie na tej stronie.
+        </p>
+        <h3 id="6.4.2.sysvinit">6.4.2. Proces typu init w stylu System V</h3>
+        <p>
+          Klasyczny proces typu <em>init</em> jakim jest 
+          <strong>sysvinit</strong>, opiera się o poziomy uruchomienia oraz
+          wykonywane w nich polecenia. Polecenia te opierają się na
+          sekwencyjny wykonywaniu skryptów umieszczanych w odpowiednich
+          katalogach. Najważniejszym plikem jest w tym przypadku plik
+          <em>/etc/inittab</em>, w jego zawrtości znajdują się wspomniane już
+          polecenia, rozpisane dla poszczególnych poziomów uruchomienia.
+          Polecenie dla 5 poziomu uruchomienia może wyglądać w następujący
+          sposób:
+        </p>
+<pre class="code-block">
+l5:5:wait:/etc/rc.d/rc 5
+</pre>
+        <p>
+          To polecenie przy wejściu na 5 poziom uruchomi wszystkie skrypty w
+          katologu <em>/etc/rc5.d</em>, o ile będą miały odpowiednią nazwę.
+          Słowo <code class="code-inline">wait</code> spowoduje, że proces
+          <em>init</em> nie przejdzie na kolejny poziom uruchomieniowy do
+          momentu zakończenia pracy tego polecenia. Inne <strong>akcje</strong>
+          niż <code class="code-inline">wait</code> mogą
+          uruchamiać ponownie polecenie po jego zakończeniu czy definiować
+          co należy zrobić po naciśnięciu kombinacji klawiszy
+          <em>Ctrl+Alt+Delete</em>, z kolei akcja <strong>initdefault</strong>
+          określa domyślny poziom uruchomieniowy dla przestrzeniu użytkownika.
+        </p>
+        <p>
+          Skrypt zawarte w katalogu <em>rc5.d</em>, który jest akronimem od
+          polecenia <em>run command</em>. Posiadają dość specyficzne nazwy,
+          zaczynają się one od wielkiej litery <em>S</em> lub <em>K</em>.
+          Następny jest numer, na końcu zaś znajduje się nazwa własna. Jeśli
+          wylistujemy ten katalog bardziej szczegółowo, to zauważymy, że te
+          skrypty to tak naprawdę dowiązania symboliczne. Wiele dowiązań w
+          jednym katalogu nazywane jest <strong>farmą dowiązań</strong>.
+          Te dowiązania zawarte w katalogach <em>rc</em> wskazują 
+          na właściwe
+          skrypty znajdujące się w katalogu <em>/etc/init.d</em>.
+        </p>
+        <p>
+          Wielkie litery na początku nazw dowiązań oznaczają operację
+          podejmowaną na usłudze czy ma ona zostać uruchomiony - <em>S</em>
+          (ang. <em>start</em>), czy jej działanie ma zostać zakończone
+          - <em>K</em> (ang. <em>kill</em>). Te czynności wykonywane są
+          poprzez uruchomienie skryptu z argumentem <em>start</em> lub 
+          <em>stop</em>.  Numery w nazwach
+          określają miejsce tej czynności w sekwencji uruchomieniowej
+          <em>sysvinit</em>. Usługi niskiego poziomu jak np. <em>syslogd</em>
+          uruchamiane są bardzo wcześnie (mają niskie numery), demony
+          świadczące użytkownikom jakieś usługi zazwyczaj mają numery powyżej
+          90. Nazwa wskazuje na uruchamianego daemona.
+        </p>
+        <p>
+          Zatem jeśli nie chcemy, aby jakaś usługa startowała należy wówczas
+          zmienić nazwę dowiązania. Warto jednak pozostawić sobie późniejszą
+          możliwość jej włączenia. Powiedzmy że chcemy wyłączyć daemona
+          <em>httpd</em> jego nazwa to <em>S99httpd</em>, więc najlepiej
+          postawić na początku nazwy znak podkreślenia:
+        </p>
+<pre class="code-block">
+$ mv /etc/rc5.d/S99httpd /etc/rc5.d/_S99httpd
+</pre>
+        <p>
+          W ten sposób daemon zostanie wyłączony z sekwencji uruchomieniowej.
+          Jeśli chcemy uruchomić/zatrzymać usługę na żądanie, należy 
+          uruchomić
+          skrypt z katalogu <em>/etc/init.d</em> z argumentem <em>start</em>
+          lub <em>stop</em>.
+        </p>
+<pre class="code-block">
+#Uruchomienie:
+$ sudo /etc/init.d/httpd start
+
+#Zatrzymanie:
+$ sudo /etc/init.d/httpd 
+</pre>
+        <p>
+          Wraz z <em>sysvinit</em> i nie tylko, rozprowadzane jest narzędzie, 
+          które działa w systemach nie używających już <em>sysvinit</em>.
+          <strong>Run-parts</strong>, jest to bardzo proste na rzędzie, które
+          uruchamia wszystkie pliki wykonywalne w danym katalogu 
+          według ściśle określonego porządku.
+          Implementacja tego narzędzia zależy od dystrybucji. Te bardziej
+          złożone pozwalają na użycie wyrażenia regularnego do określenia
+          porządku ich uruchamiania. Na potrzeby tego materiału wystarczy
+          wiedzieć, że takie narzędzie w ogóle istnieje.
+        </p>
+        <p>
+          Wspomnieniem o <em>run-parts</em> kończymy wprowadzenie do programów
+          typu <em>init</em>. Omówiłem tylko te dwa, gdyż są w
+          najpowszechniejszym użyciu. Poznając podstawy Linuksa, nie ma co
+          zniechęcać się obszernymi szczegółami. Najważniejsze dla nas na ten
+          moment jest uruchamienia/zatrzymywanie usług oraz włączanie i
+          wyłączanie ich z sekwencji uruchomieniowej. W ramach ćwiczeń możemy
+          wydedukować jak należy włączyć usługę, do sekwencji uruchomieniowej
+          przy procesie <em>init</em> w stylu <em>System V</em>, chociaż nie
+          powinno to zająć więcej niż 30 sekund.
+        </p>
+        <h2 id="6.5.shutdownthesystem">6.5. Wyłączanie systemu</h2>
+        <p>
+          Jedynym prawidłowym sposobem na wyłącznie systemu, jest użycie
+          polecenia <strong>shutdown</strong>. Wyłączyć system możemy na
+          dwa różne sposoby. Pierwszym z nich jest jego 
+          <strong>programowe zamknięcie systemu oraz wyłącznie zasilania</strong>
+          osiągane przez poniższe polecenie. 
+        </p>
+<pre class="code-block">
+$ sudo shutdown -h now
+</pre>
+        <p>
+          Do wyżej wymienionego celu możemy, użyć polecenia, które może być
+          nieco bardziej powszechne:
+        </p>
+<pre class="code-block">
+$ sudo poweroff
+</pre>
+        <p>
+          Ma ono działanie identyczne działanie jak polecenie z przykładu
+          powyżej. 
+        </p>
+        <p>
+          Przy poleceniu <code class="code-inline">shutdown</code> należy
+          wybrać czy system ma zostać zamknięty, zatrzymany, lub uruchomiony
+          ponownie. Kolejnym wymaganym argumentem jest czas. Najczęściej
+          używany jest argument <code class="code-inline">now</code> co
+          przy przyjmowanym zapisze czasonym jest <em>+0</em> minut.
+          Zapis czasowy możemy określić w minutach jak podałem powyżej lub
+          lub przy zapisie <em>hh:mm</em> , który pozwala określić konkretną
+          godzinę zamknięcia systemu.
+        </p>
+        <p>
+          Innym sposobem na zamknięcie systemu jest ponowne uruchomienie
+          komputera. System będzie musiał zostać poprawnie zamknięty, aby
+          uruchomić komputer ponownie. W tym celu możemy użyć polecenia, 
+        </p>
+<pre class="code-block">
+$ sudo shutdown -r now
+
+#lub
+
+$ sudo reboot
+</pre>
+        <p>
+          Wyłączenie systemu dla <em>systemd</em> oznacza aktywację jednostek
+          zatrzymywania (<em>systemd</em>, posiada wiele typów jednostek), dla
+          <em>sysvinit</em> przejście z poziomu 5 na 6 lub 0.
+        </p>
+        <h2 id="6.6.initramfs">6.6. Początkowy system plików w pamięci RAM</h2>
+        <p>
+          <strong>initramfs</strong> czy <strong>initrd</strong>, z tych nazw
+          korzysta się zamiennie mimo iż oznaczają coś innego, to odnoszą się
+          do tego samego komponentu, czyli <strong>początkowego systemu plików
+          w pamięci RAM</strong>. Jest to bardzo proste archiwum
+          przechowujące mini przestrzeń użytkownika z mini katalogiem głównym.
+          Zadaniem <em>initramfs</em> jest stworzenie optymalnego środowiska
+          dla narzędzi pozwalających na załadowanie do jądra zewnętrznych
+          modułów, wśród których może znajdować się sterownik dysku, co pozwoli
+          zamontować już właściwyw katalog główny z dysku i przejść na kolejne
+          etapy uruchamiania systemu. 
+        </p>
+        <p>
+          Wykorzystując nasz system w stopniu podstawowym raczej nie będziemy
+          mieć styczności z <em>initramfs</em>, chyba że używamy bardziej
+          zaawansowanej dystrybucji, która może wymagać załadowania do niego
+          dodatkowych modułów. Takie przypadki będą zazwyczaj opisane w na
+          stronach dokumentacji dystrybucji. Przykładem takiego działania może 
+          być
+          szyfrowana partycja z katalogiem głównym, w takich dystrybucjach
+          jak Arch Linux. Do obsługi początkowego systemu w pamięci RAM
+          służa takie polecenia jak <strong>mkinitramfs</strong> lub
+          <strong>update-initramfs</strong>. 
+        </p>
+        <p>
+          System plików pamięci RAM może zostać pominięty w momencie gdy, w
+          jądrze znajdują się wszystkie potrzebne mu sterowniki, jednak
+          obecnie nie jest to praktykowane.
+        </p>
+        <p>
+          Istnieją dystrybucje, których działanie opiera się na 
+          <em>initramfs</em>, pliki dystrybucji znajdują się w tym archiwum, a
+          oprogramowanie jest znajduje się wówczas w archiwach <em>squashfs</em>
+          montowanych podczas w odpowiednich miejscach w systemie podczas
+          jego ładowania. Taką dystrybucją jest na przykład TinyCore, którego
+          obraz płyty waży 21 MB.
+        </p>
+        <h2 id="6.7.oneusermode">6.7. Tryb jednego użytkownika</h2>
+        <p>
+          Tryb pojedyńczego użytkownika, jest swojego rodzaju trybem
+          awaryjnym na Linuksie, a jedynym dostępnym użytkownikiem będzie 
+          superużytkownik. W tym trybie zostanie załadowane jądro, za
+          montowany katalog główny, a proces typu init zapewni dostęp tylko
+          do niezbędnych dla działania systemu usług, wyeliminowywując tym 
+          samym potencjalnie wadliwe komponenty. To środowisko ma za zadanie
+          umożliwić nam naprawę systemu. 
+        </p>
+        <p>
+          Ze względu na to, iż to środowisko może nie zapewnić potrzebnych
+          do takiej naprawy narzędzi, najlepiej jest skorzystać jednak z 
+          obrazu <strong>LiveCD</strong>, który pozwala na korzystanie z
+          systemu bez konieczności jego instalacji. Jednak na podstawie wiedzy
+          zawartej w tym materiale nie sądze, aby można byłoby naprawić system.
+          Dlatego też jeśli zdarzy się awaria systemu, to najlepszym
+          rozwiązaniem na teraz jest zabezpieczenie osobistych danych i
+          przeinstalowanie systemu, chodziaż nie chce nikogo zniechęcić do
+          grzebania w systemie, w ten sposób możemy się wiele nauczyć. Z 
+          drugiej strony, ciężko jest aby system przestał działać tak sam z
+          siebie. Dlatego jesli tak się stało, więcej niż raz to warto zgłość
+          problem społeczności za pomocą jednego z kanałów
+          udostepnionych na stronie dystrybucji i zmienić dystrybucje na jakiś
+          czas. Linux to głównie narzędzie do pracy na naszym komputerze, na
+          tym etapie - podstawowym.
+        </p>
+        <h1 id="7.systemconfigurationandusers">7. Konfiguracje systemowe oraz użytkownicy</h1>
+        <p>
+          W tym rozdziale zajmiemy się drobnymi konfigracjami, nie których
+          komponentów systemowych takich jak <em>syslog</em> czy <em>cron</em>
+          zajmiemy się również tematem czasu systemowego na Linuksie. Rozdział
+          zakończymy dodatkową wiedzą, (choć nadal w stopniu podstawowym) na
+          temat użytkowników.
+        </p>
+        <p>
+          Wszystkie te powyższe zagadnienia łączy jedna rzecz, ich pliki
+          konfiguracyjne znajdują się w katalog <strong>/etc</strong> i od
+          omówienia tego katalogu zaczniemy.
+        </p>
+        <h2 id="7.1.etcdirectory">7.1. Katalog /etc</h2>
+        <p>
+          Jak wiemy z opisu hierarchii systemu plików (katalogu głównego), w 
+          katalogu <strong>/etc</strong> przechowywane są różnego rodzaju
+          konfiguracje, i to nie zależnie do wielkości czy istotności programu
+          w systemie. Kiedyś każdy z programów przechowywał luzem swoją
+          konfigurację tym katalogu. Obecnie jak możemy się przekonać większość
+          zawartości <em>/etc</em> stanowią podkatalogi. Oczywiście wiele
+          plików nadal się w nim znajduje, najczęsciej są to takie pliki
+          jak <em>/etc/fstab</em> czy
+          <em>/etc/passwd</em> lub <em>/etc/shadow</em> służące do
+          przechowywania informacji o użytkownikach. Katalogi w <em>/etc</em>
+          mają nazwy przeważnie odpowiadające nazwom programów, które
+          konfigurują. Wyjątkiem są katalogi z końcówką <em>.d</em>. Pliki
+          konfiguracyjne
+          zostały umieszczone w tych katalogach, aby nie zostały one nadpisane
+          przez aktualizacje pakietów. Obecnie nie ma to już miejsca, a mimo
+          to konfiguracje wielu pakietów są umieszczane w tych katalogach.
+        </p>
+        <p>
+          Pliki konfiguracyjne, nie których pakietów mogą występować w
+          dwóch różnych wersjach. Pierwsza
+          to jest, ta którą wszyscy znamy czyli katalog <em>/etc</em> taka
+          konfiguracja nazywana jest <em>konfiguracją z możliwością dostosowania</em>.
+          Druga wersją jest <em>konfiguracja bez możliwości dostosowania</em>
+          znajdująca się w katalogu <em>/usr/lib</em>. Oczywiście to jest tylko
+          koncepcja, aby administratorzy zajęli się konfiguracją w <em>/etc</em>
+          a konfiguracje w <em>/usr/lib</em> zostawili opiekunom pakietów
+          (osobom przygotowywującym pakiet oprogramowania dla danej dystrybucji,
+          z wybranym programem) oraz twórcom samej dystrybucji. Możemy zmieniać
+          oczywiście konfiguracje w tym katalogu, jednak trzeba mieć na uwadze
+          dwie rzeczy: 
+        </p>
+        <ol>
+          <li>Trzeba wiedzieć co się robi</li>
+          <li>Zmiany w konfiguracji znajdującej w <em>/usr/lib</em> mogą 
+            zostać nadpisane przez aktualizacje pakietu.
+        </ol>
+        <p>
+          System Linuks nie jest miejscem, gdzie się cokolwiek komu kolwiek
+          zabrania. Zasady i jakieś regułu  wprowadza się po to aby zapewnić 
+          względne bezpieczeństwo oraz stabilność dystrybucji czy też ogolnie 
+          systemu. 
+        </p>
+        <h2 id="syslog">7.2. syslog</h2>
+        <p>
+          Znaczna część komunikatów dignostycznych z różnych komponentów
+          systemowych spływa do protokołowania czy rejestrowania lub
+          prowadzenia plików dziennika. W języku polskim istnieje kilka
+          określeń na to co konkretnie robi usługa <strong>syslog</strong>, 
+          której zadaniem jest nasłuchiwanie na komunikaty diagnostyczne i
+          przekazywanie ich do pliku, na ekran poszczególnych użytkowników lub
+          całkowite zignorowanie. Wszystko zależy od konfiguracji.
+        </p>
+        <p>
+          Obecnie wykorzystywana jest nowsza wersja <em>syslog</em> -
+          <strong>rsyslog</strong>. Funkcje tej wersji nie ograniczają się
+          tylko do zapisywania komunikatów diagnostycznych do pliku, program
+          może na przykład przesyłać je do bazy danych. Na tym etapie nie
+          będziemy się jednak tym zajmować, póki co będziemy musieli się
+          zadowolić zwykłymi plikami tekstowymi przechowywanymi w katalogu
+          <em>/var/log</em>. Warto mieć jednak na uwadze fakt, iż nie
+          wszystkie pliki przechowywane w tym katalogu są zarządzane, przez
+          tę usługę. Nie które daemony mogą posiadać swoje sposoby na
+          utrzymanie i prezentowanie użytkownikowi własnych komunikaty
+          diagnostycznych. Więcej informacji na temat jakie <em>logi</em> są
+          przechwytywane przez <em>rsyslog</em> znajduje się w pliku
+          konfiguracyjnym - <strong>/etc/rsyslog.conf</strong>.
+        </p>
+        <p>
+          Na konfiguracje składają się tradycyjne reguły oraz dyrektywy
+          dostępne w rozszerzonej wersji <em>rsyslog</em>. Dyrektywy możemy
+          poznać po tym, że rozpoczynają się od symbolu dolara
+          (<strong>$</strong>). Natomiast reguły konfiguracyne klasycznej
+          wersji protokołu są nieco bardziej złożone.
+        </p>
+        <p>
+          Reguły protokołu <em>syslog</em> określają sposób przychwytywania
+          komunikatów diagostnycznych oraz docelowe miejsce ich zapisu. Zasady
+          składają się z selektora i akcji, o to kilka z nich.
+        </p>
+<pre class="code-block">
+*.info;mail.none;authpriv.none;cron.none  /var/log/messages
+authpriv.*  /var/log/secure,root
+mail.*      -/var/log/maillog
+*.emerg     :omusrmsg:*
+</pre>
+        <p>
+          Reguły <em>syslog</em> możemy podzielić na dwie części prawą i lewą.
+          Po lewej stronie znajduje się selektor, określający przechwywane
+          dane. Natomiast po prawej znajduje się akcja zazwyczaj jest ścieżka
+          do pliku docelowego dla przychwconych komunikatów. Przy jednej ze
+          ścieżek znajduje się myślnik, który powoduje nie synchronizowanie
+          tego pliku jeśli włączono by synchronizacje (jest ona domyślnie
+          wyłączona). Synchronizacja powoduje znaczny spadek wydajność i może
+          doprowadzić do gubienia komunikatów.
+        </p>
+        <p>
+          Selektor zaś składa się z kolejnych dwóch części: 
+          <strong>funkcji</strong> oraz <strong>priorytetu</strong>. Funkcja
+          określa źródło komunikatów i są one na stałe zaimplementowane w
+          <em>rsyslog</em> a priorytety ich rodzaj wśród, których możemy
+          wymienić (ułożenie według od najniższego do najwyższego):
+        </p>
+<pre class="code-block">
+debug, info, notice, warning, error, crit, alert, emerg
+</pre>
+        <p>
+          Tworząc selektor oddziela się funkcję od priorytetu za pomocą kropki.
+          Priorytet służy do ograniczania wielkość przechwytywanych komunikatów,
+          albowiem <em>rsyslog</em> rozpoczyna przechwytywanie komunikatów od
+          tego priorytetu w górę. Jeśli przypatrzmy się pierwszej linii
+          konfiguracji, zauważymy, że do pliku 
+          <code class="code-inline">/var/log/messages</code> będzie
+          spływać masa informacji, ponieważ selektor uwzględnia komunikaty
+          ze wszystkich funkcji z minimalnym priorytetem 
+          <code class="code-inline">debug</code>. Istnieją jednak pewne
+          wykluczenia. Na selektor może składać się więcej niż jedna para
+          <em>funkcja.priorytet</em>, co również widać w pierwszej linii
+          przykładu. Kolejne pary rozdzielone są średnikami. W omawianym
+          przykładzie, pary mają ten sam priorytet, który nie został
+          uwzględniony na powyższej liście <strong>none</strong> powoduje
+          wyłączenie przechwytywania z użytych w raz z nim funkcji. Tak więc
+          w pierwszej linii przechwytywane będą komunikaty ze wszystkich
+          funkcji z minmalnym priorytetem <code class="code-inline">info</code>,
+          poza takimi funkcjami jak <code class="code-inline">mail</code>,
+          <code class="code-inline">authpriv</code> oraz 
+          <code class="code-inline">cron</code>. Komunikaty będą zapisywane
+          zgodnie z akcją w pliku <code class="code-inline">/var/log/messages</code>.
+        </p>
+        <p>
+          Innymi ciekawymi przypadkami w pokazanymi na przykładzie jest
+          podanie w akcji w drugiej linii dwóch miejsc docelowych. Pliku
+          <code class="code-inline">/var/log/secure</code> oraz nazwy
+          superużytkownika. Podanie jakiej kolwiek nazwy użytkownika w akcji
+          spowoduje przesłanie mu (za pomocą polecenia <strong>write</strong>)
+          komunikatu diagnostycznego, o ile użytkownik zezwala na wyświetlanie
+          tego typu komunikatów (polecenie <strong>mesg</strong>). Chociaż
+          komunikaty wysłane przez superużytkownika są wyświetlane mimo tych
+          ustawień. Kolejnym przypadkiem związanym z wysyłaniem jest użycie
+          specjalnego <strong>modułu wyjściowego</strong> reprezentującego
+          konkretną akcje, w tym przypadku jest wysyłanie wiadomości do
+          zobrazowane w ostatniej linii przykładu. Jak mogliśmy zauważyć w
+          liniach reguł możemy używać symbolu wieloznacznego gwiazdki
+          (<strong>*</strong>).
+        </p>
+        <p>
+          Dyrektywy nowszej wersji daemona rejestrującego są dość proste
+          do zrozumienia i nie wymgają dodatkowego opisu.
+        </p>
+<pre class="code-block">
+$FileOwner syslog
+$FileGroup adm
+$FileCreateMode 0640
+$DirCreateMode 0775
+$Umask 0022
+</pre>
+        <p>
+          Jeśli chodzi o <em>syslog</em>, to w przypadku usługi rejestrowania
+          może stać się nie wiele złego, jedynym problemem jaki możemy
+          napotkać jest brak przechwytywania komunikatów z powodu 
+          nieuwzględnienia jakiejś funkcji lub priorytetu w selektorze.
+          Niemniej jednak rejestrator systemowy możemy przetestować za pomocą
+          polecenia <strong>logger</strong> podając mu parę 
+          <em>funkcja.priorytet</em> po opcji <strong>-p</strong>
+          (na stronie podręcznika opcja określona jest jako priorytet) oraz
+          komunikat do zapisania. Jeśli priorytet został pominięty, zostanie
+          użyty domyślny <em>user.notice</em>. W zależności od konfiguracji
+               <em>rsyslog</em> oraz użytej funkcji nasz komunikat powinien
+               pojawić jednym z plików wyszczególnionych w konfiguracji.
+          W przypadku użycia narzędzia <em>logger</em> z domyślnymi wartościami
+          komunikat zostanie zapisany do <em>/var/log/messages</em>.
+        </p>
+        <p>
+          Większość rejestratorów istnieje nie tylko w postaci odrębnego 
+          programu jakim
+          jest <em>rsyslog</em>, ale także w postaci funkcji, nie których 
+          <em>daemonów</em>
+          jak np. serwer WWW <em>Apache2</em> one również zapisuje swoje 
+          komunikaty
+          diagnostyczne do <em>/var/log</em>. Bardzo duża ilość danych
+          spływająca do jednego katalogu może powodować szybkie
+          zapełnienie przestrzeni dyskowej. Jednak się to nie dzieje, dzięki 
+          programowi <strong>logrotate</strong>, którego zadaniem jest
+          (w zależności od konfiguracji) usuwanie lub kompresja starych plików
+          dzienników i utworzenie miejsca na nowe komunikaty.
+        </p>
+        <p>
+          Z racji tego, iż demony działają w trakcje czynności wykonywanych 
+          przez <em>logrotate</em>, skrypty obsługujące konkretne pliki 
+          dziennika, tworzą puste pliki o takiej samej nazwie jak te utworzone
+          przez demon.
+        </p>
+        <h2 id="7.3.userconfig">7.3. Konfiguracja użytkowników</h2>
+        <p>
+          Komputery jak i systemy operacyjne mają za zadanie służyć
+          użytkownikom. Jak wiemy użytkownicy w systemach istnieją aby
+          wyznaczać granicę. Mówiąc kolokwialnie każdy z nas ma swoją
+          piaskownice i swoje zabawki. W Linuksach użytkownicy są opisywani za
+          pomocą kilku plików w katalogu <em>/etc</em>.
+        </p>
+        <h3 id="7.3.1.passwdfile">7.3.1. Plik /etc/passwd</h3>
+        <p>
+          Plik <em>/etc/passwd</em> jest podstawowym źródłem informacji o 
+          użytkownikach w systemie. W tym pliku każdy wiersz to jeden wpis
+          definiujący użytkownika. Każdy wiersz podzielony jest na 7 pól.
+          Poniżej znajduje się kilka przykładowych wpisów:
+        </p>
+<pre class="code-block">
+pulse:x:109:114:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
+saned:x:110:117::/var/lib/saned:/usr/sbin/nologin
+colord:x:111:118:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
+lightdm:x:112:119:Light Display Manager:/var/lib/lightdm:/bin/false
+libvirt-qemu:x:64055:105:Libvirt Qemu,,,:/var/lib/libvirt:/usr/sbin/nologin
+geoclue:x:113:124::/var/lib/geoclue:/usr/sbin/nologin
+user:x:1000:1000::/home/user:/bin/bash
+xf0r3m:x:1001:1001::/home/xf0r3m:/bin/bash
+</pre>
+        <p>
+          Pola te zawierają kolejno:
+        </p>
+        <ul>
+          <li><strong>Nazwa użytkownika</strong> - jednoznaczny identyfikator
+            użytkownika, służący do rozpoznawania użytkowników miedzy innymi
+            użytkownikami.</li>
+          <li><strong>Zaszyfrowane hasło</strong> - w dystrybucjach Linuksa
+            hasło nigdy nie było przechowywany w jawnej postaci, nawet w tak
+            zamieszchłych czasas kiedy znajdowało się ono w pliku 
+            <em>/etc/passwd</em>. Obecnie po haśle został tylko
+            <code class="code-inline">x</code>, co oznacza, że hasło jest
+            przechowywany w pliku <em>/etc/shadow</em>, który również zostanie
+            tu omówiony.</li>
+          <li><strong>UID (identyfikator użytkownika)</strong> - numer
+            identyfikujący użytkownika, służy głównie odwołaniu się jądra do
+            konkretnego użytkownika.</li>
+          <li><strong>GID (identyfikator grupy)</strong> - numer
+            identyfikujący podstawową grupę użytkownika.</li>
+          <li><strong>Pole GECOS</strong> - pole przechowujące rzeczywiste
+            informacje o użytkowniku takie jak imie, nazwisko, numer telefonu,
+            adres e-mail, numer pokoju. Pole może zostać pominięte, co widzimy
+            na kilku wpisach na przykładzie.</li>
+          <li><strong>Katalog domowy</strong> - ścieżka wskazująca na katalog
+            domowy użytkownika.</li>
+          <li><strong>Program uruchamiany po zalogowaniu (powłoka)</strong> -
+            ścieżka wskazująca na program jaki ma zostać uruchomiony po 
+            zalogowaniu, najczęściej jest to interaktywna powłoka.</li>.
+        </ul>
+        <p>
+          Drugie pole wpisu w <em>/etc/passwd</em> może przyjmować dwie
+          dodatkowe wartości. Pole może zawierać gwiazdkę (<strong>*</strong>),
+          która uniemożliwia logowanie lub pole może być puste co pozwala na
+          zalogowanie się bez podawania hasła. 
+        </p>
+        <p>
+          Jeśli przefiltrujemy za pomocą polecenia <em>grep</em> plik 
+          <em>/etc/passwd</em> pod kątem ustawionych programów (powłok), to
+          na powiedzmy ok. 50 (zależności od dystrybucji) tylko dwóch, trzech
+          użytkowników ma ustawioną powłokę. Pozostali użytkownicy zazwyczaj
+          mają ustawiony program, który uniemożliwia im korzystanie z systemu
+          nawet gdy się zalogują. Tacy użytkownicy nazwani są 
+          <strong>pseudoużytkownikami</strong>. Tego rodzaju użytkownicy
+          istnieją w jednym celu, aby uruchamiać z ich uprawnieniami różne
+          programy, głównie demony sieciowe. Co w razie włamania spowoduje, że
+          atakujący zostanie uwięziony na koncie, na którym nic nie może
+          zrobić.
+        </p>
+        <p>
+          Pseudoużytkownicy zaliczają się do użytkowników specjalnych obok nich
+          istnieje jeszcze jeden użytkownik - <strong>root</strong>, który ma
+          niczym nie ograniczone uprawnienia. Dlatego też nosi nazwę
+          <em>superużytkownika</em>. Posiada on UID i GID równy 0 oraz jego
+          katalog domowy znajduje się bezpośrednio w głównym katalogu. Innym
+          ciekawym użytkownikiem specjalnym jest użytkownik <em>nobody</em>,
+          który nie ma możliwości zapisu niczego w systemie.
+        </p>
+        <p>
+          Kombinacja wpisu w pliku <em>/etc/passwd</em> oraz katalogu domowego
+          może być określana jako <strong>konto</strong>.
+        </p>
+        <h3 id="7.3.2.shadowfile">7.3.2. Plik /etc/shadow</h3>
+        <p>
+          Plik <em>/etc/shadow</em> jest podobnym plikiem <em>/etc/passwd</em>,
+          jednak zamiast przechowywać informacje o użytkownika plik ten 
+          przechowuje informacje o hasłach. Plik <em>/etc/shadow</em> posiada
+          jedno wspólne pole wraz z plikiem <em>/etc/passwd</em> a jest nim
+          nazwa użytkownika. Hasło podobnie do pliku <em>/etc/passwd</em> 
+          znajduje się na drugim polu we wpisie. Pozostałe pola są
+          odpowiedzialne za ważność hasła. Wpisy w pliku <em>/etc/shadow</em>
+          biorą również czynny udział w blokowaniu dostępu użytkownikom. 
+          Zawartośc pliku wygląda w następujący sposób:
+        </p>
+<pre class="code-block">
+root:$y$j9T$h19rJ2ObBXMdBdXOHB0wF.$.Lqb5iG3.HpsO0FcghqSkXbcA6D5rIp9woC/Ovj40Q7:19251:0:99999:7:::
+...
+user:$y$j9T$bAf/P4bLm00VJQyS3Lf8I1$dzie3XL5lORpP7jmo4CeanOqhuWMpPzdQArAlQ9AfG0:19327:0:99999:7:::
+</pre>
+        <p>
+          Na tym etapie nauki dalsza analiza tych wpisów nie ma sensu, jeśli
+          jednak ktoś jest ciekawy pozostałych pól to może zajrzeć do mojego
+          materiału przygotowywującego do RHCSA: <a href="https://morketsmerke.github.io/articles/terminallog/RedHat_-_RHCSA.html#6.1.passwordaging">https://morketsmerke.github.io/articles/terminallog/RedHat_-_RHCSA.html#6.1.passwordaging</a>
+        </p>
+        <p>
+          Plik <em>/etc/shadow</em> jest dość mocno zabezpieczonym plikiem,
+          zwykli użytkownicy nie posiadają do niego żadnych praw. Jedyną
+          uprawnioną osobą do manipulacji nim jest superużytkownik.
+        </p>
+        <h3 id="7.3.3.changingusers">7.3.3. Manipulowanie użytkownikami i hasłami</h3>
+        <p>
+          Omawiane dotychczas pliki są zwykłymi plikami tekstowymi, których 
+          zawartością możemy manipulować za pomocą ulubionego edytora
+          tekstowego. Nie jest to jednak zalecane działanie. Ze względu na 
+          ścisłą budowę (nie możliwe jest aby umieszczać w tych plikach 
+          komentarze lub puste wiersze) oraz restrykcyjną składnie wierszy.
+          Możemy użyć specjalnego narzędzia jakim jest <strong>vipw</strong>.
+          Polecenie to tworzy kopię zmienianych plików i następnie otwiera
+          ten plik w terminalowym edytorze. Konfiguruje ono również ten edytor
+          aby zaznaczał składnię wpisów w plików, po zapisaniu zmian polecenie
+          sprawdzi składnie zmienionych lub dodanych wpisów. Jeśli wszystko
+          będzie dobrze, to polecenie zapisze zmiany jeśli coś będzie nie
+          tak to polecenie zaproponuje poprawienie błędu. Polecenie wymaga
+          oczywiście uprawnień administratora. Wydając polecenie bez żadnej
+          opcji otworzy ono plik <em>/etc/passwd</em> do edycji a jesli dodamy
+          opcje <strong>-s</strong> to wówczas zostanie otworzony plik 
+          <em>/etc/shadow</em>.
+        </p>
+        <p>
+          Inną metodą jest wykorzystanie np. opcji polecnia 
+          <strong>passwd</strong> jego domyślną rolą jest zmiana hasła, bądź 
+          ustawianie ważności hasła, jednak dodając opcję <strong>-s</strong>
+          mozemy zmienić domyślny program startowy (powłokę) lub za pomocą
+          opcji <strong>-f</strong> możemy zmienić nazwę użytkownika. Po
+          więcej informacji zapraszam do strony podręcznika polecenia 
+          <em>passwd</em>. Jeśli na naszym przypadku polecenie <em>passwd</em>
+          może nie być zadowalające. Można wówczas skorzystać z polecenia typu
+          <strong>usermod</strong>.
+        </p>
+        <h3 id="7.3.4.groups">7.3.4. Grupy</h3>
+        <p>
+          Rolą grup w systemach uniksopodobnych jest współdzielenie plików.
+          Dzięki nim możemy zwiększyć uprawnienia do pliku, nie którym
+          użytkownikom, chroniąc je przed innymi. Wynika to z możliwosci
+          nadania uprawnień grupie, natomiast można je zabrać wszystkim 
+          pozostałym. Obecnie stacje uniksowe stały się bardziej
+          spersonalizowanie to współdzielenie plików przy użyciu grup
+          straciło na znaczeniu. Jednak grupy tak jak użytkowników możemy 
+          wykorzystać do uzyskiwania dodatkowych uprawnień lub ich
+          ograniczania.
+        </p>
+        <p>
+          Wraz z każdym nowym użytkownikiem tworzona jest nowa grupa o tej
+          samej nazwie co użytkownik. Grupa ta jest również ustawiana jako
+          grupa podstawowa tworzonego użytkownika. Definicje grup znajdują
+          się w pliku <em>/etc/group</em>. Poniżej znajduje się fragment:
+        </p>
+<pre class="code-block">
+libvirt:x:123:user,xf0r3m
+libvirt-qemu:x:64055:libvirt-qemu,user,xf0r3m
+geoclue:x:124:
+user:x:1000:
+xf0r3m:x:1001:
+</pre>
+        <p>
+          Jak możemy zauważyć wpisy dzielą się na cztery pola, które kolejno
+          oznaczają:
+        </p>
+        <ul>
+          <li><strong>Nazwa grupy</strong> - nazwa jednoznacznie identyfikująca
+            grupę.</li>
+          <li><strong>Hasło grupy</strong> - hasło grupy. Obecnie aby podłączyć
+            użytkownika do grupy potrzebna jest interwencja administratora lub
+            kogoś z jego uprawnieniami. Jeśli jednak grupa posiada hasło to 
+            użytkownik może podłączyć się do grupy za pomocą polecenia
+            <strong>newgrp</strong> (dalej jest taka możliwość). Obecnie
+            jednak nie stosuje się haseł dla grup. Hasła grup są przechowywane
+            w pliku <em>/etc/gshadow</em>.</li>
+          <li><strong>GID (identyfikator grupy)</strong> - numeryczny
+            identyfikator grupy, służy do odniesienia jądra do konkretnej
+            grupy.</li>
+          <li><strong>List członków grupy</strong> - lista uzytkowników
+            należących do grupy.</li>
+        </ul>
+        <p>
+          Grupy odpowiadające istniejącym użytkownikom nie posiadają żadnych
+          członków w tym pliku, jednak odpowiadający tym grupom użytkownicy są
+          ich domyślnymi członkami.
+        </p>
+        <p>
+          Jądro Linux, nie posługuje się nazwami użytkowników czy grup 
+          odwołując się do jednego lub drugiego bytu. W tym celu używa wartości
+          UID oraz GID, aby ich używanie miało sens muszą być one unikatowe
+          w skali całego systemu. Oczywiście może zdażyć się przypadek, że
+          dwóch użytkowników będzie miało ten sam UID, ale są to bardzo rzadkie
+          i specyficzne przypadki.
+        </p>
+        <h2 id="gettyandlogin">7.4. Getty oraz login</h2>
+        <p>
+          Te dwa programy nie są zbyt skomplikowane w swoim działaniu.
+          Działanie programu <em>getty</em> polega na podłaczeniu się pod
+          terminal (nie ważne czy wirtualny czy fizyczny podłączony przez 
+          port COM) i wyświetlenie znaku zachęty logowania (napisu "login: ")
+          i oczekiwania na podanie nazwy użytkownika. Kiedy nazwa zostanie
+          podana
+          polecenie to zastępuje same siebie wywołując program <em>login</em>.
+          Ten program odpowiedzialny jest za wyświetlenie znaku zachęty hasła
+          (napisu "hasło:") po podaniu przez użytkownika hasła program
+          spróbuje go uwierzytelnić. Jeśli to się powiedzie wówczas program
+          <em>login</em> zastąpi sam siebie po przez wywołanie systemowe
+          <em>exec()</em> programem startowym ustawionym w ostatnim polu 
+          wpisu w pliku <em>/etc/passwd</em>.
+        </p>
+        <p>
+          Prawdopodbnie nigdy nie będzie potrzeby konfiguracji tych programów,
+          nie mniej jednak jest taka możliwość.
+        </p>
+        <h2 id="7.5.time">7.5. Ustawienia czasu.</h2>
+        <p>
+          Działanie wielu operacji w systemach uniksopodobnych opiera się o
+          czas. Za zegar w tych systemach odpowiedzialne jest jądro. Jednak
+          nie jest ono wstanie wziąć precyzyjnych ustawień czasowych samo z
+          siebie. Większość komputerów klasy PC posiada potrzmywany bateryjnie
+          zegar czasu rzeczywistego, jądro synchronizuje swój zegar z tym 
+          zegarem jednak z racji tego, iż maszyny uniksowe nie są uruchamiane
+          ponownie przez miesiące a nawet lata. W czasie systemowym pojawia 
+          się odchylenie. 
+        </p>
+        <p>
+          Zegar systemowy jądra również jest korygowany na podstawie ustawień
+          strefy czasowej w jakiej się znajdujemy, dlatego też 
+          RTC (ang. <em>Real Time Clock</em>) w BIOS lub UEFI powinien być 
+          ustawiony zgodnie ze strefą czasową UTC. Za pomocą poniższego
+          polecenia możemy ustawić czas UTC jądra względem RTC.
+        </p>
+<pre class="code-block">
+$ sudo hwclock --hctosys --utc
+</pre>
+        <h3 id="7.5.1.timezonesandtimerepresentation">7.5.1. Strefy czasowe i reprezentacja czasu</h3>
+        <p>
+          Jądro przechowuje swój czas w formacie uniksowym, czyli ilości 
+          sekund od północy 1 stycznia 1970 roku. Na podstawie tych informacji
+          takie polecenia jak <strong>date</strong> dokonuja wszelkich 
+          konwersji i wyświetlają nam zrozumiałą dla nas datę i czas. Czas
+          uniksowy możemy wyświetlić sobie za pomocą polecenia <em>date</em>
+          z opcją <strong>+%s</strong> (niestety polecenie <em>date</em> ma
+          nieco inny format opcji).
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ date
+śro, 28 gru 2022, 13:11:53 CET
+xf0r3m@immudex:~$ date +%s
+1672229517
+</pre>
+        <p>
+          Domyślnie polecenie <code class="code-inline">date</code> wyświetla
+          datę i czas skorygowany o ustawioną w naszym systemie, na podstawie
+          przybliżonej lokalizacji strefę czasową. Ustawiona strefa czasowa
+          znajduje się katalogu <em>/etc</em> jako dowiązanie symboliczne do
+          jednego z plików stref dostępnych w systemie w katalogu 
+          <em>/usr/share/zoneinfo</em>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ls -al /etc/localtime 
+lrwxrwxrwx 1 root root 33 11-04 17:46 /etc/localtime -&gt; /usr/share/zoneinfo/Europe/Warsaw
+</pre>
+        <p>
+          Strefę czasową możemy zmienić za pomocą polecenia interaktywnego 
+          polecenia <strong>tzselect</strong>. Polecenie to spróbuje określić
+          twoją przybliżoną lokalizacje na podstawie stolicy kraju w jakim się
+          znajdujesz. Następnie utworzy nowe dowiązanie symboliczne
+          <em>/etc/localtime</em> do odpowiedniego pliku strefy.
+        </p>
+        <p>
+          Jeśli z jakiś przyczyn potrzebujemy sprawdzić jaki bedzie czas w
+          wybranej przez nas strefie czasowej, możemy zmienić zmienną
+          środowiskową TZ, która przechowuje informacje o ustawionej strefie
+          czasowej na czas wykonania polecenia. Tę czynność możemy wykonać na 
+          czas wykonania pojedyńczego
+          polecenia, ustawiając wartość zmiennej w tej samej linii co polecenie
+          <em>date</em>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ TZ=Asia/Tokyo date
+śro, 28 gru 2022, 21:29:01 JST
+</pre>
+        <h3 id="7.5.2.settingntptime">7.5.2. Czas sieciowy</h3>
+        <p>
+          Jeśli nasza maszyna sieciowa jest na przykład serwerem ze stałym 
+          dostępem do sieci. To aby zniwelować to odchylenie czasowe, którym
+          wspomniałem na początku tego podrozdziału możemy uruchomić na nim 
+          specjalną usługę sieciową, która pobierze czas z serwerów
+          podłączonych do bardzo precyzyjnych zegarów atomowych.
+        </p>
+        <p>
+          Pierwszą rzeczą jak należy zrobić to pobrać pakiet odpowiedzialny
+          za demon NTP w naszym systemie. Następnie skonfigurować go zgodnie
+          jego dokumentacją. Najprostsza konfigurację możemy zapisać w
+          poniższych krokach.
+        </p>
+        <ol>
+          <li>Znalezienie najbliższego dla siebie serwera NTP, najlepiej
+            na poziomie STRATUM nie większym niż 3.</li>
+          <li>Zapisanie adresów serwera (serwerów, może być pula) w pliku
+            konfiguracyjnym demona NTP, najczęściej jest to 
+            <em>/etc/ntp.conf</em>.</li>
+          <li>Uruchomienie polecenia <em>ntpdate</em>.</li>
+          <li>Włącznienie demona NTP do uruchomienia w trakcie autostartu.</li>
+        </ol>
+        <p>
+          Jeśli nasz komputery nie posiada stałego łącza internetowego możemy
+          wówczas uruchomić takiego demona jak <em>chronyd</em>. Ostatecznie
+          mozemy zsynchonizowany czas systemowy załadować do zegara RTC za 
+          pomocą poniższego polecenia.
+        </p>
+<pre class="code-block">
+$ sudo hwclock --systohc --utc
+</pre>
+        <p>
+          W tym podrozdziale umieściłem polecenie, którego nie wyjaśniłem.
+          Jest nim <strong>poziom STRATUM</strong>. Wyjasnienie tego pojecia
+          wymaga zagłebienia się w protokół NTP, co zrobiłem w materiale
+          przygotowawczym do RHCSA znajdującym się tutaj: <a href="https://morketsmerke.github.io/articles/terminallog/RedHat_-_RHCSA.html#18.1.ntp">https://morketsmerke.github.io/articles/terminallog/RedHat_-_RHCSA.html#18.1.ntp</a>.
+        </p>
+        <h2 id="7.6.cron">7.6. Tworzenie powtarzalnych zadań za pomocą cron</h2>
+        <p>
+          Wróćmy na chwile do drugiego podrozdziału. Tam pod koniec omówiliśmy
+          sobie gdzie znajdują się pliki dziennika i w jaki sposób system 
+          radzi sobie z problem szybko przyrastających plików zawierających
+          komunikaty diagnostyczne z przeróżnych demonów. Wspomnialiśmy tam 
+          o <em>logrotate</em>. Ten program aby zapobiec zużyciu całego miejsca
+          na dysku musi uruchamiać się co jakiś czas.
+        </p>
+        <p>
+          W uniksach aby wykonywać jakieś czynności co określoną ilość czasu,
+          musimy skorzystać z programu o nazwie <strong>cron</strong>. Ten 
+          program to swojego rodzaju harmonogram zadań, w którym to może
+          zdefiniować co uruchomić, kiedy lub co ile czasu i przez kogo.
+          Definicje zadań znajdując się w specjalnych plikach zwanych
+          <em>crontab</em>. Każdy użytkownik ma swój plik. Ponieważ pliki te
+          znajdując się w miejscu, do którego zwykli użytkownicy nie mają 
+          dostępu muszą używać
+          dostarczonym wraz z <em>cron</em> narzędziem.
+        </p>
+        <p>
+          Aby móc zdefiniować zadania należy wydać następujące polecenie:
+        </p>
+<pre class="code-block">
+$ crontab -e
+</pre>
+        <p>
+          Wówczas otworzy nam się wybrany przez nas wcześniej edytor
+          terminalowy. Wewnątrz pliku znajdziemy obszerny komentarz, w którym
+          to rozpisano dokładnie całą składnie definicji zadania <em>cron</em>.
+        </p>
+        <p>
+          Otóż zadania <em>cron</em> to jednowierszowe wpisy definiujące na 
+          początku czas (kiedy, co ile czasu) w którym należy uruchomić zadanie
+          Następnie polecenie, które należy uruchomić.
+        </p>
+<pre class="code-block">
+21 0 * * * /usr/local/bin/backup.sh &gt; /var/log/backup_sh.log 2&gt;&amp;1
+</pre>
+        <p>
+          To zadanie zostanie uruchomione codziennie 21 minut po północy. Skąd
+          to wiem, otóż już śpieszę z wyjaśnieniami. Najpierw objaśnie
+          poszczególne pola.
+        </p>
+        <ul>
+          <li><code class="code-inline">21</code> - pole minut, podanie tutaj
+            takie zwykłej wartości jak na przykładzie, spowoduje uruchomienie
+            zadania o podanej minucie godziny. Zakres wartości od 0 - 59.</li>
+          <li><code class="code-inline">0</code> - pole godziny, podanie
+            wartości w tym polu spowoduje, że zadanie zostanie uruchomione
+            o tej samej pełnej godzinie każdego dnia, chyba że podano konkretną
+            minutę. Zakres wartości od 0 - 23.</li>
+          <li><strong><span style="color: lightgreen">*</span></strong> - pole
+            dnia miesiąca, wartość w tym polu spowoduje, że zadanie zostanie
+            uruchomione o północy podanego dnia miesiąca, chyba że zdefiniowano
+            wcześniejsze pola. Zakres wartości od 1 - 31.</li>
+          <li><strong><span color="color: fuchsia">*</span></strong> - pole
+            miesiąca, wartość w tym polu spowoduje uruchomienie zadania o
+            północy 1 dnia miesiąca, chyba że zdefiniowano wcześniejsze pola.
+            Zakres wartości od 1 - 12.</li>
+          <li><strong><span color="color: cornfloweblue">*</span></strong> -
+            pole dnia tygodnia, wartość w tym polu spowoduje uruchomienie
+            zadania co tydzeń o północy podanego dnia tygodnia. Chyba że 
+            zdefiniowano wcześniejsze pola. Zakres wartości od 0 - 7, przy czym
+            0 i 7 to niedziela.</li>
+        </ul>
+        <p>
+          Ustawienia czasu wykonania zadania jest w miarę proste o ile nie
+          wymagamy bardzo złożonego warunku czasowego lub nie próbujemy go 
+          zrozumieć (zadając sobie pytanie: kiedy to dokładnie się wykona?).
+          Załóżmy że chcemy aby zadanie wykonało się w każdy weekend wakacji
+          w Polsce. Warunek czasowy może przyjmować: wartości krokowe
+          (<strong>/2</strong>) co dwie minuty, godziny, dni, miesiące; 
+          zakresy (<strong>5-10</strong>) od 5-10 minuty, godziny, dnia itd lub
+          listy (<strong>11,12</strong>) zadanie wykoania się np. 11 i 12
+          każdego miesiąca. Zakresy oraz listy można ze sobą łączyć, jak i
+          dodać pojedyńczą wartość do zakresu, np. 5-10,12. Przy tworzeniu 
+          warunku czasowego możemy posłużyć się stronami takimi jak:
+        </p>
+        <ul>
+          <li><a href="https://crontab.guru">https://crontab.guru</a></li>
+        </ul>
+        <h3 id="7.6.1.instalationofcrontab">7.6.1. Instalacja tablicy cron.</h3>
+        <p>
+          Po zapisaniu zmian tablica z zadaniami crona (<em>crontab</em>)
+          zostanie automatycznie zainstalowana w katalogu
+          <em>/var/spool/cron/crontab</em>. Polecenie 
+          <code class="code-inline">crontab</code> daje możliwość instalacji
+          tablicy zadań z zwykłego pliku tekstowego, dokonujemy tego za pomocą
+          polecenia <code class="code-inline">crontab</code> wraz z opcją 
+          <strong>-l</strong>. Jednak
+          korzystanie z opcji <code class="code-inline">-e</code> jest bardziej
+          zalecane. Wówczas podczas zapisywania zmian polecenie sprawdzi 
+          zadania pod kątem poprawności składni i przypadku błedu, zapyta czy
+          nie chcemy go poprawić.
+        </p>
+        <p>
+          Tablice z zdaniami cron możemy usunąć za pomocą opcji 
+          <strong>-r</strong> polecania <code class="code-inline">crontab</code>.
+        </p>
+        <h3 id="7.6.2.systemwidecrontab">7.6.2. Systemowa tablica zadań crontab.</h3>
+        <p>
+          Prócz tablic użytkowników, istnieje jescze systemowa tablica
+          z zadaniami <em>cron</em>. Ją edytujemy już pomocą edytora tekstowego
+          ponieważ jej wpisy mają nieco inną składnie niż tablice użytkowników.
+          W jej wpisach znajduje się dodatkowe pole między dniem tygodnia a
+          poleceniem. W nim definiuje się użytkownika, z którego uprawnienami
+          realizowane jest zapisane zadanie. Dlatego też polecenie 
+          <em>crontab</em> z opcją <em>-e</em> nie ma tutaj zastosowania. Jako
+          systemowej tablicy cron, nie wykorzystuje się również tablicy
+          superużytkownika. Za tablicę systemową odpowiedzialny jest plik 
+          <em>/etc/crontab</em>. Plik ten edytujemy za pomocą zwykłego edytora,
+          kiedy zakończymy edycję, należy uruchomić demon <em>cron</em>
+          ponownie.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo vim /etc/crontab 
+xf0r3m@immudex:~$ sudo systemctl restart cron
+</pre>
+        <p>
+          Inną metodą na powtarzalne wykonywanie czynności jest skorzystania
+          z jednego katalogów: <em>/etc/cron.daily</em>, 
+          <em>/etc/cron.hourly</em>, <em>/etc/cron.monthly</em> lub 
+          <em>/etc/cron.weekly</em>. Wykorzystanie tych katalogów polega na 
+          umieszczeniu skryptu (powłoki, nawet jednej linii z konkretnym
+          poleceniem) w jednym z nich. W systemowej tablicy <em>cron</em> jest
+          napisane o której wykonywane są zadania zapisane w tych katalogach.
+          Skrypty uruchamiane są przez znane nam z poprzedniego rozdziału
+          narzędzie jakim jest <em>run-parts</em>. W nowszych dystrybucjach
+          obsługą tych katalogów może zajmować się demon <em>anacron</em>.
+        </p>
+        <h3 id="7.6.3.futureofcron">7.6.3. Przysłość narzędzia cron.</h3>
+        <p>
+          Narzędzie <em>cron</em> jest starsze od samego Linuksa. Jeśli coś
+          jest, aż tak stare to kwalifikuje się do wymiany. Obecnie są czynione
+          postępy w temacie zastąpienia <em>cron</em>-a jakimś innym
+          rozwiązaniem. Kandydatem mogą być elementy licznika czasu
+          <em>systemd</em>. Jednak utworzenie ulepszonej funkcjonalności to
+          jedno, a zapewnienie wstecznej zgodność z systemami oraz narzedziami
+          dalej wykorzystującymi cron to drugie, bez zapewnienia wstecznej
+          zgodności zmian nie będzie, więc póki co <em>cron</em> jeszcze z
+          nami pozostanie.
+        </p>
+        <h2 id="7.7.at">7.7. Planowanie jednorazowych zadań.</h2>
+        <p>
+          Jedno narzędzie do planowania zadań w przyszłości już poznaliśmy. 
+          Narzędzie <strong>at</strong> na pewno nie ma tak szerokiego użycia
+          jak <em>cron</em>, to pomaga wykonać pewne zadania po za czasem 
+          czynnego użytkowania komputera. Jeśli musimy poczekać do powiedzmy
+          północy, aby móc wykonać jakąś czynność, możemy ją zaplanować
+          za pomocą polecenia <em>at</em>, pozostawić komputer włączony i
+          iść spać.
+        </p>
+        <p>
+          Za pomocą polecenia <em>at</em>, możemy nie tylko zaplanować
+          wykonanie zadania na kilka godzin do przodu ale i nawet na kilka
+          miesięcy. Aby jednak to zrealizować należy poznać polecenie
+          <em>at</em>, które może nie być domyślnie dostępne w każdej
+          dystrybucji i trzeba je będzie zainstalować.
+        </p>
+        <p>
+          Aby rozpocząć planowanie zadania należy wydać polecenie <em>at</em>
+          i jako argument podać czas ewentualnie datę jeśli zadanie ma zostać
+          wykonane w dalszej przyszłości. Po wydaniu tego polecenia zostanie
+          nam wyświetlony prompt <em>at&gt;</em>. Po wyświetleniu prompta
+          podajemy polecenie do wykonania w zadaniu. Polecenia możemy podawać
+          do momentu kiedy naciśniemy kombinację klawiszy <em>Ctrl+d</em>,
+          przed zatwiedzeniem polecenia należy upewnić się, że zostało 
+          poprawnie zapisane ponieważ nie będzie możliwości jego edycji.
+          Po naciśnięciu wspomnianiej kombinacji zadanie zostanie zatwierdzone
+          Na poniższym przykładzie utworzyłem jedno zadanie z jednym 
+          poleceniem:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ at 00:00 01.01.2023
+warning: commands will be executed using /bin/sh
+at&gt; echo "Happy New Year" &gt; /dev/pts/1
+at&gt; &lt;EOT&gt;
+job 1 at Sun Jan  1 00:00:00 2023
+</pre>
+        <p>
+          Za pomocą opcji <strong>-l</strong> polecenia <em>at</em> lub
+          polecenia <em>atq</em> możemy wyświetlić znajdujące się w pamieci
+          demona <em>atd</em> zadania.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ at -l
+1      Sun Jan  1 00:00:00 2023 a xf0r3m
+xf0r3m@immudex:~$ atq
+1      Sun Jan  1 00:00:00 2023 a xf0r3m
+</pre>
+        <p>
+          Natomiast za pomocą opcji <strong>-r</strong> polecenia <em>at</em>
+          lub za pomocą polecenia <em>atrm</em>, możemy usunąć zdanie, przyczym
+          należy podać numer zadnia widniejący w pierwszej kolumnie danych 
+          wyjściowych zwracanych przez polecenie <em>at</em> w raz z opcją
+          <em>-l</em> lub polecenie <em>atq</em>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ atq
+1      Sun Jan  1 00:00:00 2023 a xf0r3m
+xf0r3m@immudex:~$ at -r 1
+xf0r3m@immudex:~$ atq
+</pre>
+        <h2 id="7.8.switchinguids">7.8. Identyfikatory użytkowników oraz ich przełączanie.</h2>
+        <p>
+          Jak pamiętamy, lub może nie bit <em>setuid</em> powodował fakt iż 
+          program uruchomiony z tym bitem dział (jego proces) z uprawnieniami
+          właściciela pliku. Tutaj poznamy inne możliwości przełączania
+          użytkowników wraz regułami oraz jaki udział ma w tym wszystkim jądro.
+        </p>
+        <p>
+          Na Linuksie istnieją dwie metody na przełączanie użytkowników.
+          Pierwszym z nich jest ustawienie wspomnianego wcześniej bitu dla
+          pliku wykonywalnego. A drugim sposobem jest wykorzystanie wywołania
+          systemowego <strong>setuid()</strong>, a żeby sprawę jeszcze bardziej
+          skomplikować to wersji tego wywołania systemowego jest kilka, w 
+          zależności o tego na jaki identyfikator użytkownika chcemy się
+          przełączyć. Zanim poznamy możliwe identyfikator (a przynajmniej ich
+          część) warto poznać reguły dotyczące możliwości procesów w zakresie
+          przełączania identyfikatorów. Otóż:
+        </p>
+        <ul>
+          <li>Procesy działające z uprawnieniami superużytkownika mogą używać
+            wywołania systemowego <em>setuid()</em> do uzyskania uprawnień 
+            dowolnego innego użytkownika.</li>
+          <li>Proces, który nie działa z uprawnieniami superużytkownika ma 
+            poważne ograniczenia odnośnie korzystania z wywołania systemowego
+            <em>setuid()</em>. Przeważnie takie procesy nie mogą z niego 
+            korzystać.</li>
+          <li>Dowolny proces może wykonać program z ustawionym bitem 
+            <em>setuid</em>, o ile dysponuje odpowiednimi uprawnieniami do
+            tego pliku (każdy proces działa z uprawnieniami jakiegoś
+            jakiegoś użytkownika i dziedziczy po nim uprawnienia).</li>
+        </ul>
+        <p>
+          Dla ścisłości w tym przełączaniu użytkowników nie chodzi o
+          przełączanie między kontami. A raczej o to, że na podstawie
+          dostępnych mechanizmów w systemie proces może zmieniać uprawnienia
+          wrazie potrzeby oraz możliwości z jakim został uruchomiony.
+        </p>
+        <h3 id="7.8.1.processowneranduids">7.8.1. Właściciel procesu oraz identyfikatory użytkownikow</h3>
+        <p>
+          Dotych czas można było sądzić, że procesy, które uruchamiamy w
+          Linuksie posiadły jeden identyfikator użytkownika. Użytkownika, który
+          ten proces zainicjował. Rzeczywistość jest niestety zgoła inna. 
+          Każdy proces posiada co najmniej dwa identyfikatory użytkowników.
+          Pierwszym z nich jest <strong>euid</strong> 
+          (ang. <em>Effective User IDentifier</em>) - efektywy identyfikator
+          użytkownika. Ten identyfikator wskazuje na użytkownika, z ktorego 
+          uprawnienia działa ten proces. Drugim jest <strong>ruid</strong>
+          (ang. <em>Real User IDentifier</em>) - rzeczywisty identyfikator
+          użytkownika. Ten wskazuje natomiast użytkownika, który zainicjował
+          ten proces. 
+        </p>
+        <p>
+          Ze względu na niejasność związane z rozgraniczeniem miedzy 
+          <em>euid</em> a <em>ruid</em>. Rzeczywistemu identyfikatorowi
+          użytkownika przypisje się rolę właściciela procesu. Może on 
+          prowadzić interakcje z procesem wysyłać do niego sygnały w tym 
+          kończyć jego działanie. W przypadku większości procesów 
+          działających w systemie <em>ruid</em> oraz <em>euid</em> będą równe.
+          Jednak w przypadku gdy uruchomimy proces z ustawionym bitem
+          <em>setuid</em>, efektywny identyfikator zostanie ustawiony na
+          właściciela pliku, zaś rzeczywisty identyfikator będzie 
+          przechowywać nasz UID. Najprostszym przykładem uruchomienia programu 
+          z bitem <em>setuid</em> a za razem doświadczenia przełączenia 
+          identyfikatorów jest użycie polecenia <strong>sudo</strong>.
+        </p>
+        <p>
+          Żeby całość jeszcze bardziej skomplikować, do tych dwóch
+          identyfikatorów należy dodać jescze większego poziomu skomplikowania
+          to istnieje trzeci identyfikator <strong>suid</strong>
+          (ang. <em>Saved User IDentifier</em>) - zapisany identyfikator
+          użytkownika. Podczas działania, proces może przełączać się między
+          zapisanym a rzeczywistym identyfikatorem. 
+        </p>
+        <p>
+          Jeśli uruchomimy jakiś proces przy użyciu polecenia <em>sudo</em>
+          i ten proces będzie trwać, i spróbujemy go zabić to wówczas 
+          dostaniemy informacje o braku dostępu. Polecenie <em>sudo</em>
+          z ustawionym bitem <em>setuid</em> (jak i inne) zamienia 
+          <strong>jawnie</strong>
+          identyfikatory użytkowników za pomocą wywołania systemowego
+          <em>setuid()</em>. Wynika to z kilku problemów jakie wynikają z
+          braku zgodności między identyfikatorami, przez co nie musimy
+          się zbytnio przejmować nimi oraz ich przełączaniem.
+        </p>
+        <p>
+          Ze względu na duże uprawnienia (czynny udział jądra w przełączaniu
+          użytkowników oraz obsłudzie uprawnień dostępu do pliku) programów z 
+          ustawionym bitem 
+          <em>setuid</em> i działającym wraz z nim wywowałań systemowych.
+          Należy uważać jakim programom nadaje się ten bit. Pozostawienie
+          kopii powłoki z ustawionym takim bitem, daje możliwość zwykłym 
+          użytkownikom przejęcia kontroli nad całym systemem. Wydając jedno
+          polecenie.
+        </p>
+        <h2 id="7.9.identifyandauthtenticate">7.9. Identyfikacja i uwierzytelnianie</h2>
+        <p>
+          Każdy wieloużytkowy system musi zapewnić mechanizmy czuwające nad
+          kontrolą użytkowników. Użytkownicy powinni przedstawić się systemowi
+          przekazać tajną informację (hasło), wówczas mechanizmy w systemie 
+          będą wiedzieć, że
+          ten użytkownik jest tym za kogo się podaje. Jeśli użytkownik został
+          uwierzytelniony ma on dostęp do swojego konta, które jest
+          autoryzowane (posiada pewne prawa w systemie) i w ten sposób systemy
+          identyfikują użytkowników. To tak wygląda tylko w teorii. Z racji
+          tego, iż jądro zna tylko UID, ustalenie nazwy użytkownika wymaga 
+          kilku czynności. Można przedstawić tutaj krokowy algorytm, który
+          byłby w stanie ustalić taką nazwę, jednak stosuje sie funkcję
+          biblioteki standardowej, które pomagają w ustaleniu takich
+          informacji. Problem stanowią natomiast hasła, ponieważ funkcje 
+          biblioteki standardowej posiadają w sobie pewne założenia, które
+          niestety nie sprawdzają się przy obecnym sposobie przechowywania
+          haseł w systemie. Więc zatem w jaki sposób obecne dystrybucje
+          dokonuja uwierzytelniania? Wykorzystują on do tego 
+          <strong>podsystem PAM</strong>.
+        </p>
+        <h2 id="7.10.pamsystem">7.10. System PAM</h2>
+        <p>
+          System PAM (ang. <em>Pluggable Authentication Modules</em>) jest to
+          zbiór bibliotek współdzielonych, których zadaniem jest udostępnienie
+          uwierzytelniania użytkownika, w taki sposób aby aplikacja nie
+          musiała się tym zajmować. System PAM może również kontrolować
+          autoryzację użytkownika np. blokując mu dostęp do pewnych usług. Jak
+          sama nazwa wskazuje system ten wykorzystuje dynamicznie ładowane
+          moduły, które realizują poszczególne zadania w zależności od użytej
+          funkcji (o tym za chwilę). Jeśli system ma sprawdzić hasło
+          użytkownika użyje modułu <em>pam_unix.so</em>. Ze względu te 
+          informacje dość łatwym zdaniem jest stworzenie dodatkowych modułów
+          obsługujących uwierzytelniania dwuskładnikowe lub klucze fizyczne,
+          mimo to system PAM dalej pozostaje spuścizną Uniksa przez co,
+          niektóre zagadnienia bywają skomplikowane a intefejs programowania
+          nie jest zbyt prosty. To z tego systemu korzysta większość aplikacji
+          wymagających uwierzytelniania na dystrybucjach Linuksa, ponieważ 
+          połączenie aplikacji z PAM wymaga niewiele pracy lub wcale.
+        </p>
+        <h3 id="7.10.1.pamconfig">7.10.1. Konfiguracja PAM</h3>
+        <p>
+          Ze względu na to, iż konfiguracja różni się w zależności od
+          dystrybucji, cieżko jest się odnaleźć i wyjaśnić to w ogólny sposób.
+          pliki konfiguracyjne systemu powinny znajdować się w katalogu 
+          <em>/etc/pam.d/</em>. Ich nazwy często zawierają nazwy komponentów
+          systemu, które wykorzystują system PAM. Najprostszym z nich jest
+          plik <em>/etc/pam.c/chsh</em>. Polecenie <em>chsh</em> służy do
+          zmiany powłowki. Pierwszy wiersz pliku wygląda następująco:
+        </p>
+<pre class="code-block">
+auth  requisite pam_shell.so
+</pre>
+        <p>
+          Nakłada on wymóg, aby podana podczas zmiany powłoka była wymieniona
+          w pliku <em>/etc/shells</em>, w przeciwym wypadku uwierzytelnienie
+          użytkownika kończy się nie powodzeniem.
+        </p>
+        <p>
+          Każda linia konfiguracji PAM składa się z co najmniej trzech części.
+          Między innymi z:
+        </p>
+        <ul>
+          <li><strong>Typu funkcji</strong>, które aplikacja żąda od systemu PAM
+            w tym przypadku jest to <code class="code-inline">auth</code>
+            powodujący uwierzytelnienie użytkownika.</li>
+          <li><strong>Argumentu kontrolnego</strong>, decydującego o tym jak
+            system zareaguje na powodzenie lub niepowodzenie działania
+            wykonywanego przez typ funkcji.</li>
+          <li><strong>Modułu</strong>, określającego jaka czynność zostanie tak
+            naprawdę wykonana. W tym przypadku jest sprawdzenie czy funkcja 
+            występuje w pliku <em>/etc/shells</em>.</li>
+        </ul>
+        <h4>Typy funkcji</h4>
+        <p>
+          System PAM oferuje aplikacji wykonanie czynności określonej jedną z 
+          z poniższych funkcji:
+        </p>
+        <ul>
+          <li><strong>auth</strong> - uwierzytelnienie użytkownika.</li>
+          <li><strong>account</strong> - sprawdzenie status (czy użytkownik
+            jest autoryzowany do wykonania pewnej czynności).</li>
+          <li><strong>session</strong> - wykonanie jakieś czynność na bierzącej
+            sesji użytkownika.</li>
+          <li><strong>password</strong> - zmiana danych uwierzytelniania.</li> 
+        </ul>
+        <p>
+          Warto wspomnieć, że moduły mogą zachować się inaczej (wykonywać inną
+          czynność, gdy zestawimy je z innymi funkcjami. Dla przykładu moduł
+          <em>pan_unix.so</em> dla modułu <em>auth</em> sprawdzi poprawność
+          podanego hasła, natomiast dla funkcji <em>password</em> ustawi je
+          użytkownikowi. Dlatego też funkcję i moduł podczas konfiguracji
+          PAM należy traktować jako parę.
+        </p>
+        <h4>Argumenty kontrolne</h4>
+        <p>
+          Inną częścią, wartą omówienie są argumenty kontrolne. Są one 
+          stosowane ze względu na to, iż wiersz zapisane w konfiguracji są 
+          zestawiane, co oznacza, że nie zawsze status (powodzenie,
+          niepowodzenie) jednego 
+          wiersza może oznaczać zwrócenie do aplikacji informacji o
+          powodzeniu lub niepowodzeniu funkcji przez nią żądanej. Inną kwestią 
+          jest rozszerzona składnia
+          argumentów kontolnych dopuszająca inne wartości niż tylko prawda
+          czy fałsz. Więcej na ten temat znajduje się na stronie podręcznika
+          pliku <em>pam.conf</em>. Poniżej znajdują się arguementy kontrolne
+          o prostej składni.
+        </p>
+        <ul>
+          <li><strong>sufficient</strong>. Jeśli reguła opatrzona tym 
+            argumentem powiedzie się, zbędne staje się sprawdzanie pozostałych
+            reguł, system PAM nie musi tego robić. Jeśli się niepowiedzie to
+            system przechodzi do kolejnej reguły.</li>
+          <li><strong>requisite</strong>. Jeśli reguła z tym argumentem
+            niepowiedzie się to wówczas całe uwierzytelnianie kończy się
+            niepowodzeniem. Jeśli reguła powiedzie się, to system przechodzi do
+            sprawdzenia pozostałych reguł, oczywiście jeśli zostały 
+            zdefiniowane.
+          </li>
+          <li><strong>required</strong>. Jeśli reguła powiedzie się to system
+            przechodzi do kolejnych reguł. Jeśli nie to system i tak sprawdzi
+            pozostałe dostępne reguły jednak jedyną zwracaną infomacją bedzie
+            niepowodzienie bez znaczenia czy następujące po <em>required</em>
+            reguły sie powiodły lub nie.</li>
+        </ul>
+        <p>
+          Znając składnię reguł systemu PAM, możemy spóbować samodzielnie
+          przeanalizować drugą linię znajdującą się w pliku <em>chsh</em> w
+          katalogu <em>/etc/pam.d</em>.
+        </p>
+<pre class="code-block">
+auth  sufficient  pam_rootok.so
+</pre>
+        <p>
+          Pamiętając o tym, że typ funkcji oraz moduł należy taktować jako
+          parę. Skupimy się na początku na argumencie kontrolonym. Otóż jeśli
+          ta reguła zakończy się powodzeniem system PAM nie będzie dalej
+          sprawdzać reguł. Natomiast funkcja (wraz z modułem) mają za zadanie
+          ustalenie czy to superużytkownik próbuje się uwierzytelnić.
+        </p>
+        <p>
+          Zwrócićmy uwagę na to, iż mimo tego co poznaliśmy konfigrację PAM
+          oraz przeanalizowaliśmy skonstruowany plik konfiguracyjny dla 
+          <em>chsh</em>, to 
+          <em>root</em> nadal może ustawić dowolną powłokę. Wynika to z
+          konstrukcji samego narzędzia. W tym przypadku PAM ma działać nad
+          uwierzytelnianiem zwykłego użytkownika i jego działań.
+        </p>
+        <p>
+          Moduły w regułach PAM mogą posiadać argumenty i są one umieszczane
+          po nazwie modułu, na przykład:
+        </p>
+<pre class="code-block">
+auth  sufficient  pam_unix.so nullok
+</pre>
+        <p>
+          Argument ten pozwala na stosowanie pustego hasła podczas
+          uwierzytelnienia.
+        </p>
+        <h3 id="7.10.3.pamnotices">7.10.3. Uwagi dotyczące PAM</h3>
+        <p>
+          Ze względu na to, iż wiekszość mechanizmów opisanych w tym materiale
+          zostało przedstawionych pobierznie, przecież to podstawy. To poniżej
+          znajduje się kilka wskazówek odnośnie systemu PAM.
+        </p>
+        <ul>
+          <li>Lista dostępnych w systemie modułów możemy wyświetlić za pomocą
+            polecenia 
+<pre class="code-block">
+$ man -k pam_
+</pre>
+            Jeśli potrzebujemy znać lokalizację modułów PAM, wówczas możemy
+            spróbowac użyć polecenia <em>locate</em> podając nazwę modułu
+            jako argument polecenia.</li>
+          <li>Strony podręcznika zawierają opis funkcji i argumentów dla
+            każdego modułu.</li>
+          <li>W wielu dystrybucjach pliki konfiguracji systemu PAM są
+            generowane automatycznie, wiec ich modyfikacja może nie być
+            najlepszym pomysłem. Przed wprowadzeniem zmian warto zapoznać
+            się z umieszczonymi w tych plikach komentarzami.</li>
+          <li>Plik <em>/etc/pam.d/other</em> definiuje konfigurację dla
+            aplikacji, które nie posiadają własnego pliku. Zazwyczaj
+            wszystko tam jest blokowane.</li>
+          <li>Istnieje możliwość dołączenia dodatkowych plików konfiguracjnych.
+            Za pomocą dyrektywy <em>@include</em> możemy załadować cały
+            dodatkowy plik, ale za pomocą specjalnego argumentu kontrolnego
+            możemy załadować plik konfiguracjny dla określonej funkcji. Te
+            sposoby są określne przez dystrybucje.</li>
+          <li>Definicja reguł systemu PAM nie kończy się na argumentach 
+            modułów. Moduły mogą uzyskiwać dostęp do plików w katalogu
+            <em>/etc/security</em>, które głownie mają na celu ograniczanie
+            uprawnień użytkownikom.</li>
+        </ul>
+        <h3 id="7.10.3.pamandpasswords">7.10.3. System PAM i hasła</h3>
+        <p>
+          System PAM możemy wykorzystać do uzyskiwania informacji na temat
+          haseł w systemie. Wykorzystanie modułu <em>pam_unix.so</em> wraz
+          z funkcją <em>auth</em> powoduje sprawdzenie hasła. Natomiast
+          jeśli użyjemy tego modułu wraz z funkcją <em>password</em> moduł
+          ustawi podane przez uzytkownika hasło. Wyszukując odpowiednią 
+          regułę możemy dowiedzieć się na przykład jakiego algorytmu użyto
+          do tworzenia skrótu hasła. Do odnalezienia tej linii posłużymy się
+          poniższym poleceniem. 
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:/ic0$ grep password.*unix /etc/pam.d/*
+/etc/pam.d/common-password:# used to change user passwords.  The default is pam_unix.
+/etc/pam.d/common-password:password    [success=1 default=ignore]      pam_unix.so obscure yescrypt
+</pre>
+        <p>
+          W drugiej linii znajduje się poszukiwana przez nas 
+          reguła. Skupmy się tylko na argumentach modułu. Otóż argument
+          <code class="code-inline">obscure</code>, najprościej rzecz ujmując
+          powoduje on sprawdzenie czy podane hasło jest wystarczająco 
+          "przesłonięte" (nie jest zbliżone do obecnie używanego). Kolejny
+          argument to algorytm szyfrowania w tym przypadku jest to
+          nowy algorytm <code class="code-inline">yescrypt</code>, do Debiana
+          został on wdrożony wraz z wypuszeniem wersji 11 "Bullseye".
+        </p>
+        <p>
+          No dobrze, w przypadku ustawiania hasła mamy jawnie podany algorytm.
+          A co w przypadku gdy moduł PAM musi sprawdzić czy podane hasło jest
+          poprawne. Niestety w tym przypadku PAM próbuje odgadnąć algorytm
+          wykorzystując do tego bibliotekę libcrypt, ktora wypróbowuje
+          wszystkie dostępne możliwości do momentu aż coś zadziała lub
+          nie pozostanie nic sprawdzenia.
+        </p>
+        <h1 id="8.processandresourcemonitoring">8. Procesy oraz monitorowania zasobów</h1>
+        <p>
+          Jeśli pamiętamy definicję procesu, to wiemy, że proces to nic innego
+          jak wystąpienie uruchomionego programu. Każdy proces aby mógł
+          wykonać swoje zadanie potrzebuje zasobów sprzetowych naszych 
+          komputerów oferowanych przez system operacyjny. Jądro odpowiada
+          za sprawiedliwy przydział zasobów systemowych. Samo jądro również
+          może być zasobem - programowym wykorzystywanym przez
+          procesy do uzyskiwania dostępu do plików czy do urządzeń
+          wejścia-wyjścia.  
+        </p>
+        <p>
+          W tym rozdziale objaśnimy sobie nieco bardziej procesy oraz zajmiemy
+          się monitorowaniem zasobów. Jednak nie po to aby optymalizować
+          system, ponieważ ten na domyślnych ustawieniach dystrybucji działa 
+          całkiem dobrze i nie potrzeba nic zmieniać. Zajmiemy się 
+          natomiast monitorowaniem zasobów by lepiej zrozumieć co jest 
+          dokładnie mierzone, dzięki czemu przybliżymy sobie, niektóre
+          działania jądra.
+        </p>
+        <h2 id="8.1.processtracking">8.1. Śledzenie procesów</h2>
+        <p>
+          Procesy możemy śledzić za pomocą polecenia <strong>ps</strong> i
+          w zależności od użytych przełączników możemy uzyskać różne 
+          rezultaty działania tego polecenia. Osobiście polecam
+          kombinację trzech przełączników <strong>-aux</strong>. Poza tym
+          to polecenie posiada trzy rózne możliwości wprowadzania do niego
+          opcji. Ja skupie się na jednym myślniku i łączeniu razem opcji. 
+          Inną godną polecenia kombinacją opcji jest <strong>-elf</strong>
+          te opcje zwracają najważniesze dla nas informacje, na przykład
+          jak wartość priorytetu oraz wartość <em>nice</em>, które biorą
+          udział w szeregowaniu procesów do wykonania. Dlaczego polecam tę
+          pierwszą kombinacją, ponieważ najczęściej do zarządzania jakimś
+          procesami będzie nam potrzebny PID, właściciel procesu, z jakiego
+          polecenia proces pochodzi lub procentowe wartości zużycia pamięci
+          czy procesora.
+        </p>
+        <p>
+          Innym przydatnym narzędziem dla śledzenia procesów jest polecenie
+          <strong>top</strong>. Ponieważ informacje wyświetlane przez to
+          polecenie są odświeżane co sekundę dając aktualny obraz tego co
+          się aktualnie dzieje w systemie. Po uruchomieniu tego programu na
+          samej górze listy procesów znajdują się najbardziej aktywne z nich.
+          Podczas działania programu, można przekazywać do niego opcje za
+          pomocą naciśniecia odpowiedniego klawisza. Poniżej znajduje się
+          kilka opisanych klawiszy.
+        </p>
+        <ul>
+          <li><strong>Spacja</strong> - natychmiastowe odświerzanie ekranu.</li>
+          <li><strong>Shift + m</strong> - sortuje procesy pod względem
+            zajętości pamięci.</li>
+          <li><strong>Shift + t</strong> - sortuje procesy pod względem
+            całkowitego zużycia czasu procesora.</li>
+          <li><strong>Shift + p</strong> - sortuje procesy pod względem
+            aktualnego zużycia czasu procesora. Użycie tego polecenia
+            przywraca domyślne ustawienia.</li>
+          <li><strong>u</strong> - wyświetla tylko dane procesów 
+            użytkownika.<li>
+          <li><strong>f</strong> - umożliwia wybranie różnych statystyk do
+            wyświetlenia.</li>
+          <li><strong>?</strong> - wyświetla informacje o opcjach programu
+            <em>top</em>.</li>
+        </ul>
+        <p>
+          W dystrybucjach Linuksa dostępne są różne odmiany polecenia
+          <em>top</em>, takie jak <strong>htop</strong> lub <em>atop</em>.
+          Polecenie <em>htop</em> jest znacznie bardziej rozbudowane, a
+          jego interaktywna konfiguracja pozwala nie tylko na zmianę
+          wyświetlanych danych, ale również zmianę tematu wyświetlania
+          (kolorów). Za pomocą <em>htop</em> możemy monitorować stan baterii.
+          Po za tym polecenie to posiada, niektóre możliwości innego
+          przydatnego polecenia jakim jest <em>lsof</em>.
+        </p>
+        <h2 id="8.2.lsof">8.2. Wyszukiwanie otwartych plików z pomocą polecenia lsof</h2>
+        <p>
+          Polecenie <strong>lsof</strong> może być bardzo przydatne ponieważ
+          pozwala wyświetlić
+          listę plików otwartych przez różnego rodzaju procesy. Co może okazać
+          się przydatne przypadku gdy chcemy odmontować jakiś system plików,
+          ale otrzymujemy informacje o tym, że <em>target is busy</em>. Ten 
+          komunikat
+          może być spowowany tym, że w systemie istnieją jeszcze procesy 
+          działające na plikach znajdujących się na odmontowywanym systemie
+          plików. Poza tym polecenie to generuje masę danych ze względu na
+          to, że w systemach uniksopodobnych wszystko jest plikiem, a więc 
+          nie otrzymamy informacji tylko i wyłącznie o konwencjonalnych
+          plikach, ale również o gniazdkach czy nazwanych potokach. Poniżej
+          znajduje się linia z otwartym plikiem podczas pisania tego tekstu. 
+        </p>
+<pre class="code-block">
+COMMAND    PID   USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
+vim.gtk3  3645 xf0r3m    7u      REG              254,0    20480    8391246 /media/xf0r3m/immudex_crypt0/Repos/morketsmerke-dev/articles/terminallog/.Linux.Podstawy.html.swp
+</pre>
+        <p>
+          Linia przedstawia otwarty plik z materiałem w trakcie redagowania.
+          Zwróćmy uwagę na nazwę pliku. Wygląda na to, że edytor <em>Vim</em>
+          ładuję zawartość pożądanego przez nas pliku do pliku bufora
+          (rozszenienie .swp). W momencie zapisu otwiera właściwy plik,
+          zapisuje dane poczym go zamyka. Edytor ten jest znany z tej metody
+          obsługi plików. Dzięki temu w przypadku nagłego wyłącznia komputera,
+          dane wciąż pozostają w pliku bufora. Nawet w przypadku, kiedy
+          będziemy otwierać ten plik to edytor zauważy pozostawiony plik
+          bufora, który o opuszczeniu programu powinien zostać usunięty. Jeśli
+          dla otwieranego przez ten edytor istnieje już plik wymiany, wówczas
+          edytor zapyta co zrobić z jego zawartością. 
+        </p>
+        <p>
+          Wracając, linie zwracane przez to polecenie podzielone są na 9 kolumn
+          Każda z nich zawiera:
+        </p>
+        <ul>
+          <li><strong>COMMAND</strong> - polecenie / nazwa procesu.</li>
+          <li><strong>PID</strong> - identyfikator procesu.</li>
+          <li><strong>USER</strong> - użytkownik, który zainicjował proces.</li>
+          <li><strong>FD</strong> - deskryptor pliku lub jego przeznaczenie.
+            Deskryptor otwartego pliku jest wykorzystywany przez proces przy
+            użyciu bibliotek wspódzielonych oraz jądra do identyfikowania
+            i manipulowania plikiem. Na przedstawionej linii mamy doczynienia
+            z deskryptorem.</li>
+          <li><strong>TYPE</strong> - rodzaj otwartego pliku (zwykły plik,
+            katalog).</li>
+          <li><strong>DEVICE</strong> - główny i poboczny numer urządzenia
+            przechowywującego plik.</li>
+          <li><strong>SIZE/OFF</strong> - rozmiar pliku.</li>
+          <li><strong>NODE</strong> - numer węzła inode.</li>
+          <li><strong>NAME</strong> - nazwa pliku / ścieżka do pliku.</li>
+        </ul>
+        <p>
+          Ze względu na przytłaczającą ilość danych zwracanych przez to
+          polecenie, możemy uruchomić je na dwa sposóby. Pierwszym z nich
+          jest przepuszcznie danych zwracanych przez to polecenie przez jakiś
+          filtr, najprostszym jest chyba polecenie <em>less</em> jednak lepiej
+          wyszukać informacji z użyciem wyrażeń regularnych (polecenia
+          <em>grep</em>). Drugą metodą jest zawężenie informacji zwracanych
+          poprzez wykorzystanie dostępnych opcji narzędzia. Najłatwiejszym w
+          użyciu jest podanie jako argumentu po prostu ścieżki do katalogu, z
+          którego chcemy widzieć otwarte pliki. Na przykład:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ lsof /home/xf0r3m
+COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
+pipewire   978 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+dbus-daem  983 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+pipewire-  988 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+xfce4-ses  989 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+at-spi-bu 1042 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+dbus-daem 1047 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+xfconfd   1051 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+...
+mpv       2923 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+atrild    3227 xf0r3m  cwd    DIR   0,27      400  638 /home/xf0r3m
+</pre>
+        <p>
+          A jeśli chcelibyśmy się dowiedzieć jakie otawrte pliki posiada
+          proces <em>mpv</em>, to możemy na przykład skorzystać z opcji
+          <strong>-p</strong> a jako jej argument podać PID procesu
+          <em>mpv</em> tak jak przedstawiłem to na przykładzie.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ lsof -p 2923
+COMMAND  PID   USER   FD      TYPE             DEVICE SIZE/OFF   NODE NAME
+mpv     2923 xf0r3m  cwd       DIR               0,27      400    638 /home/xf0r3m
+mpv     2923 xf0r3m  rtd       DIR               0,27      200      2 /
+mpv     2923 xf0r3m  txt       REG               0,29  2158056   4302 /usr/bin/mpv
+mpv     2923 xf0r3m  mem       REG                7,0            4302 /usr/bin/mpv (path dev=0,29)
+...
+mpv     2923 xf0r3m    5u     IPv4              26738      0t0    TCP 192.168.168.29:34108->prg03s12-in-f14.1e100.net:https (CLOSE_WAIT)
+mpv     2923 xf0r3m    6u     IPv4              26743      0t0    TCP 192.168.168.29:34122->prg03s12-in-f14.1e100.net:https (CLOSE_WAIT)
+mpv     2923 xf0r3m    7u     IPv4              88390      0t0    TCP 192.168.168.29:38584->prg03s13-in-f14.1e100.net:https (ESTABLISHED)
+mpv     2923 xf0r3m    8u     IPv4              86801      0t0    TCP 192.168.168.29:48618->85.162.162.204:https (ESTABLISHED)
+mpv     2923 xf0r3m    9u     unix 0x000000006b6ad31e      0t0  26745 type=STREAM
+mpv     2923 xf0r3m   10r     FIFO               0,12      0t0  26746 pipe
+mpv     2923 xf0r3m   11w     FIFO               0,12      0t0  26746 pipe
+mpv     2923 xf0r3m   12u      CHR              226,0      0t0    237 /dev/dri/card0
+mpv     2923 xf0r3m   13u      CHR              226,0      0t0    237 /dev/dri/card0
+mpv     2923 xf0r3m   14u      CHR              226,0      0t0    237 /dev/dri/card0
+mpv     2923 xf0r3m   15u      CHR              226,0      0t0    237 /dev/dri/card0
+mpv     2923 xf0r3m   16r     FIFO               0,12      0t0  26079 pipe
+mpv     2923 xf0r3m   17w     FIFO               0,12      0t0  26079 pipe
+mpv     2923 xf0r3m   18u  a_inode               0,13        0   7971 [eventfd]
+mpv     2923 xf0r3m   19u     unix 0x0000000075d44df6      0t0  26081 type=STREAM
+mpv     2923 xf0r3m   20u  a_inode               0,13        0   7971 [eventfd]
+mpv     2923 xf0r3m   21r     FIFO               0,12      0t0  26082 pipe
+mpv     2923 xf0r3m   22w     FIFO               0,12      0t0  26082 pipe
+</pre>
+        <p>
+          Zastanawiające może być, dlaczego <em>mpv</em> korzysta z połączeń
+          sieciowych, otóż za pomocą mpv oraz pakietu <em>youtube-dl</em>,
+          można korzystać z serwisu YouTube bez nadmiernego obciążenia
+          komputera przez nieoptymalną aplikację internetową.
+        </p>
+        <p>
+          Jeśli często aktualizujemy jądro, poza aktualizacją całej dystrybucji
+          to należy pamiętać o aktualizacji programu <em>lsof</em>.
+          Po aktualizacji jądra oraz programu <em>lsof</em>, może ono nie
+          nie działać prawidłowo, dopóki nie uruchomimy nowego jądra.
+        </p>
+        <h2 id="8.3.tracingprogramexecutionandsystemcalls">8.3. Śledzenie wykonania programów oraz wywołań systemowych</h2>
+        <p>
+          Zazwyczaj program jeśli się uruchamia i napotka podczas wykonywania
+          swoich czynności błąd to zwróci jakąś informację o tym co się
+          stało (większość programów uruchomianych na uniksach). Możemy jednak
+          napotkać taki przypadek, że uruchomimy program i on odrazu się
+          zamknie. Wówczas pojawia się problem w jaki sposób mamy dowiedzieć
+          się co jest nie tak z programem czy naszym środowiskiem (czy wszyskie
+          wymagane pakiety zostały zainstalowane, na przykład). Rozwiązania,
+          które przedstawię w tym podrozdziale na pewno nie są idealne i nie
+          sprawdzą się w przypadku każdego "migającego" programu.
+          Nie mniej jednak warto uruchomić dla niego chodziaż jedno z
+          zaprezentowanych tutaj poleceń.
+        </p>
+        <h3 id="8.3.1.stracecommand">8.3. Polecenie strace</h3>
+        <p>
+          Polecenie <em>strace</em> pozwala na uruchomienie programu wraz ze
+          śledzeniem wywołań systemowych (interfejsu jądra, pozwalającego na
+          wykonanie wielu czynności systemowych, na przykład otwarcia pliku
+          zapisanego gdzieś w systemie plików). Najprostszą poleceniem jakie
+          możemy wykonać dla przykładu jest wyświetlenie zawartości jakiegoś
+          pliku. Polecenie <em>strace</em> może nie występować we wszystkich
+          dystrybucjach, więc będzie trzeba je zainstalować. Z racji tego, iż
+          informacji zwracanych przez to polecenie jest na prawdę dużo to 
+          poniżej przedstawiłem wywołanie prostego wyświetlenia zawartości
+          pliku przy użyciu polecenia <em>cat</em>:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ strace cat yt-links
+execve("/usr/bin/cat", ["cat", "yt-links"], 0x7ffc8ee949b8 /* 39 vars */) = 0
+brk(NULL)                               = 0x564490232000
+access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Nie ma takiego pliku ani katalogu)
+openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=105669, ...}) = 0
+mmap(NULL, 105669, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f770de000
+close(3)                                = 0
+openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
+read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0&gt;\0\1\0\0\0@&gt;\2\0\0\0\0\0"..., 832) = 832
+fstat(3, {st_mode=S_IFREG|0755, st_size=1905632, ...}) = 0
+mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f770dc000
+mmap(NULL, 1918592, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f76f07000
+mmap(0x7f2f76f29000, 1417216, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f76f29000
+mmap(0x7f2f77083000, 323584, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17c000) = 0x7f2f77083000
+mmap(0x7f2f770d2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ca000) = 0x7f2f770d2000
+mmap(0x7f2f770d8000, 13952, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f770d8000
+close(3)                                = 0
+arch_prctl(ARCH_SET_FS, 0x7f2f770dd580) = 0
+mprotect(0x7f2f770d2000, 16384, PROT_READ) = 0
+mprotect(0x56448ed5a000, 4096, PROT_READ) = 0
+mprotect(0x7f2f77122000, 4096, PROT_READ) = 0
+munmap(0x7f2f770de000, 105669)          = 0
+brk(NULL)                               = 0x564490232000
+brk(0x564490253000)                     = 0x564490253000
+openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=3041312, ...}) = 0
+mmap(NULL, 3041312, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f76c20000
+close(3)                                = 0
+fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
+openat(AT_FDCWD, "yt-links", O_RDONLY)  = 3
+fstat(3, {st_mode=S_IFREG|0644, st_size=512, ...}) = 0
+fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
+mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f76bfe000
+read(3, "lofi girl stream: www.youtube.co"..., 131072) = 512
+write(1, "lofi girl stream: www.youtube.co"..., 512lofi girl stream: www.youtube.com/watch?v=jfKfPfyJRdk
+Stalker czyste niebo: www.youtube.com/playlist?list=PLMnTK-S7An4KqvvXn6AMkE00s_aDNZ29o
+Stalker zew prypeci: www.youtube.com/playlist?list=PLMnTK-S7An4K8BMXzFCVA0Y8KLSSHRfwV
+MysteryTV CP S03: www.youtube.com/playlist?list=PLjkTsi__dtwWJm4gUqaFLBva0k1TljXcn
+MysteryTC CP S04: www.youtube.com/playlist?list=PLjkTsi__dtwWR247M06TZ_2FxccG91f1u
+Tu skończyłem: https://www.youtube.com/watch?v=wnY3cTAujMc
+
+Iceberg o stalkerze: www.youtube.com/watch?v=uMHvO7LXVz8
+) = 512
+read(3, "", 131072)                     = 0
+munmap(0x7f2f76bfe000, 139264)          = 0
+close(3)                                = 0
+close(1)                                = 0
+close(2)                                = 0
+exit_group(0)                           = ?
++++ exited with 0 +++
+</pre>
+        <p>
+          Polecenie <code class="code-inline">strace</code> wykorzystuje
+          wyołanie systemowe <em>fork()</em> aby utworzyć kopię swojego procesu
+          następnie ta kopia jest zastępowana przez wywołanie systemowe
+          <code class="code-inline">execve()</code>, które uruchamia
+          podany przez nas proces, w tym przypadku jest wyświetlenie
+          zawartości pliku <code class="code-inline">yt-links</code>, po
+          zinicjowaniu pamięci oraz odpytaniu się bibliotek
+          proces <em>cat</em> chcę otworzyć
+          plik za pomocą wywołania systemowego
+          <code class="code-inline">openat</code>, jeśli otwarcie pliku
+          się powiedzie, otwartemu plikowi zostanie nadany pierwszy wolny
+          deskryptor, najczęsiej będzie to <code class="code-inline">3</code>,
+          co zostało przedstawione na przykładzie. Jeśli samodzielnie będziemy
+          uruchamiać podobne polecenie (nie każdy w swoim systemie posiada,
+          pliki <em>yt-links</em>), to zauważym że ten deskrytor jest
+          przypisywany i zwalniany kilkukrotnie podczas wykonywania czynności
+          Przed pobraniem zawartości pliku, pobierane są jego atrybuty za
+          pomocą wywołania <code class="code-inline">fstat()</code> oraz 
+          alokowana jest pamięci operacyjna 
+          (<code class="code-inline">mmap</code>) i wówczas następuje wywołanie
+          systemowe <code class="code-inline">read()</code>, które pobiera
+          zawartości pliku. Następne wywołanie systemowe odpowiedzialne jest
+          za wypisanie zawartości, do deskryptora o numerze
+          <code class="code-inline">1</code>. Jak pamiętamy polecenie 
+          <em>cat</em> wyświetla zawartość pliku podanego jako ścieżka
+          albo wyświetla podane dane z standardowego wejścia na standardowe 
+          wyjście. A
+          więc numer standardowego wyjścia, którym jest <strong>1</strong> jest
+          deskryptorem otwartego pliku. Dlatego też wywołanie systemowe
+          <code class="code-inline">write()</code> odwołuje się do
+          deskryptora o numerze <code class="code-inline">1</code>. Następnie
+          pamięć oraz wykorzystywane deskrytory zostają zwolnione i w ten
+          sposób kończy się wykonanie procesu polecenia <em>cat</em>.
+        </p>
+        <p>
+          Czytając ten obszerny opis możemy przyjrzeć się jak działają programy
+          na uniksach. Nie mniej jednak polecenie <em>strace</em> może pomóc
+          nam przy, nie których problemach z programami. Często sytuacją,
+          w której program może nam "mignąć" jest brak jakiegoś pliku lub
+          problem z jego dostępnością. Kiedy analizujemy wykonanie programu
+          za pomocą polecenia <em>strace</em> to należy szczególną uwagę
+          zwrócić na wywołania systemowe <em>openat()</em>. Poniżej znajdują się
+          dwa przykładowe komunikaty:
+        </p>
+<pre class="code-block">
+openat(AT_FDCWD, "test.txt", O_RDONLY)  = -1 ENOENT (Nie ma takiego pliku ani katalogu)
+openat(AT_FDCWD, "/etc/shadow", O_RDONLY) = -1 EACCES (Brak dostępu)
+</pre>
+        <p>
+          W przypadku błędu, zazwyczaj otrzymujemy deskryptor o numerze
+          <em>-1</em>, jednak zwróćmy uwagę na komunikaty błedów różnia się od
+          siebie (<code class="code-inline">ENOENT</code> a 
+          <code class="code-inline">EACCES</code>).
+        </p>
+        <h3 id="8.3.2.ltracecommand">8.3.2. Polecenie ltrace</h3>
+        <p>
+          Podobnym do <em>strace</em> narzędziem jest <strong>ltrace</strong>.
+          Jednak zamiast wywołań systemowych śledzi on wywołania bibliotek
+          wspóldzielonych, dane wyjściowe tego programu są zbliżone do 
+          <em>strace</em>. Program <em>ltrace</em> nie śledzi niczego na
+          poziomie jądra, to jednak warto mieć na uwadzę fakt, iż programy
+          o wiele częściej korzystają z bibliotek wspódzielonych niż z 
+          wywołań systemowych. Polecenie <em>ltrace</em> nie zadziała w
+          przypadku bibliotek dołączonych statycznie. A jego dane wyjściowe
+          możemy odfiltrować za pomocą opcji polecenia, których opis dostępny
+          jest na stronie podręcznika.
+        </p>
+        <h2 id="8.4.threads">8.4. Wątki</h2>
+        <p>
+          Procesy mogą dzielić się na podobne byty zwane 
+          <strong>wątkami</strong>. Wątki w pewnym sensie są podobne do
+          procesów, również zawierają identyfikator zwany <strong>TID</strong>
+          (ang. <em>Thread IDentifier</em>). Podobnie jak program może mieć
+          kilka procesów, odpowiadających wykonywanym przez niego czynnością,
+          to wątki mogą być efektem podziału czynności procesu na jeszcze
+          mniejsze części. W przypadku komputerów metoda rozwiązywania 
+          problemów "dziel i rządź", będzie miała zastosowanie jeszcze
+          nie jednokrotnie.
+        </p>
+        <h3 id="8.4.1.oneormultithreadprocess">8.4.1. Procesy jedno oraz wielowątkowe</h3>
+        <p>
+          Część procesów uruchamianych w systemie zawiera tylko jeden wątek.
+          Wówczas taki proces jest procesem jednowątkowym. Na początku, każdy
+          proces posiada jeden wątek, zwany <strong>wątkiem głównym</strong>.
+          Wątek główny może tworzyć kolejne wątki, zmieniając ten proces tym
+          samym w proces wielowątkowy.
+        </p>
+        <p>
+          Podstawową zaletą procesów wielowątkowych jest fakt wykonania 
+          zaplanowanych w procesie czynności o wiele szybciej, gdyż każdy
+          wątek może być wykonywany przez jeden procesor (wątek procesora,
+          tak rdzenie procesorów też mogą zawierać w sobie wątki, przeważnie
+          na jeden rdzeń przypadają dwa wątki). Innym cechą wątków jest to
+          iż wykorzystują one wspólne obszary pamięci, (nie tak jak w
+          przypadku procesów, gdzie procesy nie mają dostępu do obszaru
+          pamięci innych procesów) usprawniając tym samy komunikację miedzy
+          wątkami. Wątki najczęsciej wykorzystywane są do obsługi operacji
+          wejscia-wyjścia. Użycie w tym przypadku wątków zamiast procesów 
+          pozwala nam zaoszczędzić trochę czasu procesora.
+        </p>
+        <h3 id="8.4.2.displaingthreads">8.4.2. Wyświetlanie wątków.</h3>
+        <p>
+          Pozanane do tej pory narzędzia służące do obserowania procesów
+          również sprawdzą się gdy będziemy chcieli wyświetlić informacje
+          na temat wątków. W przypadku polecenia <em>ps</em> wystarczy dodać
+          do polecenia opcję <strong>m</strong>, warto jednak zaznaczyć by 
+          nie mieszać opcji <em>m</em> wraz z opcją <em>u</em>. Na poniższym
+          przykładzie wyświetliłem moje procesy uruchomione w terminalach.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ ps -am -opid,tid,time,cmd
+    PID     TID     TIME CMD
+   1799       - 00:00:02 /usr/bin/python3 -O /usr/bin/ranger
+      -    1799 00:00:02 -
+   7507       - 00:00:00 /bin/sh -c set -- '/ic0/Repos/morketsmerke-dev/articles/terminallog/Linux.P
+      -    7507 00:00:00 -
+   7508       - 00:00:00 /bin/sh /usr/bin/sensible-editor -- /ic0/Repos/morketsmerke-dev/articles/te
+      -    7508 00:00:00 -
+   7512       - 00:00:05 /usr/bin/vim.gtk3 -- /ic0/Repos/morketsmerke-dev/articles/terminallog/Linux
+      -    7512 00:00:05 -
+  12070       - 00:00:00 ps -am -opid,tid,time,cmd
+      -   12070 00:00:00 -
+</pre>
+        <p>
+          Zwróćmy uwagę na to numery PID oraz TID są takie same. W przypadku
+          poleceń jednowątkowych, wątek główny posiada taki sam TID jak
+          proces macierzysty. Jeśli pojawiłby się procesy, wkorzystujące 
+          wątki, to wówczas TIDy wynośiły by kolejne numery rozpoczynając od
+          PID-u lub TID-u wątku głównego.
+        </p>
+        <p>
+          Jeśli preferujemy narzędzie <em>top</em> to wówczas użycie kombinacji
+          klawiszy <em>Śhift + h</em> pozwoli nam na wyświetlenie wątków.
+          Możemy je rozpoznać po tym, że wyświetlone tam "procesy" są
+          uruchomione z tego samego polecenia i posiadają następujące po sobie
+          identyfikatory.
+        </p>
+        <p>
+          Wątki w tym materiale zostały przedstawione, aby zaprezetować ich
+          istnienie i na tym temat się kończy.
+        </p>
+        <h2 id="8.5.resourcemonitoring">8.5. Monitorowanie zasobów</h2>w
+        <p>
+          Monitorowanie zasobów komputerów przeprowadza się głównie, aby 
+          dowiedzieć się, które z komponentów systemów lub komputerów należy
+          z optymalizować, aby nasza praca była jescze bardziej wydajna, abyśmy
+          mogli zrobić coś lepiej, szybciej oraz niższym nakładem pracy. Jak
+          już wspomniałem jądro Linuksa jest bardzo wydajne przy domyślnych
+          ustawieniach i nie trzeba się tym przejmować. Dlatego też
+          wykorzystamy monitorowanie zasobów czasu procesora, pamięci
+          operacyjnej oraz operacji wejścia-wyjścia do sprawdzenia w jaki
+          sposób dzieli je między procesami.
+        </p>
+        <h2 id="8.6.measuringprocessorusage">8.6. Pomiar czasu procesora</h2>
+        <p>
+          Do monitorowania w czasie rzeczywistym pojedynczych procesów możemy
+          wykorzystać polecenie <em>top</em> wraz z opcją <strong>-p</strong>.
+          Jako argumenty opcji podajemy listę identyfikatorów procesów.
+        </p>
+<pre class="code-block">
+$ top -p 3329,1230
+</pre>
+        <p>
+          Wówczas polecenie <em>top</em> pokaże na swojej liście tylko te dwa
+          procesy.
+        </p>
+        <p>
+          Aby dowiedzieć się ile czasu procesora w trakcie swojego działania
+          wykorzystało konkretne polecenie, to należy je uruchomić za pomocą
+          polecenia <strong>time</strong>, jednak tu musimy się na chwilę
+          zatrzymać gdyż przeważnie w większości dystrybucji istnieją dwa
+          polecenia <em>time</em>. Jedno jest polecenie wbudowanym w powłokę
+          i nie ma z niego za bardzo pożytku. Dla przykładu poniżej umieszczam
+          pomiar czasu procesora wbudowanym w powłokę polecenie <em>time</em>:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ time ls
+...
+real   0m0,007s
+user   0m0,001s
+sys      0m0,007s
+</pre>
+        <p>
+          Z kolei dostęp do właściwego polecenie uzyskamy uruchamiając
+          konkretny plik: <strong>/usr/bin/time</strong>, jednak twórcy
+          wiodących dystrybucji uznają, że polecenie wbudowane w powłokę
+          wystarczy, dlatego też prawdopodbne jest, że omawiany przez nas
+          program nie będzie domyślnie zainstalowany w naszym systemie. 
+          Poniżej znajduje się to samo polecenie wykonane za pomocą właściwego
+          programu.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ /usr/bin/time ls
+...
+0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 2516maxresident)k
+0inputs+0outputs (0major+123minor)pagefaults 0swaps
+</pre>
+        <p>
+          To polecenie zwraca znacznie więcej informacji na temat wykonanego
+          polecenia. Na tym etapie będą interesować trzy pierwsze wartości:
+          <code class="code-inline">0.00user 0.00system 0:00.00elapsed</code>.
+          Wskazują one kolejno: 
+        </p>
+        <ul>
+          <li><strong>Czas użytkownika</strong>
+            (<code class="code-inline">0.00user</code>) - liczba sekund
+            poświęcona przez procesor na wykonanie właściwego kodu programu.
+            Przy obecnej mocy obliczeniowej komputerów czas wykonania prostej
+            czynności jest natyle krótki, że program zaokrągla go do zera.</li>
+          <li><strong>Czas systemowy</strong>
+            (<code class="code-inline">0.00system</code>) - czas poświęcony
+            przez jądro na obsługę procesu (na przykład, odczyt zawartości
+            plików lub katalogów).</li>
+          <li><strong>Czas trwania</strong>
+            (<code class="code-inline">0.00elapsed</code>) - całkowity czas
+            działania procesu od początku do końca jego życia, wraz ze
+            wszystkimi dodatkowymi czynnościami. Czas ten nie jest szczególnie
+            brany pod uwagę podczas pomiarów wydajności, ale odjęcie sumy
+            czasu użytkownika oraz czasu systemowego od tej wartości przedstawi
+            czas oczekiwania na zasoby.</li>
+        </ul>
+        <p>
+          Pozostałe wartości zwracane przez to polecenie dotyczą pamięci,
+          operacji wejścia-wyjścia oraz stronicowania (do stronicowania jeszcze
+          wrócimy w tym rozdziale).
+        </p>
+        <h2 id="8.7.processprioritization">8.7. Priorytetyzacja procesów</h2>
+        <p>
+          W pierwszym rodziale poruszyliśmy temat zarządzania procesami przez
+          jądro, dowiedzielśmy się, że każdy proces otrzymuje dostęp do
+          procesora na ułamek sekundy. Modułem odpowiedzialnym za to, który
+          z procesów uzyska w chwili obecnej dostęp do procesora jest
+          <strong>program szeregujący</strong>, który na podstawie
+          <strong>priorytetu</strong> procesu może przydzielć mu więcej lub
+          mniej czasu. W dystrybucja Linuksa priorytety funkcji przedstawiane
+          są dwojako. Polecenie <em>top</em> przestawia domyślny priorytet
+          wartością <strong>20</strong> (kolumna PR), jeśli jednak wywołamy 
+          polecenie
+          <em>ps</em> z opcjami <em>-elf</em> (ta sama kolumna), to domyślnym 
+          priorytetem będzie
+          <strong>80</strong>. My na tym etapie będziemy trzymać się raczej
+          wartosci przedstawianych przez polecenie <em>top</em>, ponieważ
+          łatwiej będzie nam je zrozumieć. Więc domyślnym priorytem jest
+          <em>20</em>, poniżej przedstawiam kilka procesów wyświetlonych przez
+          narzędzie <em>top</em>:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ top
+
+top - 09:32:04 up  1:55,  1 user,  load average: 0,73, 0,65, 0,61
+...
+PID UŻYTK.    PR  NI    WIRT    REZ    WSP S  %CPU  %PAM     CZAS+ KOMENDA
+2364 xf0r3m    20   0 2504764 158992  90048 S   0,3   2,0   0:37.66 Isolated Web Co
+2418 xf0r3m    20   0  474048  94468  66272 S   0,3   1,2   1:39.81 xfce4-terminal
+4395 root      20   0       0      0      0 I   0,3   0,0   0:01.40 kworker/3:0-events
+33705 xf0r3m    20   0   10404   4212   3452 R   0,3   0,1   0:00.36 top 
+</pre>
+        <p>
+          Najwyższym priortem w tym przypadku jest działanie w czasie
+          rzeczywistym, ale na tym etapie nie będziemy się tym zajmować. Tak
+          więc na chwilę obecną najwyższym priortetem jest <strong>1</strong>,
+          a najniższym <strong>39</strong>.
+        </p>
+        <p>
+          Do manipulacji priorytetami wartość <strong>nice</strong>
+          (kolumna NI), przechowuje ona wartość wpływającą na priorytet
+          zwiększając go lub zmieniajszając. Do ustawienia wartości
+          <em>nice</em> służy polecenie <strong>renice</strong>. To polecenie
+          możemy wykonać bez uprawnień administrator o ile zmniejszamy
+          priorytet (podając wysoką wartość <em>nice</em>, która dodawana jest
+          do domyślnej wartości priortetu), zmniejszenie priorytetu
+          (podanie ujemnej wartości <em>nice</em>) wymaga już uprawnień
+          superużytkownika. Polecenie to poza nową wartością <em>nice</em>
+          wymaga podania PID-u procesu.
+        </p>
+<pre style="code-block">
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ pidof top
+37426
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ renice 20 37426
+37426 (process ID) old priority 0, new priority 19
+
+#lub krócej:
+
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ renice 20 $(pidof top) 
+37426 (process ID) old priority 0, new priority 19
+</pre>
+        <p>
+          Polecenie <code class="code-inline">pidof</code> pozwala uzyskać
+          PID procesu na podstawie polecenia, jeśli uruchomionych jest więcej
+          niż jedna instancja danego programu polecenie zwróci listę PID-ów.
+          Podczas zmiany priorytetu mimo, iż podaliśmy wartość 20 to
+          największą wartością <em>nice</em> jest 19 tak samo jest w drugą
+          stronę. Najmniejszą wartością <em>nice</em> (a zatem proces będzie
+          mieć największy priortet) jest <em>-19</em>.
+        </p>
+        <p>
+          Priortety i manipulacja nimi miała dużo większe znaczenie w czasch
+          gdy z jednego systemu korzystało wielużytkowników. Obecnie maja one
+          mniejsze znaczenie. Warto też dodać, aby nie wymuszać wysokich
+          priortetów, gdyż mogą one zablokować istotne dla funkcjonowania
+          systemu procesy i go zdestabilizować.
+        </p>
+        <h2 id="8.8.loadaverages">8.8. Średnie obciążenia</h2>
+        <p>
+          <strong>Średnie obciążenia</strong> jest to o szaczowana liczba
+          procesów do uruchomienia. Ten parametr określa ilość procesów
+          gotowych w każdej chwili użyć procesora. Jak pamiętamy nie wszystkie
+          procesy są gotowe do działania, część z nich czeka na dane. Średnie
+          obciążenia są wyświetlane przez polecenie <strong>uptime</strong>. 
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ uptime
+ 10:40:15 up  3:03,  1 user,  load average: 1,14, 0,99, 1,17
+</pre>
+        <p>
+          Wartości przedstawione obok etykiety
+          <code class="code-inline">load average</code> przedstawiaja średnie
+          obciążenia z minuty, 5 i 15 minut. Na powszszym przykładzie widzimy
+          że ciągu ostatniej minuty z użyto na wykonanie procesów użytkownika
+          114% procent procesora. Jeśli obiążenia tak jak na przykładzie stale
+          utrzymują się powyżej 1, to oznacza to, że jeden proces cały czas
+          wykorzystuje jeden rdzeń procesora. Pełne obiążenie komputera w
+          przypadku tego wskaźnika będzie oscylować w granicach ilości
+          rdzeni/wątków procesora zamontowanego w naszym komputerze.
+        </p>
+        <p>
+          Wysokie średnie obciążenia mogą wynikać nie tylko z działania w
+          systemie procesów ale również ze względu na pozostałą nie wielką
+          ilość pamięci dostępnej w systemie. Wówczas jądro może zarządzić
+          <strong>proces przeładowania</strong> (ang. <em>trashing</em>), 
+          powoduje to szybkie
+          przenoszenie stron pamięci na dysk oraz z dysku. Gdy ma to miejsce
+          ilość procesów gotowych do uruchomienia zwiększa sią powodując
+          znacznie zwiększenie średniej obiążenia. Ze względu na małą ilość
+          wolnej pamięci system może działać znacznie wolniej i niż zwykle.
+        </p>
+        <h2 id="8.9.operating memory">8.9. Pamięc</h2>
+        <p>
+          Pamięć operacyjna jest bardzo ważnym komponentem komputera, jeśli
+          chodzi o maszyny uniksowe. W pamięci rezydują obszary, w których
+          procesy przechowują swoje dane, a jej ilość jest ograniczona. Do
+          monitorowania pamięci możemy posłużyć się takimi narzędziami jak
+          polecenie <strong>free</strong> (w przypadku tego polecenia, warto
+          przeskalować sobie wartości zwracane za pomocą opcji 
+          <strong>-h</strong>) lub skorzystać z interfejsu systemowego
+          wyświetlając zawartość pliku <em>/proc/meminfo</em> (tutaj jednak
+          jestśmy skazani na wartość wyrażone w kilobajtach). Jeśli pamięć
+          podręczna/bufora nie zajmuje dużego obszaru pamięci fizycznej, a
+          mimo to nie mamy w zanadrzu wiekszej ilości wolnej pamięci to 
+          niezbędne może być dołożenie pamięci do naszego komputera, aby
+          poprawić jego wydajność.
+        </p>
+        <h3 id="8.9.1.memorymanagement">8.9.1. Zarządzenie pamięcią</h3>
+        <p>
+          Jądro w tym zadaniu opera się na jednosce <strong>MMU</strong>
+          (ang. Memory Management Unit), której zadaniem jest zamiana adresów
+          pamięci wirtualnej na adresu pamięci fizycznej. Pamięć wirtualna
+          jest wykorzystywana przez procesy. Jądro współpracuje
+          z MMU dzieląc obszary procesów na mniejsze strony, trzymając tym
+          samym dane służące MMU do odzworowania adresów w strukturze danych
+          zwanej <strong>tabelą stron</strong>. W momencie uzyskania przez
+          proces dostępu do pamięci jednostka MMU dzięki tej strukturze może
+          dokonywać translacji adresów.
+        </p>
+        <p>
+          Procesy zazwyczaj nie wymagają dostępu do pełnego obszaru w pamięci
+          od razu. Jądro ładuje wówczas tylko te strony, których proces
+          wymaga. Taki rodzaj przydzielania pamięci nazywany jest
+          <strong>stronicowaniem na żądanie</strong>.
+        </p>
+        <p>
+          Przydzielenie pamięci nowemu procesowi, możemy zapisać w czterech
+          krokach. 
+        </p>
+        <ol>
+          <li>Jądro ładuje do stron pamięci początek kodu programu</li>
+          <li>Jeśli zajdzie taka potrzeba jądro może przypisać procesowi kilka
+            stron pamięci.</li>
+          <li>W trakcie działania procesu, może zajść potrzeba załadowania
+            większej ilości kodu, ponieważ następna instrukcja do wykonania
+            nie znajduje się na załadowanych początkowo stronach. W takiej
+            sytuacji jądro przejmuje kontrolę, ładuje wymagane strony i
+            pozwala programowi wznowic działanie.</li>
+          <li>Jeśli zajdzie potrzeba przydzielenia więcej pamięci niż
+            zakładano na początku, jądro znajduje nieużywane strony, zwalnia
+            je i przydziela procesowi.</li>
+        </ol>
+        <h3 id="8.9.2.pageserrors">8.9.2. Błędy stron</h3>
+        <p>
+          Nie zawsze wyżej wymienione czynności da się spiąć w czasie. Jeśli
+          żądana przez proces strona w pamięci nie jest jeszcze gotowa to
+          generują on <strong>błąd strony</strong>. Gdy taki błąd zostanie
+          wygenerowany, to kontrolę nad procesorem przejmuje jądro aby
+          załadować żądaną stronę. Błędy dzielą się na podstawowe oraz
+          drugorzędne.
+        </p>
+        <h4>Drugorzędne błedy stron</h4>
+        <p>
+          Błędy tego typu nię są poważnym błedami, i zdarzają się dość często.
+          Ich najczęstszym powodem występowania jest fakt iż MMU nie zna 
+          położenia strony z instrukcjami programu. Samo MMU może nie mieć
+          odpowiednio dużo miejsca aby przechować adresy wszystkich obszarów.
+          W przypadku występowania takiego błędu jądro przekazuje do MMU
+          informacje o położeniu strony i pozwala na wznowienie działania
+          procesu.
+        </p>
+        <h4>Podstawowe błędy stron</h4>
+        <p>
+          Podstawowe błędy występują wówczas gdy strony nie ma w ogóle w
+          pamięci. Jądro musi ją załadować z jakiegoś nośnika najczęsciej jest
+          to dysk. Duża ilość tego typu błędów może przeciążyć system ponieważ
+          procesor jest zajęty przez jądro ładujące kod z niekoniecznie
+          szybkich nośników, blokując go tym samym dla innych procesów. 
+          Niestety pewna ilość tego typu błedów jest
+          nie unikniona, a mają one miejsce kiedy po raz pierwszy uruchamiamy
+          jakiś program, wówczas należy załadować kod z dysku. 
+        </p>
+        <h4>Obserowowanie błędów stron</h4>
+        <p>
+          Do obserwowania błędów stron przydatne staje się polecenie 
+          <strong>time</strong>, o którym wspomniałem przy okazji pomiaru
+          czasu procesora. Jednak w tym przypadku będzie interesować nas
+          wartość w nawiasie obok napisu 
+          <code class="code-inline">pagefaults</code>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ /usr/bin/time timedatectl
+               Local time: nie 2023-01-08 17:59:08 CET
+           Universal time: nie 2023-01-08 16:59:08 UTC
+                 RTC time: nie 2023-01-08 16:59:08
+                Time zone: Europe/Warsaw (CET, +0100)
+System clock synchronized: no
+              NTP service: n/a
+          RTC in local TZ: no
+0.00user 0.01system 0:00.10elapsed 24%CPU (0avgtext+0avgdata 7416maxresident)k
+522inputs+0outputs (8major+359minor)pagefaults 0swaps
+</pre>
+        <p>
+          W przypadku uruchomienia w moim systemie polecenia
+          <code class="code-inline">timedatectl</code> wystąpiły 8 błędów
+          podstawowych (<code class="code-inline">8major</code>) oraz 359
+          błedów drugorzędnych.
+        </p>
+        <p>
+          Inne narzędzia takie <em>top</em> oraz <em>ps</em> również mogą 
+          wyświetlać informacje o błędach stron pamięć, w przypadku polecenia
+          <em>top</em> należy włączyć wyświetlanie <em>nMaj</em> oraz
+          <em>nMin</em>, aby przejść do konfiguracji należy nacisnąć literę
+          <em>f</em>, a następnie postępować zgodnie z instrukcją. Program
+          <em>ps</em> pozwala na wyświetlenie błędów strony poprzez podanie
+          niestandardowego wyświetlania kolumn (opcja <em>-o</em>) kolumny
+          noszą kolejno nazwy <em>maj_ftl</em> i <em>min_ftl</em>.
+        </p>
+        <h2 id="8.10.vmstat">8.10. Monitorowanie wydajności za pomocą polecenia vmstat</h2>
+        <p>
+          Polecenie <em>vmstat</em> pozwala na monitorowanie wielu aspektów
+          wydajności systemu, a jest jednym z najstarszych narzędzi tego typu.
+          Dane wyświetlane również pozostawiają wiele do życzenia i osoba
+          nie mająca styczności z tym narzędziem, może uznać je za mało
+          czytelne.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ vmstat 2
+proc. -----------pamięć---------- ---swap-- ---we/wy--- -system-- ------cpu-----
+dz bl   swap  wolna  bufor  cache   si   so    bi    bo   in   cs uż sy be io sk
+ 0  0      0 861264  13196 5331448    0    0    56     3  189  210 13  4 83  0  0
+ 0  0      0 861112  13196 5330624    0    0     0     0 2071 4073  8  4 88  0  0
+ 0  0      0 861712  13196 5330664    0    0     0     0 1944 3661  7  4 88  0  0
+ 0  0      0 862012  13196 5330608    0    0     0     0 2007 3866  7  4 89  0  0
+</pre>
+        <p>
+          Polecenie to przyjmuje jako argument interwał czasowym co ile sekund
+          ma wyświetlać nowe statystki. Każda linia to w tym przypadku
+          statystyki pobrane co dwie sekundy. Wyjście polecenia zawiera
+          tematyczne kolumny. Pierwszą z nich są procesy, ta kolumna zawiera
+          jeszcze dwie inne kolumny wskazujące procesy gotowe do uruchomienia
+          (<code class="code-inline">dz</code>) oraz te
+          zablokowane (<code class="code-inline">bl</code>). W następnej 
+          kolumnie znajdują się informacje na temat
+          pamięci, a w niej informacje o wykorzystaniu przestrzeni wymiany
+          (<code class="code-inline">swap</code>), ilości wolnej
+          pamięci, pamięci przeznaczonej na bufor oraz pamięci przeznaczonej
+          na pamięć podręczną. W trzeciej kolumnie znajdują się informacje o
+          przestrzeni wymiany, ile stron zostało przeniesionych na dysk
+          (<code class="code-inline">si</code>) oraz ile stron zostało
+          załadowanych z dysku do pamięci 
+          (<code class="code-inline">so<code>). Czwarta kolumna zawiera 
+          informacje o użyciu urządzeń wejścia-wyjścia, dane odczytane z dysku
+          (<code class="code-inline">bi</code>) oraz dane zapisane na dysku
+          (<code class="code-inline">bo</code>). Piąta kolumna zwiera
+          informacje systemowe, w niej znajdują się liczniki wywołań
+          systemowych (<code class="code-inline">in</code>) oraz przełączeń
+          kontekstu (<code class="code-inline">cs</code>). Ostatnia kolumna
+          zawiera procentowe zużycie czasu procesora dla kolejno: aplikacji
+          użytkownika (<code class="code-inline">uż</code>), jądra oraz obsługi
+          procesów (<code class="code-inline">sy</code>), stanu bezczynności
+          (<code class="code-inline">be</code>), czasu przeznaczonego na
+          obsługę operacji wejścia-wyjścia 
+          (<code class="code-inline">io</code>), czasu skradziony wirtualnej
+          maszynie (<code class="code-inline">sk</code>).
+        </p>
+        <p>
+          Polecenie to zawiera wiele przydanych opcji, które są zawarte na
+          stronie podręcznika programu. Jak na przykład opcję
+          <strong>-d</strong>, która pozwala na monitorowanie dysków.
+        </p>
+        <h2 id="8.11.iomonitoring">8.11. Monitorowanie operacji wejścia-wyjścia</h2>
+        <p>
+          Na dystrybucje Linuksa dostępnych jest kilka narzędzi służących do
+          monitorowania operacji wejścia-wyjścia, które w dużej mierze są
+          operacjami dyskowymi.
+        </p>
+        <h3 id="8.11.1.iostat">8.11.1. Polecenie iostat</h3>
+        <p>
+          Jedno znich przypomina omawiany w wcześniejszym
+          podrozdziale program <em>vmstat</em>, a jest nim polecenie
+          <strong>iostat</strong>, to polecenie może nie być domyślnie
+          zainstalowane i jeśli chcemy z niego skorzystać to należy je
+          zainstalować. Pakiet zawierający ten program zajduje się w
+          repozytoriach <em>Debiana</em> po nazwą <em>sysstat</em>. Poniżej
+          znajduje się przykład:
+        </p>
+<code class="code-block">
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ iostat 
+Linux 5.10.0-20-amd64 (immudex)        10.01.2023      _x86_64_        (4 CPU)
+
+avg-cpu:  %user   %nice %system %iowait  %steal   %idle
+          17,27    0,00    4,22    0,01    0,00   78,50
+
+Device             tps    kB_read/s    kB_wrtn/s    kB_dscd/s    kB_read    kB_wrtn    kB_dscd
+dm-0              0,35         3,52         0,61         0,00      25273       4396          0
+loop0             6,27        73,04         0,00         0,00     524237          0          0
+sda               1,55        66,41         0,56         0,00     476690       4048          0
+</code>
+        <p>
+          Oryginalny wydruk jest kolorowy. Ciemno niebieskie pola, mogą być
+          trochę nieczytelne, ale oznaczają one wartość
+          <code class="code-inline">0,00</code>. Pierwsza linia zawiera nazwę
+          jądra, nazwę hosta w nawiasie, aktualną datę, architekturę procesora
+          oraz liczbę logicznych procesorów (rdzenie/wątków). Druga oraz
+          trzecia linia zawierają średnie zużycie czasu procesora oraz 
+          objaśnienia tych wartości. Poniżej znajduje się tabelka
+          przedstawiająca urządzenia (<code class="code-inline">Device</code>),
+          liczba transferów na sekundę (liczba operacji wejścia-wyjścia na
+          sekundę wystosowana wobec urządzenia, 
+          <code class="code-inline">tps</code>); liczba danych odczytanych na
+          sekundę (<code class="code-inline">kB_read/s</code>); liczba danych
+          zapisanych na sekundę (<code class="code-inline">kB_write/s</code>);
+          liczba danych odrzuconych na sekundę dla urządznia
+          (<code class="code-inline">kB_dscd</code>), ostatnie trzy kolmny
+          wrażają podobne wartości tylko zamiast prędkości jest przedstawiona
+          tam łączna ilość.
+        </p>
+        <p>
+          Domyślnie dane wyrażane są w kilobajtach, jak prawie wszystko w
+          systemie co dotyczy pamięci masowych, jednostki możemy przeskalować
+          do megabajtów za pomocą opcji <strong>-m</strong>, natomiast za
+          pomocą opcji <strong>-p</strong> wraz z argumentem <em>ALL</em>
+          możemy wyświetlić statystki dla wszystkich urządzeń blokowych
+          dostępnych w systemie. Podobnie do <em>vmstat</em> podanie gołej
+          liczby jako argumentu spowoduje włączenie interwału czasowego o 
+          podanej wartości. Więcej opcji oraz bardziej szczegółowe wyjaśnienia
+          znajdują się na stronie podręcznika programu.
+        </p>
+        <h3 id="8.11.2.iotop">8.11.2. Polecenie iotop</h3>
+        <p>
+          Innym poleceniem służącym do monitorowania operacji wejścia-wyjścia
+          jest program <strong>iotop</strong>, zasada działania tego programu
+          jest podobna do znanego nam już narzędzia <em>top</em> tylko tym
+          razem zamiast skupiać się na procesach, położono nacisk na operacje
+          wejścia wyjścia.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo iotop
+Total DISK READ:         0.00 B/s | Total DISK WRITE:         0.00 B/s
+Current DISK READ:       0.00 B/s | Current DISK WRITE:       0.00 B/s
+    TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO&gt;    COMMAND                            
+      1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % init
+      2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
+      3 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_gp]
+      4 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_par_gp]
+      6 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/0:0H-events_highpri]
+      8 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [mm_percpu_wq]
+      9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_tasks_rude_]
+     10 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_tasks_trace]
+     11 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
+     12 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_sched]
+     13 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
+     15 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [cpuhp/0]
+     16 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [cpuhp/1]
+     17 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/1]
+     18 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/1]
+</pre>
+        <p>
+          Jak możemy zauważyć to polecenie wyświetla nam identyfikatory wątków.
+          Jest to jedno z nielicznych narzędzi wyświetlających wyświetlających
+          wątki, ponieważ często procesy dzielą się na nie aby własnie
+          zająć się obsługą wejścia-wyjścia. Inna kolumną wartą opisania jest
+          <code class="code-inline">PRIO</code>, podobnie jak procesy jądro
+          stara się szergować operacje wejścia-wyjścia. Przyczym priorytet
+          tutaj dzieli się na dwie wartości, klasę oraz poziom samego
+          priorytetu. Wątki o priorytecie
+          <code class="code-inline">be/0</code> otrzymają więcej czasu 
+          procesora na realizacje operacji niż wątki z priorytetem
+          <code class="code-inline">be/4</code>. Samych klas priorytetów
+          mogą wystąpić trzy rodzaje takie jak:
+        </p>
+        <ul>
+          <li><strong>be</strong>(<strong>best-effort</strong>) - w przypadku
+            tego priorytetu jądro stara się jak najbardziej sprawiedliwie
+            uszeregować operacje wejścia-wyjścia. Tę klasę posiada większość
+            operacji.</li>
+          <li><strong>rt</strong>(<strong>real-time</strong>) - Jądro
+            bezwarunkowo szereguje operacje opatrzone tą klasą ponad każdą
+            inną.</li>
+          <li><strong>idle</strong>, klasa bezczynności. Jądro będzie wykonywać
+            operacje z tą klasą, tylko wtedy gdy nie jest wykonywana żadna 
+            inna operacja. Ta klasa nie posiada żadnych poziomów, będąc
+            zarazem najniższym priorytetem.</li>
+        </ul>
+        <p>
+          Do manipulacji priortetami operacji wejścia-wyjścia służy polecenie
+          <strong>ionice</strong>, więcej na jego temat znajdziemy na stronie
+          podręcznika.
+        </p>
+        <h2 id="8.12.pidstat">8.12. Monitorowanie procesów za pomocą narzędzia pidstat</h2>
+        <p>
+          Za pomocą polecenia <em>top</em> możemy śledzić wykorzystanie
+          zasobów przez wybrany proces. Problem w przypadku tego rozwiązania
+          jest brak poprzednich wartości, ponieważ dane odświerzane są co
+          interwał czasowy (w przypadku <em>top</em> jest to jedna sekunda).
+          Rozwiązaniem tej niedogodności może być zastosowanie narzędzia
+          <strong>pidstat</strong>, ponieważ zachowuje on się tak jak 
+          <em>vmstat</em>, ale dla procesów. Jeśli nie podamy konkretnego
+          PID-u, polecenie wyświetli wszystkie procesy, które zostały
+          uruchomione w systemie. Polecenie to nie jest domyślnie dostępne w
+          dystrybucjach opartych na Debianie, jest ono częścią pakietu
+          <em>sysstat</em>, ten pakiet zawiera również polecenie <em>iostat</em>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ pidstat 
+Linux 5.10.0-20-amd64 (immudex)        11.01.2023      _x86_64_        (4 CPU)
+
+17:02:56      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
+...
+17:02:56     1001      2820    4,84    0,99    0,00    0,08    5,83     1  mpv
+17:02:56     1001      2886    0,04    0,01    0,00    0,00    0,05     1  ranger
+17:02:56     1001      3366    0,18    0,04    0,00    0,00    0,21     1  atril
+17:02:56     1001      3398    0,00    0,00    0,00    0,00    0,00     0  WebKitNetworkPr
+17:02:56     1001      3805    0,03    0,01    0,00    0,00    0,04     1  vim.gtk3
+17:02:56     1001      3829    0,00    0,00    0,00    0,00    0,00     2  bash
+17:02:56        0      4176    0,00    0,01    0,00    0,00    0,01     0  kworker/u8:2-kcryptd/254:0
+17:02:56        0      5013    0,00    0,00    0,00    0,00    0,00     0  kworker/u8:3-i915
+17:02:56     1001      5610    0,00    0,00    0,00    0,00    0,00     0  Web Content
+17:02:56     1001     28551    0,00    0,00    0,00    0,00    0,00     2  pidstat
+</pre>
+        <p>
+          Polecenie to w pierwszej linii zwraca nam podsumowanie odnośnie
+          systemu (wersję jądra, nazwę hosta, architekturę procesora oraz
+          ilość rdzeni/wątków) i datę. Następnie wyświetlana jest tabela z
+          procesami, w kolumnach kolejno od lewej znajduje się czas wywołania
+          polecenia; UID użytkownika, który ten proces zainicjował; PID
+               procesu. Następne pięć kolumn pokazuje informacje o zużyciu czasu
+          procesora. Kolumna <code class="code-inline">%wait</code> jest
+          procentowym żużyciem czasu procesora poświęconym na operacje
+          wejścia-wyjścia. Ciekawą wartością, nie zwracaną przez inne polecenia
+          jest kolumna <code class="code-inline">%guest</code>, która
+          przedstawia zużycie procesora na potrzeby zadań wykonywanych przez
+          maszynę wirtualną. Kolejnymi kolumnami są sumaryczne procentowe
+          zużycie czasu procesora; wskazanie, z którego z rdzeni/wątków
+          procesora korzysta ten proces oraz nazwa polecenia.
+        </p>
+        <p>
+          Uruchomienie tego polecenia dla pojedyńczego procesu wymaga podania
+          opcji <strong>-p</strong> wraz z wartością, którą jest PID procesu
+          oraz najlepiej podanie interwału czasowego w postaci suchej liczby
+          po PID-zie.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:/media/xf0r3m/immudex_crypt0$ pidstat -p 2820 2
+Linux 5.10.0-20-amd64 (immudex)        11.01.2023      _x86_64_        (4 CPU)
+
+17:32:37      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
+17:32:39     1001      2820   13,50    5,00    0,00    0,50   18,50     1  mpv
+17:32:41     1001      2820   13,00    3,00    0,00    0,00   16,00     0  mpv
+17:32:43     1001      2820   14,00    4,50    0,00    0,50   18,50     0  mpv
+17:32:45     1001      2820   12,50    4,00    0,00    0,00   16,50     1  mpv
+17:32:47     1001      2820   14,00    4,00    0,00    0,00   18,00     1  mpv
+17:32:49     1001      2820   15,00    2,50    0,00    0,00   17,50     3  mpv
+17:32:51     1001      2820   14,00    2,50    0,00    0,50   16,50     2  mpv
+17:32:53     1001      2820   15,00    3,50    0,00    0,00   18,50     1  mpv
+17:32:55     1001      2820   11,50    5,50    0,00    0,00   17,00     3  mpv
+^C
+Średnia:    1001      2820   13,61    3,83    0,00    0,17   17,44     -  mpv
+</pre>
+        <p>
+          Przerywając działanie polecenia przed jego zakończeniem wyświetli
+          nam o ono jedną dodatkową linię zawierającą średnią poszczególnych
+          wartości uzyskanych podczas działania polecenia.
+        </p>
+        <p>
+          Więcej przydanych opcji dla tego polecenie znajduje się na stronie
+          podręcznika.
+        </p>
+        <h2 id="8.13.extrainfo">8.13. Informacje dodatkowe</h2>
+        <p>
+          Powodem istnienia tak szerokiej gamy różnych narzedzi do 
+          monitowania wydajności jest możliwość użycia, nie których komponentów
+          na różne sposoby. Najprostszym przykładem jaki przychodzi mi teraz
+          na myśl jest wykorzystanie pamięci operacyjnej jako dysku. Inną
+          rzeczą jest, iż te zasobo są ograniczone, a takie systemy jak serwery
+          sieciowe wymagają stałego i intesywnego monitoringu. Dlatego jeśli
+          chcemy lub musimy monitorować systemy, którymi zarządzamy lub
+          będziemy zarządzać warto zapoznać się z poniższymi zagadnieniami.
+        </p>
+        <ul>
+          <li><strong>sar</strong> (raportowanie dotyczące aktywności systemu).
+            Pakiet <em>sar</em> oferuje możliwości monitorowania systemu
+            podobne do programu <em>vmstat</em>, ale również rejestruje on
+            wykorzystanie zasobów w czasie. Przez co możemy sprawdzić jak
+            wyglądało zużycie zasobów podczas wykonywania wcześniejszych zadań.
+          </li>
+          <li><strong>acct</strong> (ewidencja procesów). Ten pakie z kolei
+            zajmuje się ewidencjonowanie procesów, a nie monitorowaniem
+            wydajności, nie mniej jednak funkcja sprawdzenia jakie procesy
+            działały powiedzmy kilka dni temu może być przydatna.</li>
+          <li><strong>Przydziały</strong> przy użyciu przydziałów możemy
+            nałożyć limity wykorzystania podstawowych zasobów (czas procesora,
+            pamięć operacyjna, czy przestrzeń dyskowa). Niestety jest to funkcja
+            systemu <em>PAM</em> więc podlegją im procesy uruchomione w
+            obrębie czegoś co z niego korzysta, na przykład powłoka logowania.
+          </li>
+        <ul>
+        <h1 id="9.network">9. Sieć</h1>
+        <p>
+          Komputery służą do przetwarzania informacji. Informacje 
+          wykorzystywane do obliczeń mogą pochodzić z różnych źródeł a jednym
+          z nich może być inny system komputerowy. Jednak, aby to miało miejsce
+          komputery muszą się w jakiś sposób komunikować ze sobą. W celach
+          w miarę swobodnej komunikacji między systemami, komputery łączy się
+          w sieci. Połączenie ze sobą dwóch komputerów za pomocą jednego kabla
+          również możemy nazwać się siecią, ponieważ mechanizmy oraz
+          komponenty związane z komunikacją pozozstają takie same jak dla
+          większej ilości komputerów. Zagadnienia łączności sieciowej zostały
+          w taki sposób zdefiniowane, aby były niezależne od systemu
+          operacyjnego, ale to systemy definiują narzędzia do ich konfiguracji.
+          W tym rodziale zapoznamy się z konfiguracją sieci w Linuksie.
+        </p>
+        <h2 id="9.1.networkbasics">9.1. Podstawy sieci</h2>
+        <p>
+          Dla łatwiejszego zrozumienia sieci, zaczniemy od zapoznania się z
+          nazewnictwem, niektórych jej elementów. Nasz komputer podłączony do
+          sieci nazywany jest <strong>hostem</strong>. <em>Hosty</em> często są
+          podłączone do sieci lokalnej określanej jako <strong>LAN</strong>.
+          Sieci tego typu są wszechobecne. Tego typu sieci posiadamy w naszych
+          domach, nie przekraczają one swoim obszarem działania
+          jednego budynku lub grupy pomiesczeń. Składają się one z routera
+          łączącego sieć internet z siecią <em>LAN</em> oraz (zazwyczaj) z 
+          podłączonych do niego hostów. Definicja <em>LAN</em>-u nie ogranicza
+          się tylko do hostów podłączonych za pomocą przewodów, łączność może
+          zostać zapewniona tutaj bezprzewodowo nie ma na tym polu żadnych
+          ograniczeń.
+        </p>
+        <p>
+          Poza możliwością podłączenia sieci <em>LAN</em> do internetu routery
+          klasy <strong>SOHO</strong> (<em>Small Office/Home Office</em>)
+          posiadają wiele usług przez co konfiguracja i obsługa <em>hosta</em>
+          w sieci staje się bezobsługowa. Kilka z tych usług omówimy sobie
+          w kontekscie Linuksa w tym rozdziale.
+        </p>
+        <h3 id="9.1.1.packages">9.1.1. Pakiety</h3>
+        <p>
+          Jeśli żądana strona internetowa ma zostać przekazana do chcącego ją
+          obejrzeć użytkownika, musi zostać specjalnie przygotowana do
+          transmisji sieciowej. Takim przygotowaniem zajmują się poszczególne
+          <strong>warstwy stosu TCP/IP</strong>. Dane strony
+          (powiedzmy kod) przechodzi z jednej warstwy do drugiej będąc
+          zamienianym w <strong>pakiety</strong> zrozumiałe dla tych samych 
+          warstw po drugiej
+          stronie transmisji. Dane są przetwarzane przez poszczególne warstwy
+          stosu aż staną się możliwe do przesłania przez
+          fizyczny nośnik w postaci kabla miedzianego, światłowodu lub 
+          fal radiowych. Pakiety składają się najczęsciej z danych z poprzednej
+          warstwy (zwanych <strong>ładunkiem</strong>) oraz dedykowanego tej
+          warstwie nagłówka. Przetwarzanie danych przez stos <em>TCP/IP</em>
+          nazwywane jest <strong>enkapsulacją</strong> Dwie warstwy stosu 
+          zostaną opisane w tym rodziale.
+          Warstwą najwyższą zajmiemy się następnym rodziale. Natomiast warstwę
+          najniższą omówimy sobie w dużym uogólnieniu.
+        </p>
+        <h3 id="9.1.2.tcpstack">9.1.2. Stos TCP/IP</h3>
+        <p>
+          W stosie <em>TCP/IP</em> możemy wyróżnić cztery różne warstwy:
+        </p>
+        <ol reversed>
+          <li><strong>Warstwa aplikacji</strong> - określa sposób komunikacji
+            między aplikacjami. Wewnątrz tej warstwy rezydują protokoły
+            aplikacji wykorzystywane przez użytkowników takiej np. HTTP.</li>
+          <li><strong>Warstwa transportowa</strong> - określa sposób transmisji
+            danych z warstwy aplikacji. W tej warstwie znajdują się protokoły
+            takie jak TCP oraz UDP. Tutaj także rezyduje pojęcie 
+            <strong>portu</strong>. Warstwa transportowa będzie jeszcze
+            omawiana w tym materiale.</li>
+          <li><strong>Warstwa internetowa</strong> - określa sposób
+            dostarczania pakietów z hostów źródłowych do docelowych i
+            odwrotnie. W tej warstwie rezyduje protokół IP oraz protokoły
+            odpowiedzialne za trasowanie (znalezienie jak najlepszej drogi z
+            jednego do drugiego hosta). W tej warstwie znajduje się również
+            protokół ICMP odpowiedzialny z diagnozowanie problemów z protokołem
+            IP.</li>
+          <li><strong>Warstwa łącza</strong> - ta warstwa definuje topologię
+            logiczną sieci. Okresla ona metody transmisji danych przez użyty
+            w sieci nośnik fizyczny. W tej warstwie znajdują się takie
+            protokoły jak Ethernet oraz standard 802.11, definiujący
+            transmisję bezprzewodową.</li>
+        </ol>
+        <p>
+          Warto wspomnieć o tym, że w dystrybucjach Linuksa trzy z czterch 
+          warstw znajdują się w jądrze systemu.  Mogą jednak pojawić się
+          wyjątki, wówczas pakiet może trafic do przetworzenia w przestrzeni
+          użytkownika.
+        </p>
+        <h2 id="9.2.networklayer">9.2. Warstwa sieciowa</h2>
+        <p>
+          Jak wiemy warstwa sieciowa definiuje sposoby dostarczenia pakietów
+          z jednego do drugiego hosta. Ze względu na to, iż będziemy zajmować
+          się sieciami internetowymi, skupimy się na jednym protokole tej
+          warstwy na - protokole <strong>IP</strong>. Ten protokół posiada
+          kilka funkcji, jednak dla nas na tym etapie najważniejsza będzie 
+          jedna z nich - <strong>adresacja</strong>. Każdy host aby mógł
+          komunikować się w sieci musi mieć przypisany taki adres. Adres ten
+          składa się (a przynajmniej w wersji 4 protokołu IP) z czterech grup 
+          liczb z
+          zakresu od 0 do 255 rozdzielonych kropkami. Na przykład adres IP
+          mojego komputera to:
+        </p>
+<pre class="code-block">
+192.168.8.101
+</pre>
+        <p>
+          Uzyskałem te informacje za pomocą poniższych poleceń. Te polecenia
+          są tożsame:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ip address show
+#lub
+xf0r3m@immudex:~$ ip a
+</pre>
+        <p>
+          Drugi zapis jest skrótem pierwszego polecenia. Analizując wynik
+          działania tego polecenia musimy zwrócić uwagę na dwie rzeczy.
+          Pierwszą z nich są "dziwne" nazwy intefejsów sieciowych. Jeśli nikt
+          nie korzystał z dystrybucji Linuksa przed 2016 rokiem to wówczas
+          nie mógł spotkać się z klasycznymi nazwami interfejsów sieciowych. 
+          To jest pierwszy interfejs przewodowy = <em>eth0</em> i tak dalej
+          do <em>ethX</em>. Miało to jedną podstawową wadę znaną już z
+          dysków. Otóż po którymś uruchomieniu ponownym system mógł wykryć
+          karty sieciowe w innej kolejności niż poprzednio co powodowało
+          problemy ze <strong>statyczną</strong> (zapisana na stałe w systemie)
+          konfiguracją sieciową, ponieważ adresy niezgadzały się z adresacją
+          podpiętej sieci. Obecnie ich nazwy są zaczerpnięte z modułów jądra,
+          które są wykorzystywane do ich obsługi. Nie wszystkie dystrybucje 
+          stosują
+          nową nomenklaturę dla interfejsów sieciowych. W dużej mierze są to
+          systemy korzystające z innych programów typu <em>init</em> niż
+          <em>systemd</em>, choć co prawda nie jest to regułą.
+        </p>
+        <h3 id="9.2.1.ipaddresses">9.2.1. Adresacja IP</h3>
+        <p>
+          Inną rzeczą jest sposób prezentowania adresów IP. W linii
+          rozpoczynającej się od słowa <code class="code-inline">inet</code>
+          znajduje się adres IP przedstawioy w ten sposób 
+          <code class="code-inline">192.168.8.101/24</code>. Jest to zapis w
+          notacji <strong>CIDR</strong>. Na zapis ten składa się adres IP
+          oraz <strong>maska podsieci</strong> w postacji ilości bitów. 
+        </p>
+        <p>
+          Maska podsieci jest rodzajem adresu IP, który określa gdzie i jakie
+          liczby z zakresu możemy wpisać do adresów IP hostów. Wyzanczając tym
+          samym pierwszy oraz ostatni adres w sieci (początek i koniec sieci),
+          na podstawie maski możemy określić ilość hostów w sieci.
+          W jaki sposób się to dzieje? Otóż adres IP jak i maskę możemy
+          przedstawić w postaci binarnej. W na poprzedni przykładzie maska 
+          wynosiła 24 bity. Co to oznacza? Aby sobie to wyjaśnić przedstawimy
+          adres IP w postaci binarnej.
+        </p>
+<pre class="code-block">
+192.168.8.101 = 11000000.10101000.00001000.01100101
+</pre>
+        <p>
+          Z adresem poszło w miarę łatwo, ponieważ znaliśmy konkretne liczby.
+          Jeśli policzymy wszystkie cyferki w postaci binarnej otrzymam wynik
+          32 cyfr, z racji tego że są to wartości binarne bardziej mówimy o
+          bitach - podstawowej jednostce informacji, klasycznemu 0 oraz 1.
+          Adresy IP w wersji 4 (można zapisać to skrótowo IPv4) mają długość
+          32-bitów. Powyżej omawiając maskę podsieci zostało wspomniane, że
+          maska wyznacza początek oraz koniec sieci. Adres IP możemy przyrównać
+          do adresów pocztowych, kolejne jego części mogą wskazywać na miasto,
+          ulicę, budynek oraz na mieszkanie. Adresy pocztowe zawierają
+          zazwyczaj stałe elementy jak nazwy miast, ulic czy numerację budynków.
+          Tak samo jest w przypadku adresów IP. Te stałe elementy wydzielane są
+          maskę podsieci. Mając maskę w postaci ilości bitów z notacji CIDR,
+          możemy zapisać ją w ten sposób.
+        </p>
+<pre class="code-block">
+/24 = 11111111.11111111.11111111.00000000
+/24 = 255.255.255.0
+</pre>
+        <p>
+          Więc zapis maski w notacji CIDR, to nic innego jak ilość bitów o
+          wartości <strong>jeden</strong> (1) zapisanych od lewej w 
+          reprezentacji binarnej adresu
+          IP. No dobrze, ale 32 - 24 = 8. Co zrobić z tymi 8 bitami? Otóż te
+          bity pozostają do dyspozycji administratora i stanowią przestrzeń
+          adresową. Maskę podsieci można podzieli na dwie częsci. Jedną częścią
+          jest część sieciowa, która wyznacza stałą część adresu IP w adresacji
+          hostów w sieci i ta część adresu IP jest niezmienna podczas adresacji.
+          Drugą częścią jest część hosta, wskazująca, która część adresu IP
+          będzie zawierać konkretną wartość wskazującą na hosta w sieci. Teraz
+          złożymy ze sobą adres IP oraz maskę zapisaną w postaci dziesiętnej
+          (<code class="code-inline">255.255.255.0</code>).
+        </p> 
+<pre class="code-block">
+Adres IP: 192.168.8.101
+Maska:    255.255.255.0
+</pre>
+        <p>
+          Poszczególne części adresu IP odzielone kropkami noszą nazwe
+          <strong>oktetów</strong>, ponieważ w reprezentacji binarnej każda
+          z częsci posiada 8 bitów. Zatem przyglądając się powyższemu
+          przykładowi możemy dojść do wniosku, że czwarty ostatni oktet będzie
+          przeznaczony na częśc hostów, i tylko on będzie się zmieniać
+          podczas adresacji kolejnych hostów w tej sieci.
+        </p>
+        <p>
+          Warto zaznaczyć że przy prostych sieciach, maski mogą pozostać
+          typowe tj. 24, 12 oraz 8 bit. Gdzie niegdzie spotykałem się
+          również z maską 16 bitową. Dającą dwa oktety na część przeznaczną
+          dla hostów. W przypadku 12-bitowej maski, nie ma już takiego
+          eleganckiego podziału. Część bitów z drugiego oktetu pozostanie w
+          części sieciowej, a druga część przejdzie do części hosta. Rozpiszmy
+          sobie ten przykład. Załóżmy że nasz komputer jest podłączony do
+          sieci 172.16.X.Y/12 i chcielibyśmy dowiedzieć się jak duża jest 
+          ta podsieć. Za stałą możemy przyjąć, że jeśli na konkretnym oktecie
+          maski występuje 0, to ten sam oktet adresu IP może przyjąć wartości
+          od 0 do 255.
+        </p>
+<pre class="code-block">
+172.16.0.0/12
+10101100.00010000.00000000.00000000 = 172.16.0.0
+11111111.11110000.00000000.00000000 = /12 = 255.240.0.0
+#Część bazowa adresu IP po usunięciu wszystkich bitów z zermi na masce:
+10101100.0001
+
+10101100.00010000.00000000.00000000 = 172.16.0.0
+1.           0000                   = 172.16
+2.           0001                   = 172.17
+3.           0010                   = 172.18
+4.           0011                   = 172.19
+5.           0100                   = 172.20
+6.           0101                   = 172.21
+7.           0110                   = 172.22
+8.           0111                   = 172.23
+9.           1000                   = 172.24
+10.          1001                   = 172.25
+11.          1010                   = 172.26
+12.          1011                   = 172.27
+13.          1100                   = 172.28
+14.          1101                   = 172.29
+15.          1110                   = 172.30
+16.          1111                   = 172.31
+10101100.00011111.00000000.00000000 = 172.31.0.0
+(16 x 256 ^ 2) - 2 = 1048574
+</pre>
+        <p>
+          Myślę że powyższy przykład jasno przedstawia jak wygląda podział
+          klasowych sieci. A co jeśli będziemy chcieli
+          rozszerzyć sieci 192.168.8.0/24? Jeśli założym, że potrzebowalibyśmy
+          kolejne 255 adresów to wówczas wystarczy zabrać z maski 1 bit. Da to
+          maskę 23-bitową a my swojej sieci będziemy mogli zaadresować hosty od
+          192.168.8.1 - 192.168.9.254.
+        </p>
+        <p>
+          Każdy komputer posiadający skonfigurowaną w ten sposób warstwę
+          internetową/sieciową może komunikować się z hostami w sieci.
+          Konfigurowanie warsty sieciowej, jest chyba jedyną czynnością, w
+          w której użytkownik będzie mieć styczność z stosem TCP/IP. Jednak
+          aby móc skomunikować się za pośrednictwem routera z internetem
+          potrzebujemy jeszcze kilku informacji.
+        </p>
+        <h3 id="9.2.2.routingtable">9.2.2. Routowanie oraz tabela routingu</h3>
+        <p>
+          Każdy funkcjonujący w sieci system musi posiadać źródło informacji na
+          temat gdzie należy przesłać pakiety lub jakiego interfejsu do tego
+          celu należy użyć. Czynność ustalenia optymalnej trasy dla pakietu
+          nazywa się <strong>routowaniem</strong>, natomiast informacje na
+          temat jakie sieci są osiągalne i przez jakie interfejsy znajduje się
+          w <strong>tabeli routingu</strong>. W systemie, który nie jest
+          jakmiś routerem, tabela routingu będzie zawierać prawdopodobnie
+          tylko dwa wpisy. Na poniższym przykładzie widnieje zrzut tabeli
+          routingu z mojego komputera.
+        </p>
+<pre class="code-block">
+default via 192.168.8.1 dev enp0s31f6 onlink
+192.168.8.0/24 dev enp0s31f6 proto kernel scope link src 192.168.8.154
+</pre>
+        <p>
+          Pierwsza linia zawiera definicję <strong>bramy domyślnej</strong>,
+          którą zajmiemy się za chwilę. Natomiast druga linia wskazuje jaka
+          sieć jest osiągalna przez jaki interfejs w tym przypadku sieć
+          <code class="code-inline">192.168.8.0/24</code> jest dostępną przez
+          interfejs <code class="code-inline">enp0s31f6</code>. 
+        </p>
+        <p>
+          W systemach, które łączą ze sobą sieci (routerach) wpisów
+          w tabeli <em>routingu</em> takich jak druga linia może być znacznie
+          więcej. Możemym sobie wówczas zadać pytanie na jakiej podstawie
+          jądro wybiera właściwy port. Otóż jądro przy wyborze będzie bazować
+          na dwóch czynnikach. Pierwszy z nich jest oczywisty i chodzi tu
+          adres częsci sieciowej adresu IP, musi on pasować do adresu sieci
+          inaczej ma się rzecz jeśli jedna z sieci jest na tyle duża, że
+          obejmuje swoim zakresem także adresacje innej sieci. Tutaj wówczas
+          pojawia się drugi czynnik, którym jest długość maski/części sieciowe.
+          Czasami nazywanej także <strong>prefiksem</strong>. Jeśli przy
+          którymś z wpisów adresy sieci zachodzą na siebie, to wówczas dłuższy
+          prefiks (a co za tym idzie, mniejsza sieć) jest wybierana jako
+          trasa dla pakietu.
+        </p>
+        <h3 id="9.2.3.defaultgateway">9.2.3. Brama domyślna</h3>
+        <p>
+          Omawiając tablę <em>routingu</em> wspomnieliśmy o bramie domyślnej.
+          Brama domyślna jest rodzajem wpisu we wspomnianej tabeli a jej
+          zadaniem jest przechowywanie domyślniej trasy, która wybierana jest
+          jeśli żadna inna nie jest odpowiednia. Wynika to z faktu jak jądro
+          wybiera właściwe dla pakietów trasy oraz adresu jaki kryje się za 
+          słowem <code class="code-inline">default</code>  a jest nim
+          <strong>0.0.0.0/0</strong>. Oznacza on wszystkie hosty w adresacji
+          IPv4. Co daje najmniejszy możliwy prefiks, dlatego też jeśli komputer
+          nie posiada właściwej dla pakietu trasy to jest ona przekzywana
+          do adresu przez który taka sieć jest osiągalna.
+        </p>
+        <p>
+          Tym adresem jest przeważnie adres <em>routera</em>, który łączy 
+          sieć LAN z inną siecią np. siecią usługodawcy internetowego.
+          Zwyczajowo takie urządzenia zwykło się nazywać <em>routerami</em>,
+          mimo ich możliwość to najczęściej wykorzystywaną funkcjonalnością
+          jest automatyczna konfiguracja hostów (protokół DHCP, będzie o nim
+          w tym rozdziale), pamięć podręczna i przekazywanie zapytań systemu
+          DNS (o systemie DNS, też będzie tutaj) oraz translacja adresów
+          (o adresach prywatnych oraz translacji adresów też sobie wspomnimy)
+          oraz przekazywanie pakietów dalej do jednego z routerów usługodawcy,
+          więc równie dobrze urządzenia tego typu można nazwać bramkami.
+        </p>
+        <h2 id="9.3.ipv6">9.3. Adres IPv6</h2>
+        <p>
+          Adres IPv4 posiada długość 32 bitów, co daje nam możliwość
+          zaadresowania 4,3 miliarda hostów w Internecie. Co jest o wiele
+          mniejszym wynikem niż ilość ludzi na świecie, biorąc pod uwagę
+          rozwój przedsiębiorstw oraz samego internetu wymaga od organizacji
+          czuwających nad jego standaryzacją rozwiązań, które są w stanie
+          sprostać wymaganiom czasów obecnych oraz przyszłości. Jedym z takich
+          rozwiązań są prace na rozwojem oraz wdrożeniem nowego standardu
+          jakim <strong>protokół IP w wersji 6</strong>.
+        </p>
+        <p>
+          Adres IP w wersji 6, ma długość 128-bitów, co czyni go 4 razy
+          dłuższym od adresu IPv4. Adres ten nie przypomina adresu z
+          poprzedniej wersji. Zamiast cyfr dziesiętnych użytko cyfr systemu 
+          heksadecymalnego, a kropki zastąponio dwukropkami. Poniżej znajduje
+          się adres IPv6 komputera na którym pisze ten tekst.
+        </p>
+<pre class="code-block">
+fe80::921b:eff:fe6a:717d/64
+</pre>
+        <p>
+          Cyfry heksadecymalne są reprezentowane przez znaki: 0-9 oraz a-f.
+          Każda grupa cyfr jest odzielona dwukropkiem, a każda z nich posiada
+          po 4 znaki. Jeśli zero jest napoczątku grupy, to można je pominąć,
+          jeszcze inną zależność jak możemy zauważyć jest to, jeśli grupa
+          składa się z samych zero to można ją pominąć, wówczas w zapisie
+          adresu widnieją dwa dwukropki obok siebie. Nie tyczy się to tylko
+          jednej grupy, ale jeśli grupy zer następują po sobie to rownież
+          można je pomniąć. Zapis natomiast nie ulegnie zmianie, jesli będzie
+          więcej niż jedna grupa zer do pominięcia.
+        </p>
+        <p>
+          Jak możemy zauważyć adresy IPv6 również możemy zapisać w notacji
+          CIDR. Tutaj maska wynosi 64-bit, co oznacza ze połowa adresu zajmuje
+          prefiks. Natomiast druga połowa jest już częścią hosta.
+        </p>
+        <p>
+          Adresy IPv6 możemym podzielić na globalne, która mogą być osiągalne
+          z internetu lub lokalne, które są przypisywane automatycznie przez
+          systemy z obsługą IPv6. Każdy z tych typów posiada swój prefix i dla
+          adresów globalnych (znanych także jako globalny adres hosta) prefix 
+          wynosi <em>2000::/3</em>, przez co globalny adres hosta zaczyna się
+          od 2 lub od 3 (ze zwględu na prefix, 3 pierwsze bity pierwszej cyfry
+          są stałe (001), a zatem do dyspozycji mamym tylko jeden bit, którego
+          zmiana nie dam nam innych wartości jak 2 lub 3). Pozostałe zera służa
+          jako dopełnienie do zapisu. Z kolei prefiksem dla adresów lokalnych
+          jest <em>fe80::/10</em>. W przypadku adresu łącza lokalnego resztę
+          częsci sieciowej adresu wypełniają 54-bity zer. Na podstawie
+          przedstawionych tutaj prefiksów możemy ustalić z jakiego rodzaju
+          adresem mamy doczynienia.
+        </p>
+        <h3 id="9.3.1.showipv6">9.3.1. Wyświetletnie adresów IPv6</h3>
+        <p>
+          Do wyświetlenia adresów IPv6 może posłużyć nam to samo polecenie,
+          z którego korzystaliśmy do wyświetlenia adres IP w wersji 4.
+          Mianowicie polecenie <code class="code-inline">ip</code>, po za
+          samymi podpoleceniami tego polecenia dla adresów IPv6 podaje się
+          także opcję <strong>-6</strong>.
+        </p>
+<pre class="code-block">
+$ ip -6 addr show
+</pre>
+        <p>
+          Podobnie rzecz ma się adresami IP tras, tutaj wykorzystuje się
+          tę samą opcją natomiast inne podpolecenia.
+        </p>
+<pre class="code-block">
+$ ip -6 route show
+</pre>
+        <h2 id="9.4.basictoolkiticmpanddns">9.4. Podstawowe narzędzia ICMP oraz DNS</h2>
+        <p>
+          W tym podrozdziale omówimy sobie podstawowe narzędzia wykorzystywane
+          przy połączeniach sieciowych. Służą one do ustalania
+          adresów IP oraz sprawdzania dostępności hosta.
+        </p>
+        <h3 id="9.4.1.ping">9.4.1. Narzędzie ping</h3>
+        <p>
+          Protokół ICMP jest protokołem diagostycznym dla protokołu IP. Do jego
+          podstawowych zadań należy sprawdzenie dostępności hosta w sieci. Do
+          tego celu wykorzystujemy narzędzie <strong>ping</strong>. To
+          niepozorne narzędzie wysyła specjalny pakiet z żądaniem odesłania
+          pakietu z odpowiedzią. W przypadku tego narzędzia istotna jest
+          sama odpowiedź ale poza nią zwracanych jest kilka statystyk, które
+          pozwolają na przykład na określenie jakość połączenia oraz czasem
+          stanu samej sieci (gdy odpowiedzi z bramy domyślnej przychodzą po
+          ok. 1 sekundzie).
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ping wp.pl
+PING wp.pl (212.77.98.9) 56(84) bytes of data.
+64 bytes from www.wp.pl (212.77.98.9): icmp_seq=1 ttl=54 time=11.2 ms
+64 bytes from www.wp.pl (212.77.98.9): icmp_seq=2 ttl=54 time=11.0 ms
+64 bytes from www.wp.pl (212.77.98.9): icmp_seq=3 ttl=54 time=14.1 ms
+^C
+--- wp.pl ping statistics ---
+3 packets transmitted, 3 received, 0% packet loss, time 2001ms
+rtt min/avg/max/mdev = 11.049/12.096/14.062/1.391 ms
+</pre>
+        <p>
+          Na 56-bajtowe żądanie <em>echa</em> wysłane z naszego komputera
+          host docelowy odpowiada 64-bajtowym pakietem. Jego zawartość nie
+          jest istotna. Dla nas ważne są pola 
+          <code class="code-inline">icmp_seq<code> oraz
+          <code class="code-inline">time</code>, gdyż swiadczą on one jakości
+          połączenia pomiędzy naszym komputerem, a hostem docelowym. 
+          <code class="code-inline">icmp_seq</code> wskazuje kolejności
+          otrzymywanych odpowiedzi. Jeśli jakiegoś pakietu brakuje, oznacza to
+          że został on zgubiony podczas transmisji. Zagubione pakiety
+          zdarzają się gdy korzystamy z połączenia bezprzewodowego przy słabym
+          zasięgu. Drugim ważnym polem jest czas wyrażony w kolumnie
+          <code class="code-inline">time</code>. Czas poniżej 30 ms oznacza
+          że mamy bardzo dobre połącznie z hostem. Czas w sieci lokalnej
+          oscyluje poniżej 1 ms. Natomiast jeśli jest powyżej jednej sekundy
+          (1000 ms) lub w jej granicach oznacza, że gdzieś w sieci może
+          znajdować się problem. Polecenie <em>ping</em> w dystrybucjach
+          Linuksa ale i ogólnie w implementacji Uniksowej działa do momentu,
+          aż nie przerwiemy mu działania. Na sam koniec zostanie wyświetlona
+          statystyka zawierająca informacje o tym ile pakietów zostało
+          wysłanych ile zostało odebranych, jaki procent pakietów został
+          utracony. W drugiej linii podsumowania znajduje się podstawowe
+          statystki związane z odpowiedzia na żądania.
+        </p>
+        <p>
+          Ze względów bezpieczeństwa nie wszystkie hosty (z właszcza w
+          internecie są w stanie odpowiedzieć na żądania narzędzia 
+          <em>ping</em>. Pakiety mogą zostać do nich wysłane, ale jest wielce
+          prawdopodobne, że zostaną zablokowane po drodze. Takie zachowanie
+          jest przecidziałaniem przeciwko atakowi odmowy usługi, który opiera
+          się na przesłaniu wielu żądań (<em>echo request</em>, typ pakietu
+          nazywa się właśnie w ten sposób), tak aby host nie był w stanie
+          obsłużyć żadnego innego połączenia sieciowego.
+        </p>
+        <p>
+          Istnieje możliwość wykorzystania pakietów <em>echo request</em> 
+          zarówno z protokołu <em>IPv4</em> oraz <em>IPv6</em>. Wówczas należy
+          wskazać to za pomocą opcji <em>-4</em> lub <em>-6</em> w poleceniu
+          <em>ping</em>.
+        </p>
+        <h3 id="9.4.3.host">9.4.3. Narzędzie host</h3>
+        <p>
+          Narzędzie <strong>host</strong> jest najprostszym sposobem na
+          skorzystanie z systemu DNS. 
+        </p>
+        <p>
+          System DNS pozwala on zapamiętać ludziom typowy adres strony, bez
+          potrzeby znajomości jej adresu IP, aby zrealizować to połączenie.
+          Jeśli wpiszemy adres strony do przeglądarki, zapyta ona system DNS o
+          jej adres IP i ten udzieli jej takiej odpowiedzi. Oczywiście w
+          skrócie rzecz ujmując. Czasami możemy znaleźć się w odwrotnej
+          sytuacji, kiedy będziemy znać adres IP, a chcielibyśmy się
+          dowiedzieć do jakiej organizacji jest on przypisany. Jednak ta
+          funkcjonalność nie jest kluczowa i rzadko bywa dobrze skonfigurowana,
+          nie mniej jednak warto spróbować. 
+        </p>
+        <p>
+          Aby skorzystać z narzędzia <em>host</em>, podajemy nazwę lub adres
+          IP jako argument polecenia.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ host morketsmerke.org
+morketsmerke.org has address 213.186.33.5
+morketsmerke.org mail is handled by 10 mx3.mail.ovh.net.
+morketsmerke.org mail is handled by 1 mx4.mail.ovh.net.
+
+xf0r3m@immudex:~$ host 93.184.216.34
+Host 34.216.184.93.in-addr.arpa. not found: 3(NXDOMAIN)
+
+xf0r3m@immudex:~$ host 213.186.33.5
+5.33.186.213.in-addr.arpa domain name pointer redirect.ovh.net.
+</pre>
+        <p>
+          Na powyższym przykładzie widzimy trzy wywołania polecenia
+          <code class="code-inline">host</code> jedno z nich klasyczne
+          pytające o adres IP i dwa pytające o nazwę domenową, zwróćmy uwagę
+          na to w jaki sposób zostały zapisane adresy IP. Nie będę tutaj
+          przytaczać więcej informacji o sposobie działania systemu DNS, gdyż
+          wykraczają one poza ramy tego materiału. Do systemu DNS wrócimy 
+          podczas konfiguracji interfejsu hosta.
+        </p>
+        <h2 id="9.5.ethernet">9.5. Warstwa fizyczna</h2>
+        <p>
+          Wiemy, że sieć internetowa oparta jest o oprogramowanie. Nie miej
+          jednak gdzieś zagadnienia sieciowe muszą stykać się ze swiatem
+          realnym, z tym że komputery koniec, końców są ze sobą połączone
+          za pomocą specjalnych przewodów oraz z lub bez pośrednictwa
+          dodatkowych urządzeń. Tymi elementami zajmuje się warstwa
+          fizyczna. Standardów implementacji warstwy fizycznej (tego w jaki
+          sposób informacje przesyłane są przez media (przewody lub fale
+          radiowe)) jest wiele, jednak wykorzystywaną po dzień dzisiejszy oraz
+          najpowszechniejszą z nich jest <strong>Ethernet</strong>. Sprzęt
+          sieciowy, mimo tej samej implementacji będzie różnić się od siebie
+          ze względu na użyte medium transmisji, ale mają one wiele cech
+          wspólnych. Oto kilka z nich:
+        </p>
+        <ul>
+          <li>Element identyfikującym w sieciach <em>Ethernet</em> jest 
+            adres sprzetowy znany także jako adres <strong>MAC</strong>. Adresy
+            MAC są niezależne od adresów progrmowych i aby transmisja w sieci
+            <em>Ethernet</em> doszła do skutku to musi on być unikatowy w
+            obrębie sieci lokalnej (i zazwyczaj tak jest, w sieci lokalnej,
+            jednak w sieciach rozległych, już może tak nie być. Obecnie
+            <em>losowy</em> MAC adres interfejsu sieciowego może być stosowany
+            aby podnieść poziom prywatności w sieciah publicznych
+                 (ogólnodostępne sieci bezprzewodowe)). Adres sprzętowy składa się
+            z 6 grup po 2 cyfry systemu heksadecymalnego oddzielonego
+            dwukropkami. Całość ma łącznie 48-bitów.</li>
+          <li>W sieciach Ethernet dane wysłane są w ramkach. Ramki są 
+            opatrzone adresami MAC hostów biorących udział w wymianie
+            danych</li>
+        </ul>
+        <p>
+          Host mając nawet dwa interfejsy sieciowe podłączone do różnych
+          sieci <em>Ethernet</em> nie może przekazać pakietu z jednej do
+          drugiej sieci, chyba skonfigurowano na nim most. Więc jeśli dane
+          mają zostać wysłane do internetu, potrzebny jest udział warstw
+          wyższych, albowiem każda sieć fizyczna jest podsiecią sieci
+          warstwy wyższej, zatem router może odebrać ramkę, wyodrębnić jej
+          dane a następnie przepakować do nowej ramki i wysłać dalej
+          w świat.
+        </p>
+        <h2 id="9.6.kernelnetworkinterfaces">9.6. Sieciowe interfejsy jądra</h2>
+        <p>
+          Jądro samodzielnie odróżnia warstwę fizyczną od sieciowej, przez co
+          musi zapewniać im standard w komunikacji. Czymś takim właśnie jest
+          <strong>interfejs sieciowy</strong>. W trakcie jego konfiguracji
+          przypisane parametry warstwy internetowej są łączone z parametrami
+          urządzenia. Nazwy interfejsów opierają się o rodzaj sprzętu na którym
+          bazują. Np. <em>enp0s4</em>, oznacza zazwyczaj kartę sieciową
+          podłączoną do magistrali PCI. Nazwy tego typu są określane
+          nazwami przewidywalnymi i nie zmieniają się one ponownym uruchomieniu
+          systemu. Jest to jednak prowadzone głównie program typu <em>init</em>
+          - <em>systemd</em>. Aby wyświetlić interfejsy wydajemy polecenie:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ip a
+1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+2: enp4s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc mq state UP group default qlen 1000
+    link/ether 90:1b:0e:6a:71:7d brd ff:ff:ff:ff:ff:ff
+    inet 172.16.1.2/16 brd 172.16.255.255 scope global enp4s0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::921b:eff:fe6a:717d/64 scope link
+       valid_lft forever preferred_lft forever
+3: enp0s25: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
+    link/ether 90:1b:0e:87:3c:43 brd ff:ff:ff:ff:ff:ff
+</pre>
+      <p>
+        Polecenie <code class="code-inline">ip a</code>, jest poleceniem
+        skrótowym dla polecenia <em>ip address show</em>.
+        Interfejsy sieciowe są numerowane kolejno do numeru 2, numer 1
+        zarezerowany jest dla specjalnego interfejsu systemowego - zwanego
+        pętlą zwrotną. Każdy działający interfejs w linii z numerem oraz
+        nazwą posiada flagę <code class="code-inline">UP</code>. Poza
+        informacjami warstwy sieciowej możmy również zauważyć informacje z
+        warstwy fizycznej takie jak adres MAC. Polecenie
+        <code class="code-inline">ip a</code>, głównie skupia się na warstwie
+        sieciowej. Jeśli chcielibyś poznać więcej szczegółów związanych z
+        warstwą fizyczną, wówczas należało by użyć polecenia takiego jak
+        <strong>ethtool</strong>.
+      </p>
+      <h2 id="9.7.interfaceconfig">9.7. Konfiguracja interfejsu sieciowego</h2>
+      <p>
+        Do tej pory omawialiśmy kwestie sieciowe wyłącznie teoretycznie, a to
+        przeanalizowaliśmy sobie wynik jednego czy drugiego polecenia, ale
+        teraz zajmiemy konfiguracją interfejsu sieciowego. Aby użytkownik
+        dowolnej dystrybucji mógł połączyć się z internetem musimy wykonać
+        cztery poniższe czynności:
+      </p>
+      <ol>
+        <li>Zapewnienie obecności sterownika karty sieciowej w jądrze. Jeśli
+          sterownika będzie brakować, to nawet nieskonfigurowany interfejs
+          nie zostanie wyświetlony po wydaniu polecenia <em>ip a</em>.</li>
+        <li>Dodatkowa konfiguracja warstwy fizycznej, na przykład poprzez
+          podanie nazwy sieci oraz hasła (głównie sieci bezprzewodowe).</li>
+        <li>Ustawienie dla interfejsu adresu IP oraz maski podsieci (dzięki
+          temu warstwy będą mogły się ze sobą komunikować).</li>
+        <li>Ustawienie wszystkich wymaganych tras w tym trasy domyślnej.</li>
+      </ol>
+      <p>
+        Wiedząc teraz co musimy zrobić. Przejdziemy do wykonania tych
+        czynności w systemie.
+      </p>
+      <h3 id="9.7.1.manualifconf">9.7.1. Ręczna konfiguracja interfejsu</h3>
+      <p>
+        Reczna konfiguracja interfejsów sieciowych rzadko jest wymagana, chyba
+        eksperymentujemy z systemem lub próbujemy skonfigurować urządzenie,
+        które samo nam interfejsu nie skonfiguruje. Nie mniej jednak, a
+        własnego doświadczenia wiem, że warto posiadać taką wiedzę. Więc tak
+        załóżmy, że posiadamy sterowniki do karty sieciowej (interfejsu), którą
+        chcemy skonfigurować oraz łączymy się z siecią <em>Ethernet</em> za 
+        pomocą kabla miedzianego, dlatego też punkt nr. 2 też możemy pominąć.
+        Jeśli tak rzeczywiście jest to wówczas konfiguracja interfejsu 
+        sprowadza się do dwóch poleceń.
+      </p>
+      <p>
+        Aby skonfigurować ręcznie interfejs musimy musimy użyć polecenia
+        <strong>ip</strong> wraz z podpoleceniem <strong>address</strong> lub
+        <em>addr</em>, następnie podać komendę <em>add</em> po niej adres IP
+        wraz z maską w notacji CIDR do tego opcję <em>dev</em> po której
+        należy wskazać nazwę interfejsu jaki chcemy skonfigurować.
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo ip address add 172.16.1.1/16 dev enp4s0
+</pre>
+      <p>
+        Wykorzystując powyższe polecenie mamy pierwszą część za sobą.
+        Pamiętajmy jednak aby zmienić dane.
+      </p>
+      <p>
+        Drugą czynnością jest dodanie tras. Do połączenia z internetem
+        potrzebna będzie na pewno brama domyślna. Jeśli będziemy potrzebować
+        dodatkowych tras wystarczy zmodyfikować poniższe polecenie: 
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo ip route add default via 172.16.0.1 dev enp4s0
+</pre>
+      <p>
+        Za trasy odpowiada podpolecenie <code class="code-inline">route</code>,
+        komenda <code class="code-inline">add</code> odpowiada za dodawanie
+        tras. Następnie podawana jest sieć jaka ma być osiągalna. Po opcji
+        <code class="code-inline">via</code> podawny jest adres IP na jaki
+        mają być kierowane pakiety do docelowej sieci, tym adresem może być
+        adres routera sieci lokalnej lub nawet jeden z interfejsów
+        zainstalowanych na tym samym komputerze, na koniec po opcji
+        <code class="code-inline">dev</code> podajemy interfejs, przez który
+        adres IP podany po opcji <code class="code-inline">via</code> jest
+        osiągalny.
+      </p>
+      <p>
+        Jeśli trasa jest nam nie potrzebna lub pomyliliśmy się podczas jej
+        dodawnia, to taką trasę bez obaw można usunać, przy użyciu komendy
+        <em>del</em> podpolecenia <em>route</em>. Komenda przyjmuje adres
+        sieci jako argument.
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo ip route del 192.168.60.0/24
+</pre>
+      <h3 id="9.8.networkifacebootconfig">9.8. Konfiguracja interfejsów sieciowych podczas rozruchu</h3>
+      <p>
+        Próba konfiguracji interfejsu podczas rozruchu mogła by wyglądać w 
+        taki sposób, że gdzieś podczas sekwencji rozruchowej program typu
+        <em>init</em> (lub jeden z jego skryptów) mógłby wydać polecenia
+        <em>ip</em> (takie jak te, które wkorzystywaliśmy do ręcznej 
+        konfiguracji) lub
+        innego narzędzia. Pytanie tylko jakiego? A odpowiedzi tyle co
+        wiodących dystrybucji.
+      </p>
+      <p>
+        Do tej pory próbowano ustandaryzować ten proces za pomocą poleceń
+        <em>ifup</em> oraz <em>ifdown</em>. Z niezbyt zadawalającym skutkiem
+        ze względu na różne implementacje tych narzędzi przez osoby
+        zajmujące się rozwojem dystrybucji, czego następstwem są różnice w
+        plikach konfiguracyjnych. Kolejną problematyczną rzeczą jest fakt
+        iż wiele elementów sieciowych wykorzystywanych do konfiguracji
+        znajduje się różnych miescach w systemie i odpowiadają za nie inne
+        komponenty. W Linuksie panuje również zasada aby nie rozpowszechniać
+        plików konfiguracyjnych w przypadku wielu osobnych narzędzi czy
+        bibliotek, ponieważ zmiany wprowadzone w jednym narzędziu mogą
+        spowodować, że inne przestaną działać.
+      </p>
+      <p>
+        Więc tak chcąc skonfigurować interfejsy sieciowe podczas rozruchu
+        musimy skorzystać z jednego z dostępnych managerów lub dostępnego w
+        systemie kompnentu. W Debianie, interfejsy sieciowe są zarządzane
+        przez dodatek <strong>ifupdown</strong>, którego składową jest plik
+        <em>/etc/network/interfaces</em>. Na Ubuntu system <em>Netplan</em>,
+        od najnowszysch wersji dystrybucji opartych o Red Hat, korzysta się
+        głównie z managerów. Natomiast managerem godnym uwagi jest
+        <strong>NetworkManager</strong> i to na nim się skupimy podczas ich
+        omawiania. Aby ten podrozdział wniósł coś pożytecznego poza kilkoma
+        teoretycznymi dywagacjami omówimy sobie konfigurację interfejsów na
+        przykładzie dystrybucji Debian.
+      </p>
+<pre class="code-block">
+source /etc/network/interfaces.d/*
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+# The primary network interface
+auto enp4s0
+iface enp4s0 inet static
+        address 172.16.1.2
+        netmask 255.255.0.0
+        gateway 172.16.0.1
+        dns-nameservers 172.16.0.1
+</pre>
+      <p>
+        Na powyższym przykładzie mamy dwie deklaracje interfejsów sieciowych.
+        Pierwszym z nich jest interfejs pętli zwrotnej. Jego rola w systemie
+        jeszcze zostanie omówiona. Nie miej jednak jego deklaracja zawiera
+        słowo <code class="code-inline">auto</code>, która powoduje załączenie
+        interfejsu podczas startu systemu. Po linii ze słowem auto następuje
+        definicja interfejsu (linia ze słowem
+        <code class="code-inline">iface</code>) w niej podawana jest nazwa
+        interfejsu (<code class="code-inline">enp4s0</code>), stos protokółów
+        (<code class="code-inline">inet</code>, co oznacza IPv4. Mogą być też
+        inne). Następnie podawana jest metoda konfiguracji interfejsu.
+        Najczęściej wykorzystywanymi są <code class="code-inline">static</code>
+        oraz <em>dhcp</em>, w przypadku pętli zwrotnej w tym miejscu
+        używane jest słowo <code class="code-inline">loopback</code>. W
+        przypadku drugiego (właściwego) interfejsu adres przypisywany będzie
+        statycznie. To tak samo jakbyśmy przypisywali go ręcznie, jest to
+        czynność automatyczna wykonywana podczas rozruchu. Po uruchomieniu
+        ponownym komputera interfejs powinien zostać automatycznie podniesiony
+        (załączony) i skonfigurowany przy użyciu podanych w pliku parametrów. 
+      </p>
+      <p>
+        Obecnie systemy służą użytkownikom końcowym, którzy zapewne mają
+        uprawnienia administratora, ale nie posiadają odpowiedniej wiedzy aby
+        móc konfigurować odpowiednie warstwy. Proste rozwiązania, takie jak
+        to opisane powyżej daje oczywiście taką mozliwośc, jednak nie jest
+        ono zbyt przystępne dla użytkownika, dlatego też w dystrybucjach takich
+        Red Hat, stosowane są managery, których zadaniem jest ułatwienie
+        konfiguracji.
+      </p>
+      <h2 id="9.9.networkconfigmanagers">9.9. Menedżery konfiguracji sieciowe</h2>
+      <p>
+        Dla dystrybucji Linuksa dostępnych jest wiele programów będących
+        menedżerami konfiguracji sieciowe. Część z nich przeznaczona jest  na
+        systemy wbudowane. Dlatego godnymi uwagi pozostają tylko dwa. Jeden
+        będący częścią programu typu <em>init</em> <strong>systemd-networkd</strong>
+        nadaje się on wykonania podstawowej konfiguracji sieciowej. Jest
+        wystarczający dla serwerów, ale nie dla użytkonika końcowego. Wówczas
+        pozostaje jeden - <strong>NetworkManager</strong> i to na nim się
+        skupimy. 
+      </p>
+      <p>
+        <strong>NetworkManager</strong> jest demonem takim samym jak pozostałe
+        więc jego zadaniem jest nasłuchiwanie zdarzeń generowanych zarówno
+        przez system jak i przez samych użytkowników, dodatkowo 
+        <em>NetworkManager</em> zajmuje się konfiguracją sieciową zgodnie z
+        założonymi regułami. Program ten operuje na informacjach
+        o dostępnych urządzenia uzyskanch od jądra oraz na 
+        <strong>połączeniach</strong>, które są wskazaniem konkretnych urządzeń
+        wraz z parametrami warstw sieciowych. Konfigurując sieć w danej
+        dystrybucji, <em>NetworkManager</em> korzysta z określonego dodatku
+        aby dostosować konfigurację do standardu używanego przez dystrybucję,
+        nie narzucacjąc przy tym swoich rozwiązań.
+      </p>
+      <p>
+        W momencie uruchomienia <em>NetworkManager</em>, zbiera informacje o
+        dostępnych urządzeniach sieciowych, sprawdza listę połączeń i
+        podejmuje decyzję o próbie połączenia. Proces decyzyjny na podstawie,
+        którego menedżer decyduje, z którą z sieci chce się połączyć można
+        rozpisać w trzech krokach.
+      </p>
+      <ol>
+        <li>Jeśli dostępne jest połaczenie kablowe. To ono jest preferowane
+          jako pierwsze.</li>
+        <li>Jeśli połączenie kablowe nie jest dostępne, wówczas jeśli w
+          systemie dostępny jest interfejs bezprzewodowy to skanowane jest
+          otoczenie podzwględem występowania sieci bezprzewodowych. Jesli
+          dostępne są sieci, z którymi system już kiedyś nawiązał połączenia.
+          To jest ono nawiązywane ponownie. Jeśli nie to dostępna jest lista
+          sieci bezprzewodowych osiągalnych na danym terenie.</li>
+        <li>Jeśli dostępne są więcej niż dwie sieci, z którymi już wcześniej
+          nawiązywano połączenie to wówczas wybierana jest,
+          z którą łączono się jako z <em>ostatnią</em>.</li>
+      </ol>
+      <p>
+        Połączenie sieciowe zwłaszacza wśród sieci bezprzewodowych utrzymywane
+        jest do momentu uzyskanie połączenia o lepszych parametrach. Na
+        przykład, po przez wpięcie kabla.
+      </p>
+      <h3 id="9.9.1.interactionwithnm">9.9.1. Interakcja z Network Manager</h3>
+      <p>
+        Kontrolować <em>NetworkManager</em> możemy za pomocą apletu,
+        przygotowanego dla środowiska graficznego. Jednak w tym materiale
+        skupiamy się wyłącznie na rozwiązaniach opartych o wiersz polecenia.
+        Więc przejdziemy od razu do tego typu interakcji z tym narzędziem.
+        Do kontrolowania <em>NetworkManager</em> z poziomu powłoki, służy
+        narzędzie <em>nmcli</em>. Za pomocą podpoleceń tego narzędzia możemy
+        kontrolować połączenia sieciowe zarządzane przez omawiany menedżer.
+      </p>
+      <p>
+        Innym narzędziem związanym z <em>NetworkManager</em>-em, jest polecenie
+        <strong>nm-online</strong>, które zwraca jedynie infomacje w zależności
+        od tego czy posiadamy aktywne połączenie czy też nie.
+      </p>
+      <p>
+        Poniżej znajduje się przykładowe uruchomienie, <em>nmcli</em> bez
+        żadnych podpoleceń. 
+      </p>
+<pre class="code-block">
+</pre>
+      <p>
+        Polecenie to agreguje informacje zwracane przez wiele poznanych do
+        tej pory poleceń, takich jak <em>ip addr</em> lub <em>ip route show</em>.
+        Dodatkowo wyświetlane są informacje o konfiguracji systemu DNS. 
+      </p>
+      <p>
+        Dla przykładu możemy utworzyć ręczną konfigurację dla interfejsu tym
+        razem wykorzystując do tego <em>NetworkManager</em>.
+      <p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo nmcli con add con-name my-connection ifname enp4s0 \
+type ethernet ipv4 192.168.8.150/24 gw4 192.168.8.1
+</pre>
+      <p>
+        Efekt działania tego polecenia możemy sprawdzić za pomocą polecenia
+        <em>ip a</em> lub za pomocą <em>nmcli</em> 
+      </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ip a
+
+xf0r3m@immudex:~$ nmcli -p con show my-connection
+</pre>
+      <p>
+        Opcja <code class="code-inline">-p</code> formatuje wynik polecenia,
+        aby był on bardziej czytelny dla człowieka. Więcej przykładowych
+        poleceń wraz z opisami znajduje się na stronie podręcznika:
+        <em>man 7 nmcli-examples</em>. <em>NetworkManager</em> to naprawdę
+        rozbudowane narzędzie więc warto mieć z tyłu głowy to polecenie,
+        chociażby dlatego, że znajduje się tam opis sposobu łączność z siecią
+        bezprzewodową z poziomu wiersza poleceń. Sposób dużo bardziej
+        przystępny niż samodzielne skanowanie i obcowanie z pakietem
+        <em>wpa_supplicant</em>, gdzie często demon tego narzędzia może być
+        już użwany przez jeden z komponentów systemu.
+      </p>
+      <h3 id="9.9.2.nmconfiguration">9.9.2. Konfiguracja NetworkManager</h3>
+      <p>
+        Konfiguracja <em>NetworkManagera</em> wymaga edycji pliku
+        <em>/etc/NetworkManager/NetworkManager.conf</em>. Plik jest formatu
+        <em>XDG</em> lub wśród osób zaznajomionych z systemami od Microsoftu
+        formatu <em>.ini</em>. Rzadko będzie potrzeba zmiany czego kolwiek w
+        tym pliku. Nie mniej jednak jest jedna funkcją warta omówienia związana
+        z konfiguracją tego menedżera - <strong>wyłączenie zarządania interfejsu</strong>
+        przez <em>NetworkManager</em>. Interfejs pętli zwrotnej jest izolowany
+        od tego narzędzia i jeśli uznamy, że inny/inne interfejsy w systemie
+        też powinny to możemy zadeklarować w tym pliku. W sekcji
+        <em>[keyfile]</em> (jeśli nie ma takowej, to należy dopisać). Plik
+        ma format <em>XDG</em>, więc opcje zapisywane są w postaci 
+        <em>klucz=wartość</em>. Tak więc do klucza <em>unmanaged-devices</em>
+        przypisujemy adres MAC interfejsów, które mają być wyłączone z spod 
+        zarządzania przez <em>NetworkManager</em> w taki sposób jak przedstawio
+        to poniżej.
+<pre class="code-block">
+...
+[keyfile]
+unmanaged-devices=mac:08:00:27:3d:1b:9c
+</pre>
+      </p>
+      <p>
+        Inną kwestią związaną z konfiguracją omawianego w tym rodziale
+        menedżera jest propagacja informacji o zmianie status interfejsu
+        sieciowego. Niektóre demony do swojego poprawnego działania muszą
+        otrzymać takową informację o tego typu sytuacji, aby zakończyć lub
+        rozpocząć nasłuchiwanie na danym interfejsie. <em>NetworkManager</em>
+        realizuje to za pomoca <strong>sieciowych skrytów sterujących</strong>
+        znajdujących się w katalogu <em>/etc/NetworkManager/dispatcher.d</em>.
+        Jeśli status interfejsu sieciowego ulegnie zmianie menedżer uruchomi
+        wszystko co zostało umieszczone w powyższym katalogu z odpowiednim
+        dla stanu interfejsu (<em>up</em> lub <em>down</em>). Na przykład
+        w dystrybucjach opartych na Debianie (w tym i Ubuntu) istnieje plik
+        <em>01-ifupdown</em>, który na podstawie otrzymanego komunikatu
+        zdrzenia (jeśli przyjrzeć się plikowi, to dowiemy się że to nie tylko
+        <em>up</em> oraz <em>down</em>) uruchomi wszystko znajduje się w
+        odpowiednich podkatalogach w katalogu <em>/etc/network</em>.
+      <p>
+      <p>
+        Dla nas zarówno konfiguracja <em>NetworkManager</em> może być mało
+        istotna, podobnie jest ze skryptami rozsyłającymi. Nie mniej jednak
+        może się kiedyś zdarzyć, że będzię potrzeba zmiany czegoś w skrypcie
+        tego typu lub wyłączenie interfejsu z menedżera.
+      </p>
+      <h2 id="9.10.nameresolution">9.10. Rozwiazywanie nazw hostów.</h2>
+      <p>
+        Jeśli chcemy nawiązać jakie kolwiek połączenie sieciowe musimy podać
+        adres komputera, z którym chcemy to połączenie nawiązać. Ludzie
+        rzadko posługują się adresami IP, chyba że są to specjaliści lub 
+        entuzajści nauk komputerowych i pracują oni w lokalnych środowiskach.
+        Takie adresy trudno zapamiętąć, więc niezbędne jest zapewnienie
+        systemu/usługi, która zmieni adresu domenowe 
+        (np. <em>morketsmerke.org</em>) na adres IP. Z systemem DNS mieliśmy
+        już
+        styczność, w momencie gdy omawialiśmy protokół ICMP. Konfiguracja
+        adresów systemu DNS jest tak naprawdę czwartą ostatnią wartością
+        konfigurowaną na interfejsie sieciowym, aby mógł on nawiązać
+        połączenie z internetem. Jest to o tyle ciekawe, że system DNS należy
+        do warstwy aplikacji. Większość aplikacji sieciowych w Linuksie ma
+        możliwość odpytania systemu DNS o adres IP, dlatego możemy zarówno
+        użyć adresów IP lub nazw domenowych (chyba, że wyszczególniono inaczej). 
+        Uzyskiwania takiego adresu od DNS zwykle przebiega w następujący sposób:
+      </p>
+       <ol>
+          <li>Przy uzyciu systemowej biblioteki współużytkowanej aplikacja
+            wywołuje funkcję wyszukiwania adresu IP.</li>
+          <li>Określa się kolejność odpytywania źródeł na podstawie danych 
+            zapisanych w pliku <em>/etc/nsswitch.conf</em>. Jedną z takowych
+            reguł może być wymuszenie kolejności odpytania na początku pliku
+            <em>/etc/hosts</em> jeszcze przed odpytaniem systemu DNS.</li>
+          <li>Jeśli funkcja jednak zdecyduje o skorzystaniu z systemu DNS, musi
+            użyć zawartości pliku konfiguracyjnego, w którym zawarte są adres
+            serwerów systemu DNS.</li>
+          <li>Funkcja wysyła zapytanie z adresem domenowym serwera, prosząc o
+            jego adres IP.</li>
+          <li>Serwer DNS odsyła do funkcji adres IP serwera, który zwracany
+            jest do aplikacji.</li>
+       </ol>
+        <p>
+          Często występującym scenariuszem jest to, że serwer systemu DNS nie
+          zna adresu IP serwera, o który prosimy, wówczas serwer, do którego
+          skierowaliśmy to zapytanie musi zapytać się innych serwerów.
+          DNS ma budowę hierarchiczną, a cała hierarchia jest zapisana w 
+          adresie domenowym. Szerszy opis systemu DNS wykracza poza ramy
+          meryteoryczne tego materiału. 
+        </p>
+        <h3 id="9.10.1.dnsfiles">9.10.1. Pliki biorące udział w działaniu systemu DNS</h3>
+        <p>
+          Jak możemy wywnioskować z wyżej wymienionych czynności system DNS
+          nawet w roli klienta potrzebuje korzysta z dużej ilości plików.
+          Pierwszym z nich jest <strong>/etc/nssswitch.conf</strong>. Ten plik
+          nie jest związany <em>stricte</em> z systemem DNS, ale ze wszystkim
+          co jest związane z nazwami w systemie. Jest to klasyczny interfejs
+          określający pierwszeństwo w źródłach rozwiązywania nazw. Jeśli
+          przeanalizujemy sobie zawartość tego pliku, możemy zauważyć
+          skąd i na jakiej podstawie, niektóre z narzędzi czerpią wiedzę
+          taką jak 
+          informacje o użytkownikach, usługach czy innych rodzajach sieci niż
+          IP. Jednak na tym etapie interesuje nas wyłącznie linia
+          rozpoczynająca się od <em>hosts</em>. Wskazuje ona pierwszeństwo
+          pliku /etc/hosts nad system DNS, przez co korzystając z dystrybucji
+          możemy dowolnie manipulować rozwiązywaniem nazw. Jest to szczególnie
+          przydane podczas administracji i testowania usług, które później
+          będziemy chcieli użyć.
+        </p>
+        <p>
+          Kolejnym plikiem jest wspomaniany już wcześniej <em>/etc/hosts</em>.
+          Plik ten zawiera zestawienie adresów IP wraz z nazwami domenowymi.
+          Kiedyś kiedy hosty w internecie można było policzyć na palcach obu
+          rąk służył za centralną bazę danych odnosnie odwzrowania nazw. Był
+          on swojego czasu protoplastą systemu DNS. Jednak ze względu na
+          <em>bum</em> rozwoju internetu, zaprzestano korzystania z tej
+          praktyki. Jednak obecnie wciąż można spotkać go w roli lokalnej bazy
+          rekordów DNS w sieciach, gdzie centralnym urządzeniem (router/bramka
+          core'owy) jest urządzenie oparte na jakimś uniksie.
+        </p>
+        <p>
+          Ostatnim plikiem jest <em>/etc/resolv.conf</em>. Zawartość tego 
+          pliku, ma
+          wpływ na to z jakiego źródła systemu DNS korzysta nasz system. Otóż
+          w tym pliku przechowywane są zazwyczaj dwie wartości pierwszą z nich
+          są adresy serwerów systemu DNS, a drugim sufiks nazwy domenowej
+          wykorzystywany wtedy gdy podamy samą nazwę hosta bez nazwy domeny,
+          to znaczy jeśli na przykład podamy samo <em>www</em> zamiast
+          <em>www.morketsmerke.org</em>, wówczas funkcja na podstawie sufiksu
+          z tego pliku sama go doda i przekaże żądanie dalej na 
+          jeden z adresów widniejących po opcji <em>nameserver</em>.
+        </p>
+        <h3 id="9.10.2.configlessdnsandcache">9.10.2. Buforowanie oraz bezkonfiguracyjne systemy DNS</h3>
+        <p>
+          Buforowanie to czyność, którą głównie się kocha a czasem nienawidzi.
+          Buforowanie odpowiedzi systemu DNS jest odpowiedzią na fakt, że
+          komputery odpytujące system DNS nie przechowywały nigdzie uzyskanych
+          od
+          serwera odpowiedzi, zbyt często powtarazna tego typu czynność mogła
+          przytkać sieć. Obecnie bardzo często adres serwera DNS jest również
+          adres bramy. Ma to głównie na celu właśnie buforowanie, na naszym
+          domowym routerze za pewne uruchomiony jest demon 
+          buforująco-przekazujący. Niestety w
+          przypadku wielu urządzeń nie będzie my się wstanie tego dowiedzieć.
+          Ale jeśli nasz sprzęt jest zmodyfikowany, lub naszym routerem jest
+          jest oprogramowanie zainstalowane na komputerze z wieloma kartami
+          sieciowymi, to raczej na 100% tak będzie. Innym sposóbem na
+          <em>wykrycie</em> systemu buforującego, jest sprawdzenie zawartości
+          pliku <em>/etc/resolv.conf</em>. Jeśli widnieje tam tylko jeden
+          wpis <em>nameserver</em> to za pewne z adresem <em>127.0.0.53</em>.
+          Jest to adres z klasy <em>pętli zwrotnej</em> (o której będzie za
+          chwilę), czyli wiemy, że to usługa uruchomiona lokalnie na tej
+          maszynie. Jest to jeden z demonów programu typu <em>init</em>
+          (<em>systemd</em>) - <strong>systemd-resolved</strong>. Często w tym
+          wypadku sam plik jest dowiązaniem symboliczym. Użycie tego rodzaju
+          systemu rozwiązuje inny problem związany z brakiem elastyczności
+          statycznych konfiguracji, wówczas nie ma potrzeby wprowdzania zmian
+          w komponentach systemu.
+        </p>
+        <p>
+          Wspomniany wcześniej demon posiada jedną ważną cechę. Potrafi łączyć
+          wiele sposobów wyszukiwania nazw w sieci, co przekłada się na
+          możliwość użycia bezkonfiguracyjnych systemów DNS. W przypadku takiej
+          konfiguracji jeśli podłączymy nowe urządzenie do sieci będziemy
+          mogli wywołać je za pomocą nazwy. Jeśli host istnieje udzieli
+          odpowiedzi ze swoim adresem IP. Rozwiązaniami tego typu są 
+          <strong>mDNS</strong> (<em>multicastDNS</em>) oraz 
+          <strong>LLMNP</strong> (<em>Link-Local Multicast Name Protocol</em>).
+          Rozwiązania te poza zwykłym odwzorowaniem nazw, mogą przedstawiać
+          dostępność usług. Ich dostępność w systemie możemy sprawdzić za
+          pomocą polecenia <em>resolvectl status</em>, warto jednak pamiętać,
+          że jego działanie jest uzależnione od działania wcześniej 
+          wspomnianego demona.
+        </p>
+        <h2 id="9.11.localhost">9.11. Host lokalny</h2>
+        <p>
+          W wielu systemach operacyjnych, poznając ich możliwości sieciowe
+          możemy natknąć się na dośc specyficzny interfejs, który w uniksach
+          określany jako <strong>lo</strong>. Jest to jedyny interfejs, który
+          będzie posiadać w plikach konfiguracyjnych statyczną konfigurację.
+          Interfejs <strong>pętli zwrotnej</strong> bo tak jest określany
+          przez swój sposób działnia służy głównie interakcji z programami
+          sieciowymi bez potrzeby angażowania innych interfejsów. Na przykład
+          jeśli aplikacja jest w fazie testów i póki co nikt po za naszym
+          komputerem nie powinien się z nią łączyć. To wtedy taką aplikację
+          ustawia się tak aby oczekiwała na połączenia na interfejsie pętli
+          zwrotnej. Wówczas pakiety będą przesyłane przez ten interfejs w obu
+          kierunkach i opuszczając tym samym jednej fizycznej maszyny. Można
+          powiedzieć również że adres pętli zwrotnej to połączenie z
+          <em>samym sobą</em>.
+        </p>
+        <p>
+          Jeśli wyświetlimy sobie konfigurację interfejsu pętli zwrotnej to 
+          zwrócimy uwagę na to, jaki adres został mu przypisany:
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ ip addr show lo
+1: lo: &lt;LOOPBACK,UP&gt; mtu 1500 group default qlen 1
+    link/loopback 00:00:00:00:00:00
+    inet 127.0.0.1/8 brd 127.255.255.255 scope global dynamic
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host dynamic
+       valid_lft forever preferred_lft forever
+</pre>
+        <p>
+          Jest to bardzo duża klasa adresowa. Jeśli przypisany do usługi adres
+          będzie rozpoczynął się od 127 i posiadał 8 bitową maskę, będzie
+          wówczas przypisany do pętli zwrotnej.
+        </p>
+        <h2 id="9.12.transportlayer">9.12. Warstwa transportowa oraz usługi</h2>
+        <p>
+          Przedostatnią warstwą modelu TCP/IP jest warstwa transportowa.
+          Jak sobie wcześniej omówilismy definiuje ona sposób transmisji w
+          sieciach IP. Wewnątrz niej możemy znajdują się takie protokoły
+          jak <strong>TCP</strong> oraz <strong>UDP</strong>, ona także
+          definiuje pojęcie <strong>portu</strong>.
+        </p>
+        <h3 id="9.12.1.tcp">9.12.1. TCP - Transmission Control Protocol</h3>
+        <p>
+          TCP jest protokołem przepływu danych w sieciach IP. Jest to protokół,
+          który przed właściwą transmisją danych zestawia coś w rodzaju
+          <em>połączenia</em>. Za pomocą specjalnych pakietów kontrolnych 
+          strona odległa
+          informowana jest o nadchodzącej transmisji, i jeśli faktycznie jest
+          ona w stanie odebrać dane (port na który, strona lokalna chce wysłać
+          informacje jest otwarty) odsyła informacje zwrotną o tym, że może
+          wysyłać. Wówczas po wymianie pakietów kontrolnych, dochodzi do
+          wysłania danych z komputera lokalnego do komputera zdalnego. Protokół
+          TCP czuwa nad przebiegiem transmisji, każdy pakiet ma swój numer i
+          strona
+          zdalna po jego otrzymaniu wysyła pakiet kontrolny z potwierdzeniem
+          jeśli odpowiedź nie przychodzi w określonym czasie wówczas dochodzi
+          do retransmisji zagubionych pakietów. TCP jest protokołem
+          wolniejszym od innego protokołu z tej samej warstwy, zapewnia jednak
+          niezawdność transmisji, przez co strona odległa może mieć pewność, że
+          uzyska poprawne dane. Ten protokół wykorzystywany jest w wiekszości
+          usług w internecie, w których przenoszone przez jego łącza dane mają
+          znaczenie użytkowników końcowych. Dane są po prostu istotne.
+        </p>
+        <h3 id="9.12.2.udp">9.12.2. UDP - User Datagram Protocol</h3>
+        <p>
+          UDP jest trochę innym protokołem niż TCP, ale jego główna rola jest
+          bardzo podobna, z tą różnicą, że nie zawiera on żadnych mechanizmów
+          kontroli. Ma to swoje plusy i minusy. Protokół jest na tyle szybki,
+          że wykorzystywany jest przez różnego rodzaju aplikacji służące do
+          przesyłania strumieniowego. W tym wypadku możemy osobiście
+          doświadczyć błędów w transmisji objawiających się spadkiem jakość
+          <em>streamowanych</em> materiałów. Inną ważnym wykorzystaniem tego,
+          protokołu, właśnie ze względu na <em>zalety</em> protokołu TCP jest
+          użycie UDP do budowania sieci prywatnych VPN. Faktem, dla którego
+          nie korzysta się protokołu TCP jest <em>piekło</em> retransmisji.
+          Załóżmy, że dochodzi do błedów w zewnętrznej
+          transmisji, czyli między serwerami VPN i jeśli byłaby to transmisja
+          TCP doszło by do retransmisji, system VPN będzie musiał zatrzymać się
+          wówczas host docelowy transmisji wewnętrznej zauważy zagubienie 
+          pakietu i rozpocznie swoją retransmisję
+          co doprowadzi do zapchania łącza i wstrzymania trasnsmisji
+          w ogóle. Dlatego też stosuje się protokół UDP dla transmisji
+          zewnętrznej, wówczas nad poprawnością danych przenoszonych przez
+          tunel VPN czuwać będą hosty transmisji wewnętrznej. Jak możemy 
+          zauważyć wszystko co może być zaletą w konkretnym przypadku może 
+          okazać się wadą w innym.
+        </p>
+        <h3 id="9.12.3.ports">9.12.3. Porty</h3>
+        <p>
+          Z wyżej wymienionych metod
+          transmisji przy uzyciu portów korzystają różne aplikacje. 
+          <strong>Port</strong> to
+          nic innego jak numer wystąpienia aplikacji w obszarze warstwy
+          transportowej. Na ten numer kierowane są pakiety i w ten sposób 
+          aplikacja otrzymuje dane z sieci. Aplikacje sieciowe posidaja
+          przypisane te numery przez swoich twórców, ich lista wstępuje
+          w każdym uniksie, który ma możliwośc podłaczenia do sieci. Lista
+          znajduje się w pliku, <em>/etc/services</em>. Większość zebranych
+          tam aplikacja powstawa wraz z internetem, więc lista może być długa
+          i już nie zbyt aktualna, ale jednak jest pewnym zbiorem informacji.
+          Poniżej znajduje się kilka protokołów wraz z informacją z której
+          pochodzi źródło.
+        </p>
+<pre class="code-block">
+# Updated from https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml .
+http            80/tcp          www             # WorldWideWeb HTTP
+https           443/tcp                         # http protocol over TLS/SSL
+https           443/udp                         # HTTP/3
+http-alt        8080/tcp        webcache        # WWW caching service
+</pre>
+        <p>
+          Obok portu wyświetlony jest również rodzaj transmisji. Ciekawostką
+          jest fakt, że trzecia generacja protokołu HTTPS będzie oparta na
+          protokole UDP, a nie TCP.
+        </p>
+        <h3 id="9.12.4.printconnections">9.12.4. Wyświetlanie połączeń sieciowych w systemie</h3>
+        <p>
+          Omawiając warstwę transportową to nie sposób jest nie wspomnieć o 
+          wyświetlaniu połączeń. Obecnie w dystrybucjach Linuksa używa się
+          nowego polecenia jakim jest <strong>ss</strong>, aby wyświetlić
+          połączenia TCP w systemie należy wydać poniższe polecenie. Polecenie
+          to dla przykładu zostało wydane na jednym z moich serwerów VPS
+        </p>
+<pre class="code-block">
+root@searx:~# ss -tr
+State       Recv-Q  Send-Q          Local Address:Port                                     Peer Address:Port   Process
+CLOSE-WAIT  32      0        ip109.ip-51-178-2.eu:57026                                   146.75.74.208:https
+CLOSE-WAIT  64      0        ip109.ip-51-178-2.eu:32808                     text-lb.drmrs.wikimedia.org:https
+CLOSE-WAIT  64      0        ip109.ip-51-178-2.eu:43164                     text-lb.drmrs.wikimedia.org:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:57466                                    52.84.150.51:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:35092     server-143-204-68-27.lhr61.r.cloudfront.net:https
+CLOSE-WAIT  25      0        ip109.ip-51-178-2.eu:45492                   upload-lb.drmrs.wikimedia.org:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:41928     server-143-204-68-21.lhr61.r.cloudfront.net:https
+CLOSE-WAIT  32      0        ip109.ip-51-178-2.eu:36336              qwantbot-115-168-187-194.qwant.com:https
+ESTAB       0       52       ip109.ip-51-178-2.eu:2022                                     213.25.29.68:63950
+CLOSE-WAIT  130     0        ip109.ip-51-178-2.eu:60580                        waw02s07-in-f4.1e100.net:https
+CLOSE-WAIT  47      0        ip109.ip-51-178-2.eu:33310                                    104.16.55.16:https
+CLOSE-WAIT  130     0        ip109.ip-51-178-2.eu:43572                        waw02s07-in-f4.1e100.net:https
+CLOSE-WAIT  32      0        ip109.ip-51-178-2.eu:36666                                   140.177.50.13:https
+CLOSE-WAIT  1       0        ip109.ip-51-178-2.eu:33408                       par21s17-in-f14.1e100.net:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:53446                                    172.67.22.17:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:57454                                    52.84.150.51:https
+ESTAB       0       0        ip109.ip-51-178-2.eu:2022                                     213.25.29.68:61628
+CLOSE-WAIT  32      0        ip109.ip-51-178-2.eu:53654                            www.wolframalpha.com:https
+CLOSE-WAIT  32      0        ip109.ip-51-178-2.eu:58752              qwantbot-109-168-187-194.qwant.com:https
+CLOSE-WAIT  130     0        ip109.ip-51-178-2.eu:58880                        waw02s07-in-f4.1e100.net:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:37804              qwantbot-106-168-187-194.qwant.com:https
+CLOSE-WAIT  25      0        ip109.ip-51-178-2.eu:50924     server-18-244-117-84.lhr50.r.cloudfront.net:https
+CLOSE-WAIT  64      0        ip109.ip-51-178-2.eu:43148                     text-lb.drmrs.wikimedia.org:https
+CLOSE-WAIT  90      0        ip109.ip-51-178-2.eu:41176                                  151.101.65.181:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:58504    server-18-244-153-127.lhr50.r.cloudfront.net:https
+CLOSE-WAIT  40      0        ip109.ip-51-178-2.eu:58216      server-13-224-132-41.lhr3.r.cloudfront.net:https
+</pre>
+        <p>
+          W pierwszej kolumnie znajduje się stan połaczenia, jak już wcześniej
+          wspominałem protokół TCP ustanawia połączenia i ta kolumna
+          przedstawia ich stan. <code class="code-inline">Estab</code> skrót od
+          ang. <em>established</em> oznacza że połączenie zostało nawiązane i
+          dalej trwa. Dalej przesyłane są jakieś pakiety. Reszta połączeń
+          pozostaje w stanie <code class="code-inline">CLOSE-WAIT</code> jest
+          to stan oczekiwania na zamknięcie połączenia przez użytkownika.
+          Przeważnie nie musimy się przejmować tego rodzaju połączeniami, one
+          zostaną zakończone z czasem. Druga i trzecia kolumna przechowują
+          informacje odnośnie pamięci podręcznej wysyłania i odbioru. Najlepiej
+          aby te wartości były jak najbliżej zera. Wysokie wartości w kolumnie
+          <code class="code-inline">Recv-Q</code> mogą świadczyć o tym, że
+          pakiety osiągneły komputer docelowy, ale nie ma kto ich odebrać, na
+          natomiast w wysokie wartości w kolumnie
+          <code class="code-inline">Send-Q</code> mogą najczęściej oznaczać, że
+          pakiety zostały wysłane ale do hosta, który na nie oczekuje i nie
+          potwierdza ich odebrania lub pakiety nie zostały wysłane w ogóle.
+          Czwarta oraz piąta kolumna zawierają <strong>gniazda</strong> lokalne
+          oraz zadalne. Za pomocą <strong>gniazd</strong> określamy połączenie
+          adresu IP lub nazwy domenowej (tak, jak w tym przypadku) z portem.
+          O gniazadach w kontekście Uniksów więcej informacji przedstawię w
+          następnym rozdziale.
+        </p>
+        <p>
+          Wydając powyższe polecenie użyłem opcji <code class="code-inline">-t</code>
+          określającej rodzaj transmisji 
+          (<code class="code-inline">-t</code> - TCP) oraz opcji
+          <code class="code-inline">-r</code>, która zamienia adres IP oraz
+          numery portów na nazwy domenowe i nazwy usług. Warto zapoznać się
+          zawartością strony podręcznika narzędzia <em>ss</em>. Można odnależć
+          opcje pozwalającą na zamykanie dowolnych połączeń. Połączenia
+          (może, raczej rejestr transmisji) dla protokołu UDP możemy
+          wyświetlić za pomocą opcji <em>-u</em>.
+        </p>
+        <h2 id="9.13.dhcp">9.13. Protokół dynamicznej konfiguracji hosta - DHCP</h2>
+        <p>
+          Ciężko sobie wyobrazić współczesną sieć bez tak ważnego składnika
+          jakim jest protokół <strong>DHCP</strong>. Jest on odpowiedzialny
+          za konfigurację interfejsów sieciowych oraz za utrzymywanie 
+          informacji o przekazanych parameterach, aby nie dochodziło do
+          absurdalnych zdarzeń, np. żeby dwa komputery w sieci nie dostały tego
+          samego adresu. Poza adresami IP serwer DHCP, konfigurje interfejsy
+          w taki sposób, aby komputer był podłączony do internetu. W sieciach
+          korporacyjnych mogą być konfigurowane dodatkowe paramety lub
+          domyślna pula może nie istnieć, a nowe urządzenia trzeba dodawać do
+          listy
+          rezerwacji, w tym wypadku komputery uzyskują statyczny adres IP ale
+          nie jest on przypisywany przez administratora, tylko przez DHCP
+          właśnie.
+        </p>
+        <p>
+          Metoda uzyskiwania adresu jest dość niezwykła. Otóż jak komputer,
+          który nie posiada adresu IP ma skomunikować z innym komputerem i
+          jakimi. Otóż z każdym. Klient DHCP rozsyła na pakiet z poszukiwaniem
+          serwera DHCP, na adres rozgłoszeniowy sieci (<em>255.255.255.255</em>)
+          w tym pakiecie może być zawarty adres, jaki klient kiedyś posiadał.
+          W odpowiedzi od serwera, klient dostanie ofertę, z którą może się
+          zgodzić lub żądać innych, bądź dodatkowych parametrów, wówczas
+          zostaje wysłane żądanie. Po uznaniu żądania, serwer wysyła
+          potwierdzenie. Kiedy klient otrzyma potwierdzenie rozpoczyna
+          konfigurację interfejsu sieciowego i na tym etapie rola DHCP kończy
+          się. Jednak należy pamiętać, że adresy są dzierżawione od serwera,
+          czyli czas konfiguracji jest określony i od czasu do czasu 
+          trzeba się z tym serwerem skomunikować, aby utrzymać obecną
+          kofigurację lub prosić o nową. Jednak to pozostaje już w gestii
+          klienta. 
+        </p>
+        <p>
+          Obsługa protokołu DHCP na uniksach występuje w oryginalnej 
+          implementacji. Do dyspozycji mamy pakiet klienta
+          <strong>dhclient</strong>, wśród serwerów możemy wyróżnić co najmniej
+          dwie godne polecenie implementacje. Jedną z nich wykorzystamy
+          tworząc z komputera z dystrybucją Linuksa domową bramkę. Aby
+          pobrać konfigurację z serwera DHCP (nie które dystrybucje, nie
+          posiadają domyślnie żadnej konfiguracji sieciowej) należy wydać
+          poniższe polecenie. 
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ dhclient enp4s0
+</pre>
+        <p>
+          Podanie interfejsu jako argument spowoduje skonfigurowanie
+          tylko tego konkretnego interfejsu, jeśli go pominiemy skonfigurowane
+          zostaną wszystkie aktywe (w których warstwy poniżej internetowej już
+          działają).
+        </p>
+        <p>
+          Jeśli chcelibyśmy poznać np. czas dzierżawy to informacje uzyskane
+          od serwera znajdują sie w pliku dzierżawy
+          <em>/var/lib/dhcp/dhclient.leases</em>
+        </p>
+        <p>
+          Do tej pory omawiając DHCP, skupialiśmy się głównie na protokole
+          IPv4. W przypadku protokołu IPv6 również istnieje możliwość
+          zastosowania DHCP, nawet został przygotowany ku temu standard
+          protokołu DHCPv6 to proponowane jest innego rodzaju rozwiązanie.
+          Ze względu na długość adresów IPv6, organizacja zarządzająca
+          wykorzystała częśc adresów na potrzeby nowej metody konfiguracji.
+          <strong>Konfiguracja bezstanowa</strong> nie wymaga punktów
+          centralnych w postaci serwerów do konfiguracji interfejsów dla IPv6.
+        </p>
+        <p>
+          Metoda działania tej konfiguracji opiera się o adresy sieci lokalnej
+          łącza, ze względu długość adresu host może wygenerować sobie adres,
+          który może z mały prawdopodobnieństwem powtórzyć się w sieci.
+          Z resztą mając ustalony prefiks (<em>fe80::/64</em>) można wysłać
+          zapytania do innych hostów w sieci czy adres, który host wygenerował
+          jest wykorzystywany przez inne hosty w sieci. Jest to mało
+          prawdopodobne gdyż do wygenerowania tego adresu bierze udział
+          adres MAC. Po uzyskaniu łącza lokalnego, host może określić adres
+          globalny z pomocą komunikatów RA (<em>Router Advertisement</em>)
+          wysłanego co jakiś czas przez router w naszej sieci lokalnej.
+          Komunikat zawiera prefiks sieci globalnej, adres routera oraz adresy
+          serwerów DNS. Po otrzymaniu tych informacji może podjąć próbę
+          wygenerowania części adresów odpowiadającej za identyfikator
+          interfejsu. W ten sposób interfejs otrzymuje dostęp do internetu
+          za pośrednictwem protokołu IP w wersji 6.
+        </p>
+        <h2 id="9.14.linuxasrouter">9.14. Konfiguracja systemu Linux jako router</h2>
+        <p>
+          Ten podrozdział będzie dość obszerny, ponieważ postanowiłem zebrać
+          w nim część zagadnień sieciowych dotyczących konfiguracji dystrybucji
+          Linuksa w celu wykorzystania jako router.
+        </p>
+        <p>
+          Chcąc wykorzystać komputer z dystrybucją Linuksa jako bramę czy
+          router (w zależności ile sieci będzie łączyć) musimy zaopatrzyć nasz
+          komputer w odpowiednią ilość interfejsów. Jak możemy się domyślić
+          interfejsy to nic innego jak karty sieciowe. Jeśli jest to zwykły
+          PC to dołożenie kart nie powino być problemem (zakładając, że
+          nasza sieć jest oparta na miedzianej skrętce) a najzwyklejsze
+          karty (gigabitowe) mogą kosztować w okolicach 50 zł  jeśli nie mamy
+          możliwości rozbudowania komputera o więcej niż jedną kartę to możemy
+          użyć kart serwerowych, one zazwyczaj posiadają od 2 do 4 portów a
+          zajmują jeden port PCI-E x16 (rzadko, kto będzie mieć w komputerze
+          przeznaczonym na router, złącza PCI-E x8 lub x4, bo takie złącze
+          będą mieć karty tego typu). 
+        </p>
+        <h3 id="9.14.1.linuxdistroforrouters">9.14.1. Oprogramownie główne</h3>
+        <p>
+          Wiele urządzeń dostępnych na rynku jako router posiada przyjazny,
+          z którym możemy połączyć się za pośrednictwem przeglądarki
+          internetowej, a obecnie cześć producentów posiada również aplikacje
+          mobline do ich kontrolowania. Tego typu rozwiązania zapewniają nam
+          łatwość konfiguracji, która często sprowadza sie to wpisania kilku
+          rzeczy i klikania <em>Dalej, dalej, dalej...</em> i na koniec
+          zrestartowania urządzenia. Na tym zadanie się, kończy za
+          pośrednictwem tego urządzenia komputery w naszej sieci lokalnej będą
+          posiadać połączenie z internetem. Mimo to na tych sprzętach w dużej
+          mierze przeważa Linux. Ten system w warunkach wbudowanych jest
+          wstanie uruchomić się z każdego urządzenia. Czytając te słowa,
+          zabrneliśmy tak daleko w głąb tego materiału, że możemy z pewnością
+          stwierdzić, że domyślnie na Linuksie próżno szukać takich udogodnień.
+        </p>
+        <p>
+          Każda dystrybucja posiada wiele cech specyficznych, z racji tego iż
+          nie narzucałem żadnej konkretej (chociaż, Debian tutaj przoduje). To
+          warto wybrać tę której używaliśmy do tej pory jeśli jest to wiodąca
+          dystrybucja to możemy zainstalować takie oprogramowanie jako
+          <strong>cockpit</strong>, jest to środowisko do zarządania serwerem
+          z poziomu WWW, przez przeglądarkę. Dostępne jest ono w wiekszości
+          dystrybucji. Niestety nie daje ono zbyt rozbudowanych możliwości.
+          Cechą dominującą przy wyborze powinna być stabliność
+          dystrybucji, dlatego takie dystrybucje jak Debian lub dystrybucje
+          klasy <em>Enterprise</em> (pomijając te płatne) jak Rocky czy Alma
+          Linux sprawdzą się tutaj znakomicie. Problemem z tymi dystrybucjami
+          jest trochę inna konfiguracją zapory sieciowej, ale ona opisana jest
+          w innym moim materiale odnośnie RHCSA. Zatem wybierając taką
+          dystrybucję mamy nieco więcej pracy, ale możemy mieć pewność, że
+          nie spotkamy się z różnymi, nie zawsze przemyślanymi rozwiązaniami
+          dostawców różnych nakładek czy dystrybucji skierowanych na routery.
+          Sam osobiście wole takie rozwiązanie.
+        </p>
+        <p>
+          Innym, dużo prostszym podejściem do tego typu zadania, może być użycie
+          dystrybucji przeznaczonej do zamieniania PC-tów z kilkoma kartami
+          sieciowymi w router, takimi jak np. dystrybucja IPFire. Takich
+          dystrybucji nie tylko opartych o Linux jest wiele więcej. Część z
+          nich jest już niewspierana lub wątpliwej jakość (<em>zeroshell</em>,
+          może dlatego upadła). Cała lista dostępna jest pod 
+          <a href="https://en.wikipedia.org/wiki/List_of_router_and_firewall_distributions">tym</a>
+          adresem.
+        </p>
+        <p>
+          Możemy również zmienić całkowicie podejście do tematu. Jeśli nie mamy
+          wolnego
+          komputera, którego możemy użyć w roli routera. To możemy użyć
+          domowego routera, jako mikroserwer z Linux. Za pomocą dystrybucji
+          takiej jak DD-WRT, a szczególnie <strong>OpenWRT</strong> możemy
+          uzyskać dostęp dystrybucji Linuksowej na tym nie pozornym urządzeniu.
+          Lista kompatybilnego sprzętu, na którym możemy zainstalować
+          OpenWRT jest dość obszerna. Więc może znajdziemy system pasujący do
+          naszego sprzętu. Dodam również, że obsługa tego typu dystrybucji
+          może może opierać na konkretnym narzędziu i żadne z przedstawionych
+          poniżej rozwiązań, skierowanych raczej do dystrybucji ogólnych, takich
+          jak Debian, może nie działać. Wówczas zachęcam do zapoznania się z
+          dokumentacją.
+        </p>
+        <p>
+          Poniższe rozwiązania bedą dotyczyć głównie wiodących dystrybucji.
+          Więc jeśli zdecydujemy się inne rozwiązania wykonanie zadania możemy
+          oprzeć o dostępną dokumnetację.
+        </p>
+        <h3 id="9.14.2.additionalsoftware">9.14.2. Oprogramowanie dodatkowe</h3>
+        <p>
+          Poza system operacyjnym i jego wewnętrznymi komponentami sieciowymi
+          do zbudowania pełno prawnego routera lub bramy potrzebujemy kilku
+          pakietów: 
+        </p>
+        <ul>
+          <li>Pakietu zapory sieciowej - <strong>iptables</strong></li>
+          <li>Pakietu DHCP wraz z DNS - <strong>dnsmasq</strong></li>
+          <li>Pakietu rozgłaszania sieci bezprzewodowej (opcjonalnie) - <strong>hostapd</strong></li>
+        </ul>
+        <p>
+          Jeśli jesteśmy w posiadaniu odpowiedniego sprzętu nasz router może
+          rozgłaszać sieć bezprzewodwą. Jeśli chcielibyśmy coś takiego
+          zrealizować to warto zapoznać się z tematem tworzenia mostów.
+          Jeśli taki most miedzy <em>LAN-em</em> a <em>WLAN</em>-em zostanie
+          zestawiony to oba interfejsy zostaną połączone jednym wirtualnym,
+          który będzie obsługiwał połączenia z zupełnie różnych dwóch
+          warstw fizycznych.
+        </p>
+        <p>
+          Dostępność oraz sposób instalacji tych pakietów dla wybranych przez
+          nas dystrybucji (ze względu na ich róznorodność) należy ustalić we
+          własnym zakresie. Poniżej znajduje się polecenie dla dystrybucji
+          Debian oraz pokrewnych.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo apt install dnsmasq
+</pre>
+        <p>
+          To polecenie zainstaluje tylko jeden pakiet. Debian 11 jest
+          już rozprowadzany zainstalowanym pakietem zapory.
+        </p>
+        <h3 id="9.14.3.linuxrouterconfig">9.14.3. Konfiguracja dystrybucji jako router</h3>
+        <p>
+          Po złożeniu sprzętu oraz zainstalowaniu oprogramowania. Przyszedł
+          czas na jego konfigrację. Najlepiej rozpocząć ją (a wręcz trzeba) od
+          konfiguracji interfejsów. Musimy ustalić wykorzystywany przez nas
+          sposób łączenia z Internetem, czy posiadamy statyczny adres IP lub
+          interfejs jest konfigurowany dynamicznie przez naszego usługodawcę.
+          Te informacje musimy zapisać w charkterystyczny dla naszej
+          dystrybucji sposób konfiguracji interfejsów. Jeśli chcemy możemy
+          wykorzystać do tego celu <em>NetworkManager</em>. Pamietając, że
+          w przypadku Debiana interfejs wykorzystywany podczas instalacji
+          będzie kontrolowany przez system <em>ifupdown</em>, trzeba go 
+          stamtąd usunąć. Po skonfigurowaniu interfejsu łączącego z internetem
+          musimy skonfigurować interfejsy sieci LAN. Tutaj wystarczy sam adres
+          oraz maska podsieci. Adres ten musi być jednym z adresów
+          <strong>sieci prywatnych IPv4</strong>.
+        </p>
+        <h4>Sieci prywatne IPv4</h4>
+        <p>
+          Sieci prywatne to nic innego jak wycięte klasy adresowe
+          sieci IP w wersji 4. Te adresy mają zastosowanie jedynie w sieciach
+          lokalnych, ale i usługodawcy również mogą się nimi posługiwać,
+          ponieważ to co wpinamy w port WAN routera jest umowne i tak naprawdę
+          naszym WAN-em, może być sieć osiedlowa, która jest nieco wiekszym
+          LAN-em lub będąc bardziej szczegółowym siecią kampusową. Adresy sieci
+          prywatnych powstały ze względu na wyczerpywanie się adresów
+          publicznych. Można by się zastanowić nad tym w jaki sposób zabranie
+          prawie 18 milionów adresów, przyczniło się do tego, że sieci IPv4
+          jest na wyczerpaniu to nadal są przydzielane konkretne adresy. Otóż
+          adresy klas prywatnych nie mogą funkcjonowac w internecie, są tylko
+          do użytku wewnetrznego. Największa klasa A (posidająca grubo ponad
+          16 miliownów adresów) może być widoczna w internecie jako jeden adres.
+          Dzięki technologii translacji adresów (bardziej szczegółów informacje
+          na ten temat znajdują się poniżej).
+          Stąd taka optymalizacja. Dostępne mamy trzy klasy adresowe: 
+        </p>
+        <ul>
+          <li><strong>Klasa A</strong> - o masce 255.0.0.0, dającą 256^3 - 2
+            adresów w zakresie od 10.0.0.0 do 10.255.255.255.</li>
+          <li><strong>Klasa B</strong> - o masce 255.240.0.0, dająca
+            16*256^2 -2 adresów w zakresie od 172.16.0.0 do 172.31.255.255.</li>
+          <li><strong>Klasa C</strong> - o masce 255.255.0.0, dająca 256^2 - 2
+            adresów w zakresie od 192.168.0.0 do 192.168.255.255.</li>
+        </ul>
+        <p>
+          Gdzieś wśród młodych adeptów informatyki, wzięło się przeswiadczenie,
+          że klasy B oraz C są dużo mniejsze. Klasie B przypisywało się wówczas
+          maskę 16-bitową, odcinając wszystkie adresy powyżej 172.16.255.255.
+          A klasie C przypisywano maskę 24-bitową, przez co zmniejszano ją
+          do 254 adresów. Ten sposób adresacji wziął się z nie wiedzy osób
+          konfigurjących sprzęt oraz z narzucenia przez producentów domyślnie
+          takich wartości. Nie jest to błędem, ponieważ możemy alokować te
+          adresy odpowiednio do swoich potrzeb. Dlatego jeśli nie potrzebujemy
+          tak dużej sieci, to możemy ją zmniejszyć dzieląc te sieci na
+          podsieci i wykorzystując tylko jedną z nich.
+        </p>
+        <p>
+          Po konfiguracji interfejsów możemy przjeść do konfiguracji serwera
+          DHCP, który jest również serwerem buforująco-przekazujący systemu
+          DNS. Przyczym konfiguracja DNS-u nie wymaga od nas żadnej uwagi
+          <strong>dnsmasq</strong> zaraz po uruchomieniu zaczyna nasłuchiwać
+          na porcie 53/UDP. Naszym zadaniem będzie jedynie ograniczenie tego
+          nasłuchiwania do portów LAN. Dla przykładu żałożymy, że naszym
+          interfejsem LAN-u jest klasyczny port eth0. 
+        </p>
+<pre class="code-block">
+interface=eth0
+dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,12h
+dhcp-option=3,192.168.4.1
+dhcp-option=6,192.168.4.1
+</pre>
+        <p>
+          Pierwsza opcja <code class="code-inline">interface=eth0</code>
+          ogranicza działanie demona tylko i wyłącznie do interfejsu
+          <code class="code-inline">eth0</code>. Dzięki tej opcji nasłuchiwanie
+          na porcie 53/udp (DNS) zostanie ograniczone do wskazane interfejsu.
+          Pozostałe opcje konfigurją nam już serwer DHCP. Pierwsza opcja
+          <code class="code-inline">dhcp-range</code> definiuje nam zakres
+          przydzielanych adresów, maskę podsieci oraz czas dzierżawy. Następnie
+          zaczynają się typowe opcje protokołu DHCP, są one opisane w
+          standardzie, ale dla zachowania kontekstu przytocze je również tutaj
+          opcja <code class="code-inline">3</code> odpowiada za przypisanie
+          adresu domyślnej bramy, natomiast opcja
+          <code class="code-inline">6</code> odpowiada za przypisanie adresów
+          serwerów DNS. Adres bramy oraz adres serwera DNS wskazują na adres
+          portu LAN. Te cztery linie wystarczą aby skonfigurować serwer DNS i
+          DHCP dla naszej sieci. Teraz po podłączeniu komputera do routera
+          powinniśmy uzyskać adres IP wraz z pozostałymi paramerami 
+          pozwalającymi na połączenie z internet za pośrednictwem naszego
+          systemu.
+        </p>
+        <p>
+          Aby zrealizować połączenie z internetem hostów podłączanych do sieci
+          LAN musimy wykonać jescze dwie czynności. Umożliwić w systemie
+          przsyłanie pakietów między interfejsami, domyślnie jest ono 
+          wyłączone oraz włączyć funckję NAT-u.
+        </p>
+        <h4>NAT - Translacja adresów sieciowych</h4>
+        <p>
+          Translacja adresów potocznie zwana NAT-em, jest funkcja zapór
+          sieciowych, której zadaniem jest najczęściej zamiana adresów sieci
+          LAN, na adres sieci publicznej. Tak aby komputery mogły wysyłać oraz
+          odbierać dane z sieci rozległej nie będąc do niej bezpośrednio
+          podłączone. Istnieje kilka rodzajów translacji adresów nas będą
+          interesować tylko dwa. Przeznaczone dla ruchu wychodzącego (danych
+          generowanych przez komputery z sieci LAN). Do wybory wówczas mamy
+          <strong>SNAT</strong> - ang. <em>Source Network Address Translation</em>
+          lub <strong>MASQUERADE</strong>. Użycie SNAT-u będzie wymagać
+          podania adresu IP portu WAN, teoretycznie nic w tym złego, ale jeśli
+          nasz usługodawca automatycznie przypisuje swoim klientom adresy IP,
+          za każdą zmianą adresu na tym interfejsie połączenie z internetem
+          zostało by zerwane. Zatem SNAT jest szybszą metodą NAT-u, ale wymaga
+          stałego adresu IP. Jeśli takim nie władamy, pozostało nam tylko
+          użycie MASQUERADE, który pozwala na podanie interfejsu. Działanie
+          NAT-u opiera się na podstawieniu w miejscu adresu źródłowego pakietu
+          albo adresu podanego w regule (SNAT) albo adres interfejsu 
+          (MASQUERADE).
+        </p>
+        <p>
+          Za przekazywanie pakietów między interfejsami odpowiada jądro. Aby
+          je włączyć musimy skorzystać z interfejsu ukrytego za poleceniem
+          <strong>sysctl</strong>. Do konkretnych wartości prowadzi ścieżka,
+          której elementy są odzielone od siebie kropkami. Poniżej znajduje
+          sie polecenie, które odpowiada za przekazywanie pakietów miedzy
+          interfejsami.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo sysctl net.ipv4.ip_forward=1
+</pre>
+        <p>
+          Teraz pakiety będą swobodnie przekazywane między interfejsami. Tak
+          jak wspomniałem NAT jest funkcją zapory sieciowej. Tak więc
+          konfiguracja dystrybucji Linuksa jako router będzie wymagać jej
+          konfiguracji. Co prawda będzie to jedno polecenie, ale żeby nie
+          pozostawiać użytkownika w niewiedzy trzeba trochę przybliżyć temat
+          działania zapory jaką jest <strong>iptables</strong>.
+        </p>
+        <h4>Zapora sieciowa w systemie Linux</h4>
+        <p>
+          Zapora sieciowa w dystrybucjach Linux realizowana jest przez pakiet
+          <em>iptables</em>, jego zasada
+          działania opiera się o <strong>łańcuchy</strong> zasad pod kątem
+               których sprawdzany może być pakiet przychodzący, wychodzący a nawet
+          dodatkowo przekazywany dalej. Łańcuchy łączą się w tablice, które
+          mogą modyfikować moment konfrontacji pakiety z łańcuchem, ale ogólna
+          zasada pozostaje bez zmian. Każdy łańcuch posiada domyślną politykę,
+          która jest stosowana dla pakietów niepasujących do żadnej z reguł.
+          Domyślnie jest to polityka <em>przepuszczaj</em>, oznacza to swobodną
+          transmisję. Wśród najważniejszych tablic oraz łańcuchów możemy 
+          wyróżnić:
+        </p>
+        <ul>
+          <li><strong>filter</strong> - tablica zwierająca łańcuchy
+            sprawdzające pakiety, które są związane jakoś z docelowym 
+            komputerem, Ta tablica jest również domyślna i nie ma
+            potrzeby definiowania jest nazwy wśród niej możemy wyróżnić takie 
+            łańcuchy jak:
+          <ul>
+            <li><strong>INPUT</strong> - zawiera reguły filtrujące pakiety
+            przeznaczone dla lokalne hosta (tego komputera).</li>
+            <li><strong>OUTPUT</strong> - zawiera reguły filtrujące pakiety
+            wysyłane (jego połączenia) z tego komputera.<li>
+            <li><strong>FORWARD</strong> - zawiera reguły filtrujące pakiety
+            przesyłane przez ten komputer.</li>
+          </ul>
+          </li>
+          <li><strong>nat</strong> - tablica zawierająca łańcuchy, których
+            zadaniem jest modyfikacja przechodzących przez nią pakietów.
+            Np. łańcucha <em>PREROUTING</em> korzysta się do
+            <strong>port-forwardingu</strong>, czyli udostępniania połączeń
+            z internetu dla wybranych usług. Kluczowe łańcuchy tej tablicy
+            przetwarzają pakiety zaraz po pojawieniu się na interfejsie (tj.
+            bardzo wcześnie) lub zaraz przed jego opuszczeniem (tj. bardzo
+            późno). Będą przy tym pierwszymi oraz ostatnimi zestawiami reguł
+            przetwarzającymi pakiet. Wśród tej tablicy możemy wyróżnić takie
+            łańcuchy jak:
+          <ul>
+            <li><strong>PREROUTING</strong> - zawiera reguły filtrujące, które
+            najwcześniej przetwarzają pakiety. Ten łańcuchy wykorzystywany jest
+            w <em>port-forwarding</em>.</li>
+            <li><strong>OUTPUT</strong> - zawiera reguły filtrujące pakiety dla
+            wygenerowanych lokalnie pakietów, które poźniej będą wymagały
+            trasowania.<li>
+            <li><strong>POSTROUTING</strong> - zawiera reguły filtrujące, które
+            najpóźniej przetwarzają pakiety. Tutaj stosowany jest SNAT oraz
+            <em>maskarada</em>.</li>
+          </ul>
+          </li>
+        </ul>
+        <p>
+          <em>Iptables</em> konfrontując pakiet z łańcuchem zastosuję akcję
+          dla pierwszej reguły do której będzie pasować przetwarzany pakiet.
+          Natomiast możemy wyróżnić trzy rodzaje akcji podstawowych takich
+          jak:
+        </p>
+        <ul>
+          <li><strong>ACCEPT</strong> - przepuść pakiet do dalszego
+            przetwarzania</li>
+          <li><strong>DROP</strong> - odrzuć pakiet</li>
+          <li><strong>REJECT</strong> - odrzuć pakiet, ale poinformuj nadawcę
+            o takiej sytuacji</li>
+        </ul>
+        <p>
+          Istnieją także dodatkowe akcje specyficzne dla tablicy. Przeważnie
+          po podaniu akcji w tablicy <em>filter</em> reguła się kończy. W
+          przypadku akcji <em>SNAT</em> oraz <em>DNAT</em> tablicy <em>nat</em>
+          wymagane jest podanie docelowego adresu IP. Akcją bez argumentów dla
+          tej tablicy jest <em>MASQUERADE</em> uruchamiające maskaradę.
+        </p>
+        <p>
+          Z powyższego wywodu możemy wywnioskować, że aby uruchomić NAT na
+          naszym routerze musimy zapisać regułę tablicy <em>nat</em> w łańcuchu
+          <em>POSTROUTING</em>. Więc tak, tablicę wskazujemy z pomoca opcji
+          <em>-t</em>, teraz w zależności od tego czy chcemy wstawić w
+          konkretną linią naszą regułę czy ją dopisać musimy użyć innych opcji.
+          Opcja <em>-I</em> odpowiedzialną za wstawianie (<em>INSERT</em>)
+          wymaga po podaniu nazwy łańcucha numeru linii, w którą ma wstawić
+          daną regułem, natomiast opcja <em>-A</em> odpowiedzialna za
+          dopisanie (<em>APPEND</em>). Ze względu na to, że jest to łańcuch 
+          <em>POSTROUTING</em>, to raczej będzie on pusty, więc nie będzie
+          to miało znaczenia czy użyjemy dopisania czy wstawienia. Drugą rzeczą
+          jest wskazanie interfejsu, na którym interfejsy będą wymagały NAT-u,
+          aby transmisja miała sens. W przypadku wyjściowych łańcuchów takich
+          jak <em>POSTROUTING</em> czy <em>OUTPUT</em> interfejs podwany jest
+          po opcji <em>-o</em> (nazywane jest kierunkien od 
+          <em>in</em>/<em>out</em>, jednak łańcuchy mają już zdefiniowane
+          możliwe kierunki transmisji) następnie po opcji <em>-j</em> podawana
+          akcja, zawsze wieliki literami. Więc nasza reguła uruchamiająca NAT
+          prezentuje się następująco. W przypadku tego oraz poniższych
+          przykładów dotyczących zapory sieciowej interfejsem przeznaczonym do
+          połączenia z siecią WAN będzie <em>eth1</em>.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
+</pre>
+        <p>
+          Teraz o ile komputery podłaczone do interfejsu <em>LAN</em> posiadają
+          prawidłowe adresy IP, powinny mieć już połączenie z Internetem.
+          Mimo, że wszystko funkcjonuje prawidłowo to pozostawienie tak
+          podłączonego routera do Internetu pozostawia wiele do życzenia.
+          Pierwszym rażącym zaniedbanie jest fakt iż router będzie przyjmował
+          połączenia z internetu, z każdym dowolnym portem, w ramach lepszego
+          poznania pakietu <em>firewall</em>-a na Linuksie możemy nieco
+          bardziej zabezpieczyć naszą transmisję.
+        </p>
+        <p>
+          Jak zapewne pamiętamy, każdy łańcuch posiada swoją politykę, która
+          jest stosowana dla każdego pakietu, które nie zostanie przypasowana
+          żadna reguła. Moglibyśmy ustawić ją na odrzucanie i dopuścić tylko
+          potrzebny ruch. To dobry pomysł szczególnie jeśli myślimy o
+          interfejsie WAN, ale zły jeśli pomyślimy interfejsie LAN. Ponieważ
+          możemy zdefiniować polityki <em>per</em> interfejs, ten pomysł
+          odpada, ponieważ dla interfejsu LAN musiała by powstać długa lista
+          reguł dopuszczająca ruch do wszystkie bardziej oraz mniej znanych 
+          usług. Dlatego też pozostawimy politykę bez zmian i dopuścimy tylko
+          niezbędny ruch. Na pewno z internetu musimy przyjąć dane od serwera
+          DNS, aby rozwiązywać dotąd nieznane nazwy oraz w zależności
+          konfiguracji interfejsu WAN dane z serwera DHCP usługodawcy. Łańcuch
+          INPUT będziemy konfigurować dodają na początku reguły zezwalające na
+          ruch, żeby następnie zablokować pozostały nieokreślony regułami.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo iptables -A INPUT -i eth1 -p udp --sport 53 -j ACCEPT
+#Opcjonalnie:
+xf0r3m@immudex:~$ sudo iptables -A INPUT -i eth1 -p udp --sport 67 -j ACCEPT
+#Zablokowanie pozostałego ruchu
+xf0r3m@immudex:~$ sudo iptables -A INPUT -i eth1 -p udp -j DROP;
+xf0r3m@immudex:~$ sudo iptables -A INPUT -i eth1 -p tcp --syn -j DROP;
+</pre>
+        <p>
+          Dwie pierwsze reguły dopusczają ruch z sieci WAN (interfejs eth1) na
+          porcie 53/udp (serwer systemu DNS) oraz 67/udp (serwer DHCP).
+          Pozostały ruch protokołu UDP został zablokowany. Podobnie jest z
+          całym ruchem na protokole TCP, tutaj dodano także modyfikator
+          <code class="code-inline">--syn</code>. Jak wspominałem omawiając
+          protokół TCP, musi on zestawić połączenie, aby rozpocząć transmisje
+          co wymaga wysłania kilku pakietów sterujących. Pakiet wysyłany aby
+          zainicjować zestawienie połączenia TCP posiada własnie ustawioną
+          flagę SYN (pakiety TCP posiadają specjalne miejsce na flagi).
+          I tego typu pakiety są właśnie blokowane. To rozwiązanie skutecznie
+          zablokuje próbę połączenia, ale prawdopodbnie nie uchroni przed
+          metodą rozpoznawczą jaką jest skanowanie portów. Należało by tutaj
+          zamiast flagi, stanów połączenia.
+        </p>
+        <p>
+          Ze względu na to, iż zapora na Linuksie to temat rzeka. 
+          Małe ćwiczenie. Usprawnienie tej ostatniej reguły, takby aby 
+          opierała się na stanach TCP. (Podpowiedź: Zablokowanie ma służyć
+          nawiązywaniu nowych połączeń z naszym routerem. Transmisja
+          przez hosty w sieci, ktore łączy nasz routera powina przebiegać bez
+          zarzutu).
+        </p>
+        <p>
+          <em>Iptables</em> nie jest bez wad jedną z nich jest utrzymanie
+          reguł w łańuchach do momentu wyłączenia systemu. Dlatego
+          systemy, w których instalowany jest ten pakiet dostępny jest też
+          pakiet odpowiadający za zapisanie reguł w pliku i przywrócenie ich
+          w momencie startu systemu. Pakiet nazywa się 
+          <em>iptables-persistent</em> dostępny jest w repozytoriach Debiana.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo apt install iptables-persistent
+</pre>
+        <p>
+          Zapisanie reguł odbywać się będzie za wydaniem poniższego polecenia.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo iptables-persistent save
+</pre>
+        <p>
+          Teraz router jest skonfigurowany i gotowy do działania. Routery
+          programowe mają to do siebie, że ich funkcjonalność można
+          rozszerzyć np. o serwer plików. Konfiguracje takiego serwera plików
+          będziemy jeszcze omawiać w tym materiale. Także będziemy jeszcze
+          wracać do naszego routera.
+        </p>
+        <p>
+          Kolejną kwestią jest komunikacja między sieciami. Jeśli nasz router
+          łączy ze sobą więcej niż jedną sieć lokalną i ich komputery mają się
+          ze sobą komunikowac to należy utworzyć statyczne trasy, wskazujące
+          przez, który interfejs należy komunikować się z daną siecią.
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo ip route add 192.168.1.0/24 via 192.168.1.1 dev eth2
+xf0r3m@immudex:~$ sudo ip route add 192.168.4.0/24 via 192.168.4.1 dev eth0
+</pre>
+        <p>
+          Trasy te mogą zostać utworzone automatycznie jeśli np. interfejs
+          sieci WAN zostanie podniesiony podczas automatycznej konfiguracji.
+          Jeśli takie zachowanie nie jest przez nas porządane to w najlepszym
+          wypadku jest zablokować transmisję między sieciami na 
+          <em>firewall</em>-u. Ninejszym temat konfigruacji routera uważam
+          za zakończony. Nie mniej jednak to nie koniec rodziału. Zostały
+          jeszcze dwa tematy do omówienia.
+        </p>
+        <h2 id="9.15.ipoverethernet">9.15. Sieci IP oparte na Ethernet. Protokół ARP i NDP</h2>
+        <p>
+          Mając na uwadzę to, że chcąc wysłać jakieś dane musimy podać adres
+          hosta docelowego. Zazwyczaj takim adresem jest albo adres IP albo 
+          nazwa domenowa. Te piewsze wykorzystywane są głównie w sieciach
+          lokalnych przez specjalistów. Zatem podając nazwę domenową aplikacja
+          musi rozwiązać ją na adres IP i dokonuje tego za pomoca systemu DNS.
+          To dzieje się w warstwie aplikacji. Warstwa transportowa definiuje
+          port oraz rodzaj transmisji dla wysłanych danych. Najczęściej są
+          to znane protokoły jak HTTPS, protokoły przesyłania strumieniowego
+          oraz protokoły poczty. Warstwa sieciowa posiada już adres IP hosta
+          docelowego i bez względu na to czy host docelowy znajduje się w tej 
+          samej sieci czy nie, pakiet przekazywany jest dalej i tutaj pozostaje
+          nam pewna nie wiadoma, skąd host źródłowy wie jakim adresem MAC 
+          ma zaadresować ramkę <em>ethernet</em>? 
+        </p>
+        <p>
+          Tutaj pojawia się protokoły <strong>ARP</strong> oraz RARP. Ten 
+          drugi jest może mniej wykorzystywany. Ich zadaniem jest zamiana
+          adresów IP na MAC i odwrotnie. Głownie chodzi tu o protokół ARP i
+          to nanim się się skupimy. Informacje na temat adresów MAC hostów
+          w sieci przechowywane są w tablicy lub w buforze ARP. Jednak co jeśli
+          tablica jest pusta? Wówczas protokół ARP dla docelowego adresu IP
+          tworzy ramkę z żądaniem ARP. Taka ramka rozsyłana jest w całej sieci.
+          Jeśli jeden ze znajdujących się w niej hostów posiada adres MAC dla
+          adresu IP z żądania wówczas odsyłana jest odpowiedź. Nasz host na
+          podstawie odpowiedzi uzpełnia swoją tablicę o ten wpis wówczas może
+          on rozpocząć transmisję.  Dostęp do tablicy w dystrybucjach Linuksa
+          odbywa się z pomocą: 
+        </p>
+<pre class="code-block">
+xf0r3m@immudex:~$  sudo ip -4 neigh
+172.16.2.20 dev enp4s0 lladdr 74:27:ea:e9:cc:14 STALE
+172.16.7.6 dev enp4s0 lladdr 70:85:c2:a4:bf:b9 STALE
+172.16.8.2 dev enp4s0 lladdr 6c:4b:90:be:91:74 STALE
+172.16.6.1 dev enp4s0 lladdr 78:45:c4:12:6a:5d STALE
+172.16.2.100 dev enp4s0 lladdr 3c:84:6a:44:d7:a4 STALE
+172.16.2.46 dev enp4s0 lladdr 74:27:ea:ea:98:8a STALE
+172.16.17.15 dev enp4s0 lladdr 78:45:c4:09:23:4c STALE
+172.16.2.146 dev enp4s0 lladdr 1c:69:7a:cd:f4:cb STALE
+172.16.2.119 dev enp4s0 lladdr 74:27:ea:ea:63:56 STALE
+172.16.8.13 dev enp4s0 lladdr 6c:4b:90:be:88:16 STALE
+172.16.0.1 dev enp4s0 lladdr 90:e2:ba:45:4f:8c REACHABLE
+...
+</pre>
+        <p>
+          Wpisy w tablicy same ulegją usunięciu jeśli nie nastąpiła aktywność
+          przez pewien czas. Nie mniej jednak istnieje możliwość ręcznego
+          usunięcia wpisów za pomocą polecenia:
+        </p> 
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo ip neigh del 172.16.8.13 dev enp4s0
+</pre>
+        <p>
+          Efektem działania tego polecenia będzie usunięcie wpisu dotyczączego
+          host <code class="code-inline">172.16.8.13</code>.
+        </p> 
+        <p>
+          Protokołem o działaniu udwrotnym jest <strong>RARP</strong>, jego
+          zadaniem była zamiana adresów MAC na adresy IP, przez co
+          wykrzystywany był do automatycznej konfiguracji hosta, przed
+          upowszechnieniem się protokołu DHCP. Obecnie jest już rzadko
+          spotykany.
+        </p>
+        <p>
+          Za pomocą podpolecenia <em>neigh</em> polecenia <em>ip</em> mogliśmy
+          sprawdzić tablicę ARP w systemie. Kiedyś używano do tego polecenia
+          <em>arp</em>. Obecnie doszło do unifikacji przez narzędzie 
+          <em>ip</em> obsługi protokołu ARP dla IPv4 oraz protokołu NDP dla
+          IPv6. NDP jest podobny rozwiązaniem dla IPv6. Jego działanie opiera
+          na dwóch rodzajach komunikatów:
+        </p>
+        <ul>
+          <li><strong>Poszukiwanie adresu</strong> - pakiet tego rodzaju służy
+            do uzyskania informacji o sieci lokalnej hosta wraz z adresem MAC.</li>
+          <li><strong>Ogłaszenie adresu</strong> - pakiet z odpowiedzią wraz
+            z żądanymi informacjami.</li>
+        </ul>
+        <h2 id="9.16.wirelesslan">9.16. Sieć bezprzewodowa</h2>
+        <p>
+          Logiczna konstrukcja sieci bezprzewodowej, nieco rózni się
+          od połączeń kablowych kilkoma charakterystycznymi elementami w 
+          warstwie fizycznej. Sieci bezprzewodowe definiowane są przy użyciu
+          standardu <strong>802.11</strong> i jego poszczególnych odmian
+          (np. 802.11a lub 802.11n)
+          Poniżej opiszemy sobie cechy charakterystyczne, z którymi będziemy
+          mieć styczność podczas konfiguracji sieci bezprzewodowej.
+        </p>
+        <ul>
+          <li><strong>Identyfikator/Nazwa sieci/ESSID</strong> jest ciąg
+            znaków jednoznacznie określający sieć. Każda sieć bezprzewodowa
+            go posiada. Jest on niezbedny do połączenia.</li>
+          <li><strong>Dane autoryzacyjne</strong> sieci bezprzewodowe, mogą
+            zostać zabezpieczone za pomocą funkcji kryptograficznych 
+            (zaszyfrowane), aby osoby nie będące jej częścią nie mogły
+            się podłączyć lub 
+            przechwycić przesyłanych przez nie danych. Najczęsciej jest hasło,
+            chociaż, czasami też stoswane są PIN-y (w przypadku funkcji WPS)
+            lub dane logowania (w przypadku sieci korporacyjnych).</li>
+          <li><strong>Częstotliwość</strong> - fragment pasma częstotliwości
+            radiowej, na której możliwa jest wymiana informacji w obrębie danej
+            sieci bezprzewodowej. Bezprzewodowe sieci komputerowe operują
+            najczęściej na częstotliwości 2,4GHz lub 5GHz. Każda sieć ma
+            do dyspozycji tylko fragment pasma powyższych częstotliwości.</li>
+          <li><strong>Kanał</strong> - kanał jest powiązany z częstotliwością
+            Kanał określa konkretną częstotliwość dla pasma np. 2,4GHz.
+            Jeśli nasza sieć ma nadawać na pierwszym kanale (Kanał/CH 1,
+            oznaczenia są różne) to znaczy że będzie nadawać na częstotliwości
+            2412MHz.</li>
+        </ul>
+        <p>
+          Oczywiście cech charakterystycznych jest jescze więcej. Nie 
+          opisywałem tutaj siły sygnału. To chyba każdy rozumie. My tutaj
+          skupimy się głownie na podłączaniu się do sieci i to najlepiej za
+          pomocą terminala. Opcji jest kilka.
+        </p>
+        <ul>
+          <li><strong>NetworkManager</strong>. Do przyłączenia się do sieci
+            bezprzewodowej możemy wykorzystać dobrze znany nam już menedżer.
+            Za pomocą komend polecenia <em>nmcli</em> możemy wyświetlić sobie
+            listę dostępnych sieci i następnie się do niej podłączyć. Poniżej
+            znajdują się polecenia, dzięki którym możemym wykorzystać ten
+            menedżer do podłączenia do sieci.
+<pre class="code-block">
+xf0r3m@immudex:~$ nmcli device wifi list
+*  SSID               MODE    CHAN  RATE       SIGNAL  BARS  SECURITY
+   netdatacomm_local  Infra   6     54 Mbit/s  37      ▂▄__  WEP
+*  F1                 Infra   11    54 Mbit/s  98      ▂▄▆█  WPA1
+   LoremCorp          Infra   1     54 Mbit/s  62      ▂▄▆_  WPA2 802.1X
+   Internet           Infra   6     54 Mbit/s  29      ▂___  WPA1
+xf0r3m@immudex:~$ nmcli device wifi connect "F1" password "p4ssw0rd"
+#lub
+xf0r3m@immudex:~$ nmcli --ask device wifi connect "F1"
+xf0r3m@immudex:~$ nmcli -p -f general,wifi-properties device show wlan0
+</pre>
+            Można użyć modyfikatora <code class="code-inline">--ask</code>
+            zamiast wpisywać hasło w poleceniu. Ostatnie polecenie zwraca
+            podstawowe informacje na temat interejsu oraz samej sieci. 
+        </li>
+          <li><strong>iwd</strong>, jest menedżer sieci bezprzewodywych stworzony
+            przez firmę Intel. Jego obsługa jest interaktywna i opiera sie na
+            wydaniu kilku poleceń. W przeciwieństwie do <em>NetworkManagera</em>
+            (który może być już zainstalowany w wielu dystrybucjach) trzeba go
+            zainstalować. Pomoc dostępna jest wewnąrz narzędzia po jego
+            uruchomieniu. Uruchomienie odbywa się poprzez wydanie polecenia:
+<pre class="code-block">
+xf0r3m@immudex:~$ iwctl
+[iwd]# help
+[iwd]# device list
+[iwd]# station wlp1s0 scan
+[iwd]# station wlp1s0 get-networks
+[iwd]# station wlp1s0 connect SSID
+</pre>
+            Ten program wymaga nieco więcej poleceń. Ostanie poleceń, jeśli
+            połączenie tego będzie wymagać zapyta o hasło. (Więcej informacji
+            na <a href="https://wiki.archlinux.org/title/iwd">https://wiki.archlinux.org/title/iwd</a>)
+          </li>
+          <li><strong>wireless-tools</strong> - Pakiet. Konfiguracja ręczna.
+            Ten sposób jest najdłuższy, ale zadziała na każdej dystrybucji.
+            Składa się on z klasycznego interfejsu <em>iwconfig</em> oraz
+            programu <strong>wpa_supplicant</strong> służącego do łączenia się
+            sieciami wykorzystującymi mechanizm bezpieczeństwa WPA. Chcąc
+            znaleźć sieć, do której chcemy się podłaczyć musimy skorzystać z
+            polecenia <em>iwlist</em>, który wyświetli nam raport ze skanowania
+            z znalezionymi sieciami oraz ich parametrami. Te informacje są
+            trochę nieczytelne, ale nam potrzebny jest jedynie ESSID
+            (nazwa sieci) oraz sam fakt jej obecnosci. Po uzyskaniu tych
+            informacji musimy utworzyć plik zawierający <em>profil</em> sieci
+            posiłkując się poleceniem <em>wpa_passphrase</em>. Czasami może
+            być wymagane dodanie kilku opcji, ale przedstawie to na liście
+            poleceń. Następnie należy uruchomić polecenie 
+            <em>wpa_supplicant</em> z odpowiednimi przełącznikami oraz opcjami
+            a na sam koniec należy pobrać adresy IP. Jeśli zestawienie
+            połączenie niedochodzi do skuktu to może oznaczać, że uruchomiony
+            jest już demon, którego to my mieliśmy uruchamiać. Można wówczas
+            wyłączyć jednostkę i zabić wszystkie pozostałe procesy związane
+            z <em>wpa_supplicant</em>, a następnie spróbować ponownie. Jednak
+            tutaj mała wskazówka. W raz z obecnością działającego demona
+            wpa_supplicant w systemie dostępne jest polecenie 
+            <strong>wpa_cli</strong>, które umożliwia nam podłączenie za
+            pomocą interaktywnego interfejsu. Nie mniej jednak próba reczenego
+            podłączenia się do sieci bezprzewodowej wygląda następująco.
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo iwlist wlp1s0 scan
+xf0r3m@immudex:~$ wpa_passphrase "F1" 'p4ssw0rd' &gt;&gt; f1_wlan.conf
+#lub
+xf0r3m@immudex:~$ echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" | tee f1_wlan.conf
+xf0r3m@immudex:~$ echo "update_config=1" | tee -a f1_wlan.conf
+xf0r3m@immudex:~$ echo "country=PL" | tee -a f1_wlan.conf
+xf0r3m@immudex:~$ wpa_passphrase "F1" 'p4ssw0rd' | tee -a f1_wlan.conf
+xf0r3m@immudex:~$ sudo systemctl stop wpa_supplicant.service
+xf0r3m@immudex:~$ sudo kill -9 $(ps -aux | grep '^root.*wpa_supplicant' | awk '{printf %2" "}')
+xf0r3m@immudex:~$ sudo wpa_supplicant -B -Dwext -iwlp1s0 -cf1_wlan.conf
+xf0r3m@immudex:~$ sudo dhclient
+</pre>
+            Jak możemy zauważyć proces jest nieco bardziej złożony, ale jest
+            to ręczna metoda. Z racji tego iż opisałem główny proces powyżej
+            tutaj skupię się na kilku szczegółach. Program
+            <code class="code-inline">wpa_passphrase</code> tworzy tak zwany
+            <em>blok sieci</em> w nim zawarta jest nazwa sieci oraz klucz PSK
+            (hasło do sieci). Mimo tego my podajemy ten plik jako plik
+            konfiguracyjny <em>wpa_supplicant</em> i w niektórych przypadkach
+            nie jest wystarczająca konfiguracja. Dlatego też podaje się
+            takie informacje jak lokalizacja interfejsu sterowania 
+            wpa_supplicant 
+            (<code class="code-inline">ctrl_interface=DIR=/var/run/wpa_supplicant</code>),
+            grupa użytkowników, którzy mogą sterować <em>wpa_supplicant</em>
+            (<code class="code-inline">GROUP=netdev</code>), zezwolenie na
+            możliwość modyfikacji konfiguracji
+            (<code class="code-inline">update_config=1</code>) oraz kod ISO
+            kraju w którym działa odbiornik
+            (<code class="code-inline">country=PL</code>). Kod kraju jest o
+            o tyle istotny, że każdy kraj posiada swoje regulacje prawne
+            odnośnie wykorzystania częstotliwości radiowych, które są
+            wykorzystywane przez sieci bezprzewodowe. Na przykład w Polsce
+            dostępnych jest 13 kanałów a w USA tylko 11. A to są tylko kanały
+            większość krajów reguluje również moc nadawczą. Więc manipulacja
+            kodem kraju może wpłynąć na siłę sygnału i poprawić jakość
+            połączenia. Kolejną rzeczą jest działanie już <em>wpa_supplicant</em>
+            w systemie. Ten program może działać jako usługa. Dzięki czemu
+            możemy zapisać <em>bloki sieci</em> w ogólnym pliku konfiguracjnym.
+            Wówczas powoduje to, że jeśli komputer z włączony demon znajdzie
+            się w zasięgu sieci, zostanie z nią połączony. W przypadku kiedy
+            łaczność ma być wykonywana na żadanie użytkownika działanie demona
+            nie jest pożądane. Dlatego demona należy wyłączyć, ale mimo jego
+            wyłączenia nadal może pozostawać proces, który bedzie blokował
+            próbę podłączenia się. Dlatego też ważne jest aby pozbyć się
+            tego procesu i za to odpowiada polecenie
+            (<code class="code-inline">kill</code>) w podstawieniu polecenia
+            uzyskujemy PID tego procesu. Uruchomienie polecenia
+            <em>wpa_supplicant</em> wymaga kilku opcji. Opcja
+            <code class="code-inline">-B</code> uruchamia narzędzie w tle,
+            opcja <code class="code-inline">-D</code> wraz z wartością
+            <code class="code-inline">wext</code> jest to wskazanie sterownika
+            odpowiedzialnego za obsługę sieci bezprzewodowej, dostępnych jest
+            ich kilka, <code class="code-inline">wext</code> jest rozwiązaniem
+            przestarzałym niemniej jednak cechuje się obsługa przez bardzo
+            wiele układów kart bezprzewodowych na rynku. Następnie po opcji
+            <code class="code-inline">-i</code> podaje się interfejs sieciowy,
+            ostatnią opcją jest <code class="code-inline">-c</code>, która
+            wskazuje na plik konfiguracyjny. Zwróćmy uwagę na to, iż opcję
+            wraz z wartościami zapisujemy łącznie.
+            Inną opcją skorzystania z tego
+            pakietu jest wykorzytanie narzędzia <strong>wpa_cli</strong>.
+            Poniżej znajduje się lista polecenie, jakich należy użyć. Użycie
+            <em>wpa_cli</em> wymaga działania demona <em>wpa_supplicant</em>.
+<pre class="code-block">
+xf0r3m@immudex:~$ sudo wpa_cli
+&gt; scan
+&gt; scan_results
+#tu_wyswietli_sie_lista_znalezionych_sieci
+&gt; add_network
+#tu_wyswietli_sie_id_sieci_wazne_bo_sluzy_do_odlowania_sie_do_sieci
+&gt; set_network 0 ssid "nazwa_sieci/ESSID"
+&gt; set_network 0 psk "haslo/PSK"
+&gt; enable_network 0
+#tu_wyswietli_sie_informacja_o_podlaczaeniu_do_sieci
+&gt; save_config
+&gt; quit
+</pre> 
+           Jeśli nie chcemy aby połączenie zostało zapisane dołączenia
+           do łączenia automatycznego to należy pominąć przedostatnią opcję.
+          </li>
+        </ul>
+        <p>
+          Na konfiguracji narzędzia <em>wpa_suplicant</em> zakończymy temat
+          konfiguracji sieci w Linuks. Jednak to nie koniec tematów 
+          sieciowych ponieważ następne dwa rozdziały będą na niej bazować.
+        </p>
+      </div>
+                       <p style="margin: 15px; padding: 0; outline: 0;">
+                               2022; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/RedHat_-_RHCSA.html b/articles/terminallog/RedHat_-_RHCSA.html
new file mode 100755 (executable)
index 0000000..d77a9e0
--- /dev/null
@@ -0,0 +1,17663 @@
+<!DOCTYPE html>
+<html>
+  <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="/style.css">
+               <style>
+                       .code-block {
+                               text-align: left;
+                       }
+                       ul {
+                               text-align: left;
+                       }
+      p {
+        text-align: justify;
+      }
+      .exam_tip {
+        border: solid 1px black;
+      }
+      body {
+        width: 99%;
+        height: 100vh;
+      }
+      .main {
+        width: 100%;
+      }
+               </style>
+       </head>
+       <body>
+               <div class="main">
+    <div id="tableOfContent">
+      <h1>Red Hat Enterprise Linux 9 - Red Hat Certified System Administrator</h1>
+      <ul class="toc">
+        <li><a href="#1.introduction">1. Wstęp</a>
+          <ul class="toc">
+            <li><a href="#1.1.exam">1.1. Egzamin</a></li>
+            <li><a href="#1.2.examobjectives">1.2. Zagadnienia</a></li>
+            <li><a href="#1.3.exampreparation">1.3. Przygotowania</a>
+              <ul class="toc">
+                <li><a href="#1.3.1.vboxinstallationonrhel">1.3.1. Instalacja Oracle VirtualBox na RHEL 9.0</a></li>
+                <li><a href="#1.3.2.gettingrheliso">1.3.2. Pozyskanie obrazu ISO z Red Hat Enterprise Linux 9</a></li>
+                <li><a href="#1.3.3.createvmwithrhel">1.3.3. Tworzenie maszyn wirtualnych z RHEL</a></li>
+                <li><a href="#1.3.4.rhelinstallation">1.3.4. Instalacja Red Hat Enterprise Linux 9.0</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec1.1">Ćwiczenie 1: Instalacja Red Hat Enterprise Linux 9</a></li>
+            <li><a href="#exec1.2">Ćwiczenie 2: Logowanie zdalne do RHEL</a></li>
+            <li><a href="#ch1summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#2.firststepsinRHEL9">2. Poruszenia się po systemie RHEL 9</a> 
+          <ul class="toc">
+            <li><a href="#2.1.serverwithgui">2.1. Środowisko graficzne RHEL 9</a></li>
+            <li><a href="#2.2.hfs">2.2. Struktura katalogowa w Uniksach</a></li>
+            <li><a href="#2.3.usingcli">2.3. Obsługa wiersza poleceń i najprostsze polecenia</a>
+              <ul class="toc">
+                <li><a href="#2.3.1.ls">2.3.1. Listowanie zawartości katalogu</a></li>
+                <li><a href="#2.3.2.pwd">2.3.2. Wyświetlenie bieżącego katalogu roboczego</a></li>
+                <li><a href="#2.3.3.cd">2.3.3. Poruszanie się wśrod katalogów</a></li>
+                <li><a href="#2.3.4.tty">2.3.4. Identyfikacja urządzenia terminala</a></li>
+                <li><a href="#2.3.5.uptime">2.3.5. Czas systemowy oraz załadowanie procesora</a></li>
+                <li><a href="#2.3.6.clear">2.3.6. Czyszczenie ekranu powłoki</a></li>
+                <li><a href="#2.3.7.which">2.3.7. Określanie ścieżki polecenia</a></li>
+                <li><a href="#2.3.8.uname">2.3.8. Wyświetlenie informacji o systemie</a></li>
+                <li><a href="#2.3.9.lscpu">2.3.9. Wyświetlanie informacji o procesorze</a></li>
+              </ul>
+            </li>
+            <li><a href="#2.4.gettinghelp">2.4. Uzyskiwanie pomocy</a>
+              <ul class="toc">
+                <li><a href="#2.4.1.manpages">2.4.1. Strony podręcznika</a></li>
+                <li><a href="#2.4.2.helpincommand">2.4.2. Pomoc w samym poleceniu</a></li>
+                <li><a href="#2.4.3.texinfo">2.4.3. Dokumentacja texinfo</a></li>
+                <li><a href="#2.4.4.usrsharedoc">2.4.4. /usr/share/doc</a></li>
+                <li><a href="#2.4.5.rhdocs">2.4.5. Dokumentacja Red Hat Enterprise Linux</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec2.1">Ćwiczenie 1: Nawigacja pośród katalogów Linuksa</a></li>
+            <li><a href="#exec2.2">Ćwiczenie 2: Rożne zadania</a></li>
+            <li><a href="#exec2.3">Ćwiczenie 3: Informacje o systemie</a></li>
+            <li><a href="#exec2.4">Ćwiczenie 4: Używanie pomocy</a></li>
+            <li><a href="#ch2summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#3.fileoperations">3. Operacje na plikach</a>
+          <ul class="toc">
+            <li><a href="#3.1.filetypes">3.1. Rodzaje plików</a></li>
+            <li><a href="#3.2.compressionandarchiving">3.2. Kompresja i archiwizowanie</a>
+              <ul class="toc">
+                <li><a href="#3.2.1.gzip">3.2.1. gzip</a></li>
+                <li><a href="#3.2.2.bzip">3.2.2. bzip2</a></li>
+                <li><a href="#3.2.3.tar">3.2.3. tar</a></li>
+              </ul>
+            </li>
+            <li><a href="#3.3.vim">3.3. Edycja plików za pomocą edytora Vim</a>
+              <ul class="toc">
+                <li><a href="#3.3.1.startingvim">3.3.1. Podstawy obsługi Vim</a></li>
+                <li><a href="#3.3.2.othervimcommands">3.3.2. Pozostałe polecenia Vim</a></li>
+              </ul>
+            </li>
+            <li><a href="#3.4.filesanddirectories">3.4. Pliki i katalogi</a>
+              <ul class="toc">
+                <li><a href="#3.4.1.createfilesanddirs">3.4.1. Tworzenie plików i katalogów</a></li>
+                <li><a href="#3.4.2.listingfiles">3.4.2. Wyświetlanie zawartości pliku</a></li>
+                <li><a href="#3.4.3.copyingandmoving">3.4.3. Kopiowanie i przenoszenie plików i katalogów</a></li>
+                <li><a href="#3.4.4.removefilesanddirs">3.4.4. Usuwanie plików i katalogów</a></li>
+              </ul>
+            </li>
+            <li><a href="#3.5.links">3.5. Dowiązania</a>
+              <ul class="toc">
+                <li><a href="#3.5.1.hardlinks">3.5.1. Dowiązania twarde</a></li>
+                <li><a href="#3.5.2.symlinks">3.5.2. Dowiązania symboliczne</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec3.1">Ćwiczenie 1: Archiwa</a></li>
+            <li><a href="#exec3.2">Ćwiczenie 2: Praktyka z Vim-a</a></li>
+            <li><a href="#exec3.3">Ćwiczenia 3: Manipulacja plikami</a></li>
+            <li><a href="#ch3summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#4.advancedfilemanagement">4. Zaawansowane zarządzanie plikami</a> 
+          <ul class="toc">
+            <li><a href="#4.1.basicspermission">4.1. Uprawnienia podstawowe</a>
+              <ul class="toc">
+                <li><a href="#4.1.1.defaultpermissions">4.1.1. Uprawnienia domyślne</a></li>
+                <li><a href="#4.1.2.changefileowner">4.1.2. Zmiana właściciela oraz grupy pliku</a></li>
+              </ul>
+            </li>
+            <li><a href="#4.2.specialpermissions">4.2. Uprawnienia specjalne</a>
+              <ul class="toc">
+                <li><a href="#4.2.1.setuid">4.2.1. Uprawnienia bitu setuid</a></li>
+                <li><a href="#4.2.2.setgid">4.2.2. Uprawnienia bitu setgid</a></li>
+                <li><a href="#4.2.3.stickybit">4.2.3. Uprawnienia bitu sticky</a></li>
+              </ul>
+            </li>
+            <li><a href="#4.3.find">4.3. Polecenie find</a>
+              <ul class="toc">
+                <li><a href="#4.3.1.actionoptions">4.3.1. Opcje akcji polecenia find</a></li>
+              </ul>
+            </li>
+            <li><a href="#4.4.acl">4.4. Lista kontroli dostępu</a>
+              <ul class="toc">
+                <li><a href="#4.4.1.defaultacl">4.4.1. Domyślne listy kontroli dostępu</a></li>
+                <li><a href="#4.4.2.aclbug">4.4.2. Dziwny problem z listami kontroli dostępu</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec4.1">Ćwiczenie 1: Manipulowanie uprawnieniami pliku</a></li>
+            <li><a href="#exec4.2">Ćwiczenie 2: Konfiguracja katalogu do pracy grupowej</a></li>
+            <li><a href="#exec4.3">Ćwiczenie 3: Wyszukiwanie plików</a></li>
+            <li><a href="#exec4.4">Ćwiczenie 4: Zaawansowane wyszukiwanie plików</a></li>
+            <li><a href="#exec4.5">Ćwiczenie 5: Ustawianie list dostępu</a></li>
+            <li><a href="#ch4summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#5.userbasics">5. Podstawy zarządzania użytkownikami</a>
+          <ul class="toc">
+            <li><a href="#5.1.whoandw">5.1. Kto jest zalogowany do systemu i co robi</a>
+              <ul class="toc">
+                <li><a href="#5.1.1.loginattempts">5.1.1. Monitorowanie prób logowania się do systemu</a></li>
+                <li><a href="#5.1.2.idandgroup">5.1.2. Informacje o użytkowniku</a></li>
+              </ul>
+            </li>
+            <li><a href="#5.2.userauthfiles">5.2. Pliki autentykacji użytkowników</a>
+              <ul class="toc">
+                <li><a href="#5.2.1.passwdfile">5.2.1. Pliki /etc/passwd</a></li>
+                <li><a href="#5.2.2.shadowfile">5.2.2. Plik /etc/shadow</a></li>
+                <li><a href="#5.2.3.group">5.2.3. Plik /etc/group</a></li>
+                <li><a href="#5.2.4.gshadowfile">5.2.4. Plik /etc/gshadow</a></li>
+              </ul>
+            </li>
+            <li><a href="#5.3.basicsofusermanagement">5.3. Podstawy zarządzania użytkownikami</a>
+              <ul class="toc">
+                <li><a href="#5.3.1.usersdefaultinformations">5.3.1. Domyślnie informacje użytkowników</a></li>
+                <li><a href="#5.3.2.useradd">5.3.2. Tworzenie użytowników</a></li>
+                <li><a href="#5.3.3.usermod">5.3.3. Zmiana informacji użytkownika</a></li>
+                <li><a href="#5.3.4.userdel">5.3.4. Usuwanie użytkowników</a></li>
+                <li><a href="#5.3.5.nologinusers">5.3.5. Użytkownicy bez możliwości logowania</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec5.1">Ćwiczenie 1: Sprawdzenie prób logowania użytkowników</a></li>
+            <li><a href="#exec5.2">Ćwiczenie 2: Weryfikacja użytkownika oraz grupy</a></li>
+            <li><a href="#exec5.3">Ćwiczenie 3: Tworzenie użytkowników</a></li>
+            <li><a href="#exec5.4">Ćwiczenie 4: Tworzenie użytkowników nieinteraktywnych</a></li>
+            <li><a href="#ch5summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#6.advancedusermanagement">6. Zaawansowane zarządzanie użytkownikami</a>
+          <ul class="toc">
+            <li><a href="#6.1.passwordaging">6.1. Zasady ważności hasła</a></li>
+            <li><a href="#6.2.groupmanaging">6.2. Zarządzanie grupami</a>
+              <ul class="toc">
+                <li><a href="#6.2.1.groupadd">6.2.1. Tworzenie nowych grup</a></li>
+                <li><a href="#6.2.2.groupmod">6.2.2. Zmiana informacji grupy</a></li>
+                <li><a href="#6.2.3.groupdel">6.2.3. Usuwanie grup</a></li>
+              </ul>
+            </li>
+            <li><a href="#6.3.suandsudo">6.3. Przełączanie użytkowników oraz uruchamianie poleceń jako superużytkownik</a>
+              <ul class="toc">
+                <li><a href="#6.3.1.su">6.3.1. Przełącznie użytkownika</a></li>
+                <li><a href="#6.3.2.sudo">6.3.2. Polecenie sudo</a></li>
+              </ul>
+            </li>
+            <li><a href="#6.4.chownchgrp">6.4. Zmiana praw własności plików i katalogów</a></li>
+            <li><a href="#exec6.1">Ćwiczenie 1: Utwórz użytkowników oraz skonfiguruj zasady haseł</a></li>
+            <li><a href="#exec6.2">Ćwiczenie 2: Zablokuj i odblokuj użytkownika</a></li>
+            <li><a href="#exec6.3">Ćwiczenie 3: Zmień dane grupy</a></li>
+            <li><a href="#exec6.4">Ćwiczenie 4: Konfiguracja dostępu do sudo</a></li>
+            <li><a href="#exec6.5">Ćwiczenie 5: Zmiana praw własności do plików i katalogów</a></li>
+            <li><a href="#ch6summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#7.bashshell">7. Powłoka BASH</a>
+          <ul class="toc">
+            <li><a href="#7.1.bashfeatures">7.1. Funkcje powłoki BASH</a>
+              <ul class="toc">
+                <li><a href="#7.1.1.variables">7.1.1. Zmienne</a></li>
+                <li><a href="#7.1.2.commandsubstitution">7.1.2. Podstawienie polecenia</a></li>
+                <li><a href="#7.1.3.streamredirections">7.1.3. Przekierowanie strumieni</a></li>
+                <li><a href="#7.1.4.history">7.1.4. Historia poleceń</a></li>
+                <li><a href="#7.1.5.editingcli">7.1.5. Edycja wiersza polecenia</a></li>
+                <li><a href="#7.1.6.commandcompletion">7.1.6. Uzupełnianie poleceń</a></li>
+                <li><a href="#7.1.7.tilde">7.1.7. Podstawienie tyldy</a></li>
+                <li><a href="#7.1.8.alias">7.1.8. Aliasy</a></li>
+                <li><a href="#7.1.9.metacharacters">7.1.9. Metaznaki oraz nazwy wieloznaczne</a></li>
+                <li><a href="#7.1.10.pipes">7.1.10. Potoki i polecenia potokowe</a></li>
+                <li><a href="#7.1.11.quoting">7.1.11. Cytowanie</a></li>
+                <li><a href="#7.1.12.regex">7.1.12. Wyrażenia regularne</a></li>
+                <li><a href="#7.1.13.jobmanaging">7.1.13. Zarządzanie zadaniami</a></li>
+              </ul>
+            </li>
+            <li><a href="#7.2.startupscripts">7.2. Pliki startowe powłoki</a>
+              <ul class="toc">
+                <li><a href="#7.2.1.systemwidefiles">7.2.1. Globalne pliki startowe powłoki</a></li>
+                <li><a href="#7.2.2.usersfiles">7.2.2. Pliki startowe powłoki użytkownika</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec7.1">Ćwiczenie 1: Zmiana symbolu zachęty</a></li>
+            <li><a href="#exec7.2">Ćwiczenie 2: Przkierowanie strumieni</a></li>
+            <li><a href="#ch7summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#8.processandschedule">8. Zarządzanie procesami oraz harmonogram zadań</a>
+          <ul class="toc">
+            <li><a href="#8.1.procesmgmt">8.1. Zarządzanie procesami</a>
+              <ul class="toc">
+                <li><a href="#8.1.1.pscommand">8.1.1. Polecenie ps</a></li>
+                <li><a href="#8.1.2.polecenietop">8.1.2. Polecenie top</a></li>
+                <li><a href="#8.1.3.niceandrenice">8.1.3. Priorytet procesu</a></li>
+                <li><a href="#8.1.4.signals">8.1.4. Zarządzanie procesami za pomocą syganałów</a></li>
+              </ul>
+            </li>
+            <li><a href="#8.2.taskschedule">8.2. Harmonogram zadań</a>
+              <ul class="toc">
+                <li><a href="#8.2.1.scheduleaccesscontrol">8.2.1. Kontrola dostępu do harmongramu</a></li>
+                <li><a href="#8.2.2.at">8.2.2. Wykonanie zadań w przyszłości - polecenie at</a></li>
+                <li><a href="#8.2.3.cron">8.2.3. Definiowanie powtarzalnych zadań - program cron</a></li>
+                <li><a href="#8.2.4.anacron">8.2.4. Wykonanie pominiętych zadań - program Anacron</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec8.1">Ćwiczenie 1: Wartość nice procesu</a></li>
+            <li><a href="#exec8.2">Ćwiczenie 2: Konfiguracja tablicy cron użytkownika</a></li>
+            <li><a href="#ch8summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#9.rpmbasics">9. Podstawy zarządzania pakietami oprogramowania</a>
+          <ul class="toc">
+            <li><a href="#9.1.rpm">9.1. Red Hat Packet Manager - RPM</a>
+              <ul class="toc">
+                <li><a href="#9.1.1.gettinginfo">9.1.1. Pobieranie danych z pakietu</a></li>
+                <li><a href="#9.1.2.checkingpkgs">9.1.2. Sprawdzanie pakietów</a></li>
+                <li><a href="#9.1.3.installation">9.1.3. Instalacja i reinstalacja</a></li>
+                <li><a href="#9.1.4.updates">9.1.4. Aktualizacje pakietów</a></li>
+                <li><a href="#9.1.5.erasing">9.1.5. Usuwanie pakietów</a></li>
+                <li><a href="#9.1.6.miscs">9.1.6. Pozostałe czynności wykonywane na pakietach</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec9.1">Ćwiczenie 1: Instalacja pakietu zsh</a></li>
+            <li><a href="#exec9.2">Ćwiczenie 2: Pobieranie informacji oraz usunięcie pakietu</a></li>
+            <li><a href="#ch9summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#10.advancedpackagemanagement">10. Zaawansowane zarządzanie pakietami.</a>
+          <ul class="toc">
+            <li><a href="#10.1.repoconfig">10.1. Konfiguracja repozytorium dnf</a></li>
+            <li><a href="#10.2.individualpackagemgmnt">10.2. Zarządzanie pojedynczymi pakietami</a>
+              <ul class="toc">
+                <li><a href="#10.2.1.listofpackages">10.2.1. Listy pakietów</a></li>
+                <li><a href="#10.2.2.repoqueries">10.2.2. Zapytania do repozytorium</a></li>
+                <li><a href="#10.2.3.info">10.2.3. Pobieranie informacji o pakietach</a></li>
+                <li><a href="#10.2.4.installpackage">10.2.4. Instalacja pakietów</a></li>
+                <li><a href="#10.2.5.updatepackages">10.2.5. Aktualizacje pakietów</a></li>
+                <li><a href="#10.2.6.removepackages">10.2.6. Usuwanie pakietów</a></li>
+                <li><a href="#10.2.7.provides">10.2.7. Więcej informacji na temat pakietów</a></li>
+              </ul>
+            </li>
+            <li><a href="#10.3.packagegroup">10.3. Grupy pakietów</a>
+              <ul class="toc">
+                <li><a href="#10.3.1.listsofgroups">10.3.1. Listy grup</a></li>
+                <li><a href="#10.3.2.infoaboutgroup">10.3.2. Informacje o grupie</a></li>
+                <li><a href="#10.3.3.instalationofgroup">10.3.3. Instalacja grup</a></li>
+                <li><a href="#10.3.4.groupupdate">10.3.4. Aktualizacja grupy</a></li>
+                <li><a href="#10.3.5.removethegroup">10.3.5. Usuwanie grupy</a></li>
+              </ul>
+            </li>
+            <li><a href="#10.4.modulesmanaging">10.4. Zarządzanie modułami pakietów</a>
+              <ul class="toc">
+                <li><a href="#10.4.1.listingmodules">10.4.1. Wyświetlanie modułów</a></li>
+                <li><a href="#10.4.2.infoaboumodule">10.4.2. Informacje na temat modułu</a></li>
+                <li><a href="#10.4.3.moduleinstallation">10.4.3. Instalacja modułów</a></li>
+                <li><a href="#10.4.4.moduleupdates">10.4.4. Aktualizacja modułu</a></li>
+                <li><a href="#10.4.5.removethemodule">10.4.5. Usuwanie modułu</a></li>
+                <li><a href="#10.4.6.swichingstreams">10.4.6. Przełączanie się miedzy strumieniami</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec10.1">Ćwiczenie 1: Konfiguracja dostępu do repozytorium</a></li>
+            <li><a href="#exec10.2">Ćwiczenie 2: Instalacja i zarządzanie pojedynczymi pakietami</a></li>
+            <li><a href="#exec10.3">Ćwiczenie 3: Instalacja i zarządzanie grupami pakietów</a></li>
+            <li><a href="#exec10.4">Ćwiczenie 4: Instalacja i zarządzanie modułami</a></li>
+            <li><a href="#exec10.5">Ćwiczenia 5: Przełączanie się miedzy strumieniami</a></li>
+            <li><a href="#ch10summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#11.bootprocess">11. Proces ładowania systemu, GRUB oraz jądro</a>
+          <ul class="toc">
+            <li><a href="#11.1.grub">11.1. Program rozruchowy GRUB</a>
+              <ul class="toc">
+                <li><a href="#11.1.1.grubconfig">11.1.1. Konfiguracja programu GRUB</a></li>
+                <li><a href="#11.1.2.rescuemode">11.1.2. Ładowanie systemu do określonego trybu</a></li>
+              </ul>
+            </li>
+            <li><a href="#11.2.kernel">11.2. Jądro systemu Linuks</a>
+              <ul class="toc">
+                <li><a href="#11.2.1.kernelfiles">11.2.1. Pliki jądra w systemie</a></li>
+                <li><a href="#11.2.2.kernelpackes">11.2.2. Pakiety jądra</a></li>
+                <li><a href="#11.2.3.kernelversion">11.2.3. Wersja jądra</a></li>
+                <li><a href="#11.2.4.rebuidkernel">11.2.4. Przebudowa jądra</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec11.1">Ćwiczenie 1: Właczenie komunikatów podczas ładowania systemu</a></li>
+            <li><a href="#exec11.2">Ćwiczenie 2: Przywrócenie hasła superużytkownika</a></li>
+            <li><a href="#exec11.3">Ćwiczenie 3: Instalacja nowego jądra</a></li>
+            <li><a href="#ch11summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#12.sysinitlogsandtuned">12. Inicjalizacja systemu, pliki dziennika oraz dostarajanie systemu</a>
+          <ul class="toc">
+            <li><a href="#12.1.systeminit">12.1. Inicjalizacja systemu - systemd</a>
+              <ul class="toc">
+                <li><a href="#12.1.1.units">12.1.1. Jednostki</a></li>
+                <li><a href="#12.1.2.target">12.1.2. Jednostki celu</a></li>
+                <li><a href="#12.1.3.systemctl">12.1.3. Polecenie systemctl</a></li>
+                <li><a href="#12.1.4.managingunits">12.1.4. Zarządzanie jednostkami</a></li>
+                <li><a href="#12.1.5.managingtargets">12.1.5. Zarządzanie jednostkami celów</a></li>
+              </ul>
+            </li>
+            <li><a href="#12.2.logging">12.2. Prowadzenie plików dzienników systemowych</a>
+              <ul class="toc">
+                <li><a href="#12.2.1.rsyslog">12.2.1. Rejestrator systemowy - rsyslog</a></li>
+                <li><a href="#12.2.2.logrotating">12.2.2. Obrót plików dziennika</a></li>
+                <li><a href="#12.2.3.bootlog">12.2.3. Plik dziennika rozruchu</a></li>
+                <li><a href="#12.2.4.logger">12.2.4. Własne komunikaty diagnostyczne</a></li>
+              </ul>
+            </li>
+            <li><a href="#12.3.systemdjournal">12.3. Dzienniki systemd</a>
+              <ul class="toc">
+                <li><a href="#12.3.1.displaingjournald">12.3.1. Wyświetlanie dziennika systemd</a></li>
+                <li><a href="#12.3.2.storageforjournald">12.3.2. Konfiguracja miejsca do przechwywania dzienników systemd</a></li>
+              </ul>
+            </li>
+            <li><a href="#12.4.tuned">12.4. Dostosowywanie systemu</a>
+              <ul class="toc">
+                <li><a href="#12.4.1.tuned-adm">12.4.1. Polecenie tuned-adm</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec12.1">Ćwiczenie 1: Zmiana domyślnego celu ładowania systemu</a></li>
+            <li><a href="#exec12.2">Ćwiczenie 2: Zapis własnego komunikatu diagnostycznego</a></li>
+            <li><a href="#exec12.3">Ćwiczenie 3: Zastosowanie profili wydajności</a></li>
+            <li><a href="#ch12summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#13.basicsofstoragemanagement">13. Podstawy zarządzania pamięcią masową</a>
+          <ul class="toc">
+            <li><a href="#13.1.basicsterminology">13.1. Podstawowe pojęcia związane z zarządzaniem dyskami</a>
+              <ul class="toc">
+                <li><a href="#13.1.1.mbr">13.1.1 Schemat partycjonowania MBR (Master Boot Record)</a></li>
+                <li><a href="#13.1.2.gpt">13.1.2. Schemat patycjonowania GPT (GUID Partition Table)</a></li>
+                <li><a href="#13.1.3.partitionsonthesystem">13.1.3. Partycje dyskowe w systemie</a></li>
+                <li><a href="#13.1.4.storagemanagementools">13.1.4. Narzędzia do zarządzania pamięcią masową</a></li>
+                <li><a href="#13.1.5.thinprovisioning">13.1.5. Technologia thin provisioning</a></li>
+              </ul>
+            </li>
+            <li><a href="#13.2.mbrpartitioning">13.2. Zarządzenie partycjami ze schematem MBR</a></li>
+            <li><a href="#13.3.gptpartitioning">13.3. Zarządzanie partycjami ze schematem GPT</a></li>
+            <li><a href="#exec13.1">Ćwiczenie 1: Zarządzanie partycjami za pomocą parted</a></li>
+            <li><a href="#exec13.2">Ćwiczenie 2: Zarządzanie partycjami za pomocą gdisk</a></li>
+            <li><a href="#ch13summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#14.advancedstoragemanagement">14. Zaawansowane zarządzanie pamięcią masową</a>
+          <ul class="toc">
+            <li><a href="#14.1.lvm">14.1. Zarządzanie pamięcią masową przy użyciu LVM</a>
+              <ul class="toc">
+                <li><a href="#14.1.1.createpv">14.1.1. Tworzenie woluminów fizycznych</a></li>
+                <li><a href="#14.1.2.vgcreate">14.1.2. Tworzenie grup woluminów</a></li>
+                <li><a href="#14.1.3.lvcreate">14.1.3. Tworzenie woluminów logicznych LVM</a></li>
+                <li><a href="#14.1.4.rename">14.1.4. Zmiana nazwy elementów LVM</a></li>
+                <li><a href="#14.1.5.extend">14.1.5. Rozszerzanie elementów LVM</a></li>
+                <li><a href="#14.1.6.reduce">14.1.6. Zmniejszanie elementów LVM</a></li>
+                <li><a href="#14.1.7.undo">14.1.7. Wycofywanie zmian LVM na dyskach</a></li>
+              </ul>
+            </li>
+            <li><a href="#14.2.vdo">14.2. Wykorzystanie VDO do zarządzania pamięciami masowymi</a></li>
+            <li><a href="#14.3.stratis">14.4. Zarządzanie pamięcią masową za pomocą Stratis</a>
+              <ul class="toc">
+                <li><a href="#14.3.1.createpool">14.3.1. Tworzenie puli Stratis</a></li>
+                <li><a href="#14.3.2.createfilesystem">14.3.2. Tworzenie systemu plików Stratis</a></li>
+                <li><a href="#14.3.3.expandandrenamestratis">14.3.3. Rozszerzenie puli oraz zmiana nazwy puli i systemu plików Stratis</a></li>
+                <li><a href="#14.3.4.destroy">14.3.4. Usuwanie elementów Stratis</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec14.1">Ćwiczenie 1: Tworzenie grup woluminów oraz logicznych woluminów</a></li>
+            <li><a href="#exec14.2">Ćwiczenie 2: Rozszerzenie grupy woluminów oraz logicznego woluminu</a></li>
+            <li><a href="#exec14.3">Ćwiczenie 3: Redukcja oraz usunięcie woluminów logicznych</a></li>
+            <li><a href="#exec14.4">Ćwiczenie 4: Wycofywanie zmian LVM na dyskach</a></li>
+            <li><a href="#exec14.5">Ćwiczenie 5: Logiczne woluminy VDO</a></li>
+            <li><a href="#exec14.6">Ćwiczenie 6: Tworzenie puli Stratis</a></li>
+            <li><a href="#exec14.7">Ćwiczenie 7: Rozszerzenie i usunięcie puli Stratis</a></li>
+            <li><a href="#ch14summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#15.filesystemsandswap">15. Systemy plików oraz przestrzeń wymiany</a>
+          <ul class="toc">
+            <li><a href="#15.1.filesystems">15.1 Systemy plików na RHEL 9</a></li>
+            <li><a href="#15.2.mountandunmount">15.2. Montowanie oraz odłączanie systemów plików</a></li>
+            <li><a href="#15.3.gettinguuid">15.3. Pozyskiwanie identyfikatora UUID systemu plików</a></li>
+            <li><a href="#15.4.labeling">15.4. Nadawanie etykiet systemom plików</a></li>
+            <li><a href="#15.5.fstab">15.5. Automatyczne monotowanie systemów plików - /etc/fstab</a></li>
+            <li><a href="#15.6.df">15.6. Monitorowanie zużycia miejsca w systemie plików</a></li>
+            <li><a href="#15.7.du">15.7. Określenie użycia systemu plików</a></li>
+            <li><a href="#15.8.managingfilesystems">15.8. Zarządzanie systemami plików</a>
+              <ul class="toc">
+                <li><a href="#15.8.1.createfs">15.8.1. Tworzenie systemów plików</a></li>
+                <li><a href="#15.8.2.mountumount">15.8.2. Montowanie oraz odłączanie systemu plików</a></li>
+                <li><a href="#15.8.3.automount">15.8.3. Montowanie automatyczne z użyciem pliku /etc/fstab</a></li>
+                <li><a href="#15.8.4.expandvolumes">15.8.4. Rozszerzanie systemu plików na woluminie logicznym LVM</a></li>
+              </ul>
+            </li>
+            <li><a href="#15.9.swapmanaging">15.9. Zarządzanie przestrzenią wymiany</a>
+              <ul class="toc">
+                <li><a href="#15.9.1.createswap">15.9.1. Tworzenie przestrzeni wymiany</a></li>
+                <li><a href="#15.9.2.swaponoff">15.9.2. Włączanie i wyłączanie swapu</a></li>
+                <li><a href="#15.9.3.autoswapon">15.9.3. Automatyczne włączanie przetrzeni wymiany - /etc/fstab</a></li>
+                <li><a href="#15.9.4.swapmonitoring">15.9.4. Monitorowanie zużycia przestrzeni wymiany</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec15.1">Ćwiczenie 1: Tworzenie systemów plików oraz dodawanie wpisów do /etc/fstab</a></li>
+            <li><a href="#exec15.2">Ćwiczenie 2: Wolumin VDO z XFS</a></li>
+            <li><a href="#exec15.3">Ćwiczenie 3: Zarządzanie systemami plików z LVM</a></li>
+            <li><a href="#exec15.4">Ćwiczenie 4: Montowanie automatyczne woluminu Stratis</a></li>
+            <li><a href="#exec15.5">Ćwiczenie 5: Przestrzeń wymiany</a></li>
+            <li><a href="#ch15summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#16.networkfundamentals">16. Podstawy sieci w RHEL 9</a>
+          <ul class="toc">
+            <li><a href="#16.1.fundamentalstermsaboutnetworking">16.1. Podstawowe pojęcia o sieciach komputerowych</a>
+              <ul class="toc">
+                <li><a href="#16.1.1.ipv4">16.1.1. Adres IPv4</a></li>
+                <li><a href="#16.1.2.privateaddreses">16.1.2. Adresy prywatne</a></li>
+                <li><a href="#16.1.3.protocols">16.1.3. Protokoły</a></li>
+                <li><a href="#16.1.4.tcpudp">16.1.4. Protokoły TCP i UDP</a></li>
+                <li><a href="#16.1.5.icmp">16.1.5. Protokół ICMP</a></li>
+                <li><a href="#16.1.6.mac">16.1.6. Adres fizyczny</a></li>
+                <li><a href="#16.1.7.ipv6">16.1.7. Adres IPv6</a></li>
+                <li><a href="#16.1.8.hostname">16.1.8. Nazwa hosta</a></li>
+              </ul>
+            </li>
+            <li><a href="#16.2.networkdevsandcons">16.2. Urządzenia sieciowe i połączenia</a>
+              <ul class="toc">
+                <li><a href="#16.2.1.networkdevsnaming">16.2.1. Nazewnictwo urządzeń sieciowych w systemie</a></li>
+                <li><a href="#16.2.2.connectionprofiles">16.2.2. Profile połączeń sieciowych</a></li>
+                <li><a href="#16.2.3.nmcli">16.2.3. Zarządzanie połączeniami sieciowym za pomocą podsystemu NetworkManager</a></li>
+                <li><a href="#16.2.4.nmcliaddconnection">16.2.4. Tworzenie nowych połączeń sieciowych za pomocą nmcli</a></li>
+                <li><a href="#16.2.5.hostsfile">16.2.5. Plik /etc/hosts</a></li>
+                <li><a href="#16.2.6.connectivitytest">16.2.6. Testowanie łączności</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec16.1">Ćwiczenie 1: Zmiana nazwy hosta</a></li>
+            <li><a href="#exec16.2">Ćwiczenie 2: Nowe połączenia sieciowe</a></li>
+            <li><a href="#ch16summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#17.nfs">17. Network File System</a>
+          <ul class="toc">
+            <li><a href="#17.1.nfsconfig">17.1. Konfiguracja serwera oraz klienta NFS</a>
+              <ul class="toc">
+                <li><a href="#17.1.1.nfsserverconfig">17.1.1. Konfiguracja serwera NFS</a></li>
+                <li><a href="#17.1.2.nfsclientconfig">17.1.2. Konfiguracja klienta NFS</a></li>
+              </ul>
+            </li>
+            <li><a href="#17.2.autofs">17.2. Konfiguracja udziału NFS za pomocą AutoFS</a>
+              <ul class="toc">
+                <li><a href="#17.2.1.directmap">17.2.1. Mapowanie bezpośrednie</a></li>
+                <li><a href="#17.2.2.indirectmap">17.2.2. Mapowanie pośrednie</a></li>
+                <li><a href="#17.2.3.homeautomount">17.2.3. Automatyczne montowanie zdalnych katalogów domowych</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec17.1">Ćwiczenie 1: Tworzenie udziału NFS oraz mapowanie bezpośrednie</a></li>
+            <li><a href="#exec17.2">Ćwiczenie 2: Pośrednie mapowanie udziału NFS</a></li>
+            <li><a href="#ch17summary">Podsumowanie</a></li>
+          </ul>
+          <li><a href="#18.ntpanddns">18. Synchronizacja czasu oraz rozwiązywanie nazw w RHEL 9</a>
+            <ul class="toc">
+              <li><a href="#18.1.ntp">18.1. Network Time Protocol - synchronizacja czasu</a>
+                <ul class="toc">
+                  <li><a href="#18.1.1.chronyconfig">18.1.1. Konfiguracja demona Chrony</a></li>
+                  <li><a href="#18.1.2.settingdateandtime">18.1.2. Ustawienia daty i czasu</a></li>
+                </ul>
+              </li>
+              <li><a href="#18.2.nameresolving">18.2. Rozwiązywanie nazw domenowych</a>
+                <ul class="toc">
+                  <li><a href="#18.2.1.resolv.conf">18.2.1. Plik /etc/resolv.conf</a></li>
+                  <li><a href="#18.2.2.nsswitch.conf">18.2.2. Plik /etc/nsswitch.conf</a></li>
+                  <li><a href="#18.2.3.dnstools">18.2.3. Narzędzia do rozwiązywania nazw domenowych</a></li>
+                </ul>
+              </li>
+              <li><a href="#exec18.1">Ćwiczenie 1: Zmiana daty i czasu</a></li>
+              <li><a href="#exec18.2">Ćwiczenie 2: Konfiguracja Chrony</a></li>
+              <li><a href="#ch18summary">Podsumowanie</a></li>
+            </ul>
+          </li>
+        </li>
+        <li><a href="#19.ssh">19. Usługa bezpiecznej powłoki</a>
+          <ul class="toc">
+            <li><a href="#19.1.sshtheory">19.1. Podstawy teoretyczne na temat SSH</a>
+              <ul class="toc">
+                <li><a href="#19.1.1.sshcryptography">19.1.1. Kryptografia SSH</a></li>
+                <li><a href="#19.1.2.sshauthmethod">19.1.2. Metody uwierzytelniania OpenSSH</a></li>
+                <li><a href="#19.1.3.sshprograms">19.1.3. Oprogramowanie OpenSSH</a></li>
+              </ul>
+            </li>
+            <li><a href="#19.2.sshd">19.2. Serwer OpenSSH - sshd</a></li>
+            <li><a href="#19.3.sshclientconfig">19.3. Konfiguracja klienta - ssh</a></li>
+            <li><a href="#19.4.sshusage">19.4. Obsługa połączeń zdalnych - programy OpenSSH</a>
+              <ul class="toc">
+                <li><a href="#19.4.1.ssh">19.4. Połączenie ze zdalnym serwerem z pomocą ssh</a></li>
+                <li><a href="#19.4.2.sshpubkeys">19.4.2. Generowanie, dystrybucja oraz logowanie się za pomocą klucza publicznego</a></li>
+                <li><a href="#19.4.3.sshexecutioncommand">19.4.3. Wykonywanie pojedyńczych poleceń na zdalnym serwerze</a></li>
+                <li><a href="#19.4.4.scp">19.4.4. Bezpieczne kopiowanie plików</a></li>
+                <li><a href="#19.4.5.sftp">19.4.5. Przesyłanie plików za pomocą polecenia sftp</a></li>
+                <li><a href="#19.4.6.rsync">19.4.6. Synchronizacja danych ze zdalnym serwerem</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec19.1">Ćwiczenie 1: Logowanie przez SSH z użyciem klucza</a></li>
+            <li><a href="#exec19.2">Ćwiczenie 2: Działanie dyrektywy PermitRootLogin</a></li>
+            <li><a href="#ch19summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#20.firewall">20. Zapora sieciowa w RHEL 9</a>
+          <ul class="toc">
+            <li><a href="#20.1.firewalldtheory">20.1. Teoria firewalld</a></li>
+            <li><a href="#20.2.firewallmanagement">20.2. Zarządzanie ruchem sieciowym w firewalld</a>
+              <ul class="toc">
+                <li><a href="#20.2.1.firewalldstatus">20.2.1. Sprawdzenie status zapory sieciowej</a></li>
+                <li><a href="#20.2.2.firewalladd">20.2.2. Dodowanie usług, portów oraz zarządzanie strefami</a></li>
+                <li><a href="#20.2.3.firewallremove">20.2.3. Usuwanie portów oraz usług</a></li>
+                <li><a href="#20.2.4.firewalleffective">20.2.4. Efektywność zapory firewalld</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec20.1">Ćwiczenie 1: Dodawanie usługi do zapory</a></li>
+            <li><a href="#exec20.2">Ćwiczenie 2: Dodawanie zakresu portów do zapory</a></li>
+            <li><a href="#ch20summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#21.selinux">21. Security Enchanced Linux</a>
+          <ul class="toc">
+            <li><a href="#21.1.theoryofselinux">21. Podstawy teoretyczne SELinux</a>
+              <ul class="toc">
+                <li><a href="#21.1.1.terminology">21.1.1. Pojęcia związane z SELinux</a></li>
+                <li><a href="#21.1.2.contextofusers">21.1.2. Kontekst SELinux użytkowników</a></li>
+                <li><a href="#21.1.3.contextofprocess">21.1.3. Kontekst procesów</a></li>
+                <li><a href="#21.1.4.contextoffile">21.1.4. Kontekst SELinux plików</a></li>
+                <li><a href="#21.1.5.savethecontext">21.1.5. Zachowanie kontekstu SELinux podczas zarządzania plikami</a></li>
+                <li><a href="#21.1.6.contextofports">21.1.6. Kontekst SELinux portów sieciowych</a></li>
+                <li><a href="#21.1.7.domaintransitioning">21.1.7. Zmiana domeny SELinux</a></li>
+                <li><a href="#21.1.8.selinuxbooleans">21.1.8. Wartości logiczne SELinux</a></li>
+              </ul>
+            </li>
+            <li><a href="#21.2.selinuxadministration">21.2. Zarządzanie SELinux</a>
+              <ul class="toc">
+                <li><a href="#21.2.1.managingcommands">21.2.1. Polecenia zarządzające</a></li>
+                <li><a href="#21.2.2.operationalstate">21.2.2. Zmiana stanu operacyjnego SELinux</a></li>
+                <li><a href="#21.2.3.querying">21.2.3. Sprawdzanie stanu SELinux</a></li>
+                <li><a href="#21.2.4.modifyselinuxcontent">21.2.4. Modyfikowanie kontekstu SELinux plików</a></li>
+                <li><a href="#21.2.5.addandapplyfilecontext">21.2.5. Dodwanie oraz zatwierdzanie kontekstu plików SELinux</a></li>
+                <li><a href="#21.2.6.addanddeletenetworkport">21.2.6. Dodawanie i usuwanie portów sieciowych w ujęciu SELinux</a></li>
+                <li><a href="#21.2.7.preservingcontext">21.2.7. Zachowanie kontekstu SELinux podczas kopiowania</a></li>
+                <li><a href="#21.2.8.changebooleans">21.2.8. Zmiana wartości logicznych SELinux</a></li>
+                <li><a href="#21.2.9.selinuxmonitoring">21.2.9. Monitorowanie naruszeń SELinux</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec21.1">Ćwiczenie 1: Zmiana trybu operacyjnego SELinux</a></li>
+            <li><a href="#exec21.2">Ćwiczenie 2: Modyfikacja kontekstu plików</a></li>
+            <li><a href="#exec21.3">Ćwiczenie 3: Dodawanie portów</a></li>
+            <li><a href="#exec21.4">Ćwiczenie 4: Kopiowanie plików z zachowaniem kontekstu</a></li>
+            <li><a href="#exec21.5">Ćwiczenia 5: Zmiana stanu wartości logicznej SELinux</a></li>
+            <li><a href="#ch21summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#22.shellscripts">22. Skrypty powłoki</a>
+          <ul class="toc">
+            <li><a href="#22.1.basicsofshellscripts">22.1. Podstawy skryptów powłoki</a>
+              <ul class="toc">
+                <li><a href="#22.1.1.scriptdebuging">22.1.1. Debugowanie skryptu</a></li>
+                <li><a href="#22.1.2.scriptsvariables">22.1.2. Zmienne</a></li>
+                <li><a href="#22.1.3.shellparameters">22.1.3. Parametry powłoki</a></li>
+              </ul>
+            </li>
+            <li><a href="#22.2.logicalconstructs">22.2. Konstrukcje logiczne w skryptach powłoki</a>
+              <ul class="toc">
+                <li><a href="#22.2.1.exitcodes">22.2.1. Kody wyjściowe</a></li>
+                <li><a href="#22.2.2.conditionalexpressions">22.2.2. Wyrażenia warunkowe</a></li>
+                <li><a href="#22.2.3.ifthenfi">22.2.3. Konstrukcja if-then-fi</a></li>
+                <li><a href="#22.2.4.ifthenelsefi">22.2.4. Konstrukcja if-then-else-fi</a></li>
+                <li><a href="#22.2.5.iftheneliffi">22.2.5. Konstrukcja if-then-elif-fi</a></li>
+              </ul>
+            </li>
+            <li><a href="#22.3.loop">22.3. Konstrukcje pętli</a>.
+              <ul class="toc">
+                <li><a href="#22.3.1.forloop">22.3.1. Konstrukcja pętli for-do-done</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec22.1">Ćwiczenie 1: Poprawienie skryptu</a></li>
+            <li><a href="#ch22summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+        <li><a href="#23.containers">23. Kontenery</a>
+          <ul class="toc">
+            <li><a href="#23.1.workwithimagesandcontainers">23.1. Praca z obrazami oraz kontenerami</a>
+              <ul class="toc">
+                <li><a href="#23.1.1.registeringredhatsystem">23.1.1. Rejestrowanie systemu Red Hat</a></li>
+                <li><a href="#23.1.2.contsoftwareinstallation">23.1.2. Instalacja oprogramowania kontenerów</a></li>
+                <li><a href="#23.1.3.podmancommand">23.1.3. Polecenie podman</a></li>
+                <li><a href="#23.1.4.skopeocommand">23.1.4. Polecenie skopeo</a></li>
+                <li><a href="#23.1.5.registries.conf">23.1.5. Plik registries.conf</a></li>
+                <li><a href="#23.1.6.podmaninfo">23.1.6. Informacje nt. konfiguracji kontenerów w systemie</a></li>
+              </ul>
+            </li>
+            <li><a href="#23.2.imagesmgmt">23.2. Zarządzanie obrazami</a></li>
+            <li><a href="#23.3.basicscontainermgmt">23.3. Podstawy zarządzania kontenerami</a>
+              <ul class="toc">
+                <li><a href="#23.3.1.namedcontainer">23.3.1. Zarządzanie konterami nazwanymi</a></li>
+                <li><a href="#23.3.2.namelesscontainers">23.3.2. Zarządzanie kontenerami bez nazw</a></li>
+              </ul>
+            </li>
+            <li><a href="#23.4.advcontainermgmt">23.4. Zaawansowane zarządzanie kontenerami</a>
+              <ul class="toc">
+                <li><a href="#23.4.1.portmapping">23.4.1. Mapowanie portów hosta na porty kontenera</a></li>
+                <li><a href="#23.4.2.envtocontainers">23.4.2. Przekazywanie zmiennych środowiskowych do kontenerów</a></li>
+                <li><a href="#23.4.3.storageforcontainers">23.4.3. Konfigurowanie miejsca na dane dla kontenerów</a></li>
+                <li><a href="#23.4.4.controlingcontainersviasystemd">23.4.4. Kontrolowanie kontenerów przez systemd</a></li>
+              </ul>
+            </li>
+            <li><a href="#exec23.1">Ćwiczenie 1: Utwórzenie laboratorium kontenerów</a></li>
+            <li><a href="#exec23.2">Ćwiczenie 2: Nazwany kontener z mapowaniem portów</a></li>
+            <li><a href="#exec23.3">Ćwiczenie 3: Kontener bez nazwy z przekazanymi zmiennymi</a></li>
+            <li><a href="#exec23.4">Ćwiczenie 4: Kontener ze stałym miejscem przechowywania</a></li>
+            <li><a href="#exec23.5">Ćwiczenie 5: Kontener z przekazywaniem portów, zmiennymi oraz stałym miejscem przechowywania</a></li>
+            <li><a href="#exec23.6">Ćwiczenie 6: Konfigracja kontroli systemd nad kontenerami uprzywilejowanymi</a></li>
+            <li><a href="#exec23.7">Ćwiczenie 7: Konfigracja kontroli systemd nad kontenerami nieuprzywilejowanymi</a></li>
+            <li><a href="#ch23summary">Podsumowanie</a></li>
+          </ul>
+        </li>
+      </ul>
+      <p>
+        Źródła:
+      </p>
+      <ol>
+        <li><strong>RHCSA® Red Hat® Enterpise Linux® 8 (UPDATED)</strong>.
+          Training and Exam Preparation Guide. Second Edition. 
+          <em>Asghar Ghori</em></li>
+        <li><a href="https://access.redhat.com/solutions/6809311">How to configure a storage device to use VDO deduplication and compression in RHEL 9?</a></li>
+        <li><a href="https://www.redhat.com/en/blog/rhel-9-networking-say-goodbye-ifcfg-files-and-hello-keyfiles">RHEL 9 networking: Say goodbye to ifcfg-files, and hello to keyfiles </a></li>
+        <li>Strony podręcznika Red Hat Enterprise Linux 9</li>
+      </ol>
+    <p class="footer">
+        ~xf0r3m<br />
+                               2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+      </div>
+      <div id="content">
+      <div id="contentHeader">
+<pre id="divisionBaner">
+ ____          _ _   _       _   
+|  _ \ ___  __| | | | | __ _| |_ 
+| |_) / _ \/ _` | |_| |/ _` | __|
+|  _ &lt;  __/ (_| |  _  | (_| | |_ 
+|_| \_\___|\__,_|_| |_|\__,_|\__|
+                                 
+</pre>
+        <p id="contentHeaderLink" class="header_link">
+           &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+        </p>
+      </div>
+      <h1 id="1.introduction">1. Wstęp</h1>
+      <p>
+        Chcąc zmienić coś w swoim życiu postanowiłem, że zacznę od pracy.
+        Dalej chciałem pracować w IT, tylko na innym stanowisku (praca 
+        szkolnego administratora
+        jest porównywalna z pracą technika IT, tu ma ktoś problem z systemem,
+        tu trzeba podłączyć rzutnik, szczerze to znudziła się praca tego 
+        typu).  Dobrze czułem się pracując z
+        Linuksem, to była moja pasja. Znałem dwa stanowiska na których 
+        mógłbym pracować: <em>Linux System Administrator</em> lub 
+        <em>Linux System Engineer</em>. 
+        Teraz na rynku pracy jeśli chodzi o IT ważniejsze są 
+        uzyskane certyfikaty i odbyte kursy niż wykształcenie akademickie. 
+        Szukając certyfikatów,
+        które spowodują większe szanse na zatrudnienie, znalazłem dwa.
+        <em>Linux Fundation</em> oraz <em>Red Hat</em>. Po przeczytaniu postu a
+        na <em>Reddit</em>
+        doszedłem do wniosku, że lepszym wyborem będzie Red Hat. Jeśli
+        chodzi o produkcyjne wykorzystanie Linuksa to większość używa
+        <strong>Red Hat Enterprise Linux</strong> lub jego darmowego 
+        odpowiednika. Kiedyś <em>CentOS</em> ale
+        obecnie może być to zarówno <em>Rocky</em> lub <em>Alma Linux</em>, 
+        oba są oparte na tym
+        systemie. Szukając jakiś materiałów w internecie, które
+        pomogły by mi się przygotować natrafiłem na Amazonie na książke
+        Asghara Ghori pt. <em>RHCSA Red Hat Enterprise Linux 8 (UPDATED): 
+        Training and Exam Preparation Guide (EX200), Second Edition</em>
+        zamówiłem ją na swojego Kindla i zacząłem przygotowywać się do
+        egzaminu. 
+      </p>
+      <h2 id="1.1.exam">1.1. Egzamin</h2>
+      <p>
+        Egzamin EX200 dający uprawnienia Red Hat Certified System
+        Administrator jest egzaminem praktycznym sprawdzającym umiejętność
+        instalacji, konfiguracji oraz rozwiązywania podstawowych problemów
+        administracyjnych na dystrybucji Red Hat. Egzamin będzie odbywać
+        się w postaci elektronicznej i zdający będzie mięć do dyspozycji
+        dwie maszyny wirtualne do wykonania zadań egzaminacyjnych. Takie
+        też środowisko przygotujemy sobie do nauki. Na dzień 11 listopada
+        2020 (tak jak podaje książka) egzamin obejmuje 69 zagadnień jednak
+        ta liczba, ze względu na rozwój technologii jak i samego 
+        <em>RHEL</em>-a mogła ulec już zmianie.
+      </p>
+      <h2 id="1.2.examobjectives">1.2. Zagadnienia</h2>
+      <p>
+        Zagadnienia używane na egzaminie mogą cały czas ewoluować. Odnośnik
+        obok przedstawia aktualne zagadnienia egzaminacyjne:
+        <a href="http://www.redhat.com/training/courses/ex200/examobjective">http://www.redhat.com/training/courses/ex200/examobjective</a>. Obecnie egzamin zadawany jest na
+        <em>RHEL</em> 9, wydanym 17 maja 2022. Dość istotną zmianą w produkcji 
+        tego
+        systemu jest zmiana <em>upstreamu</em>. Ta wersja <em>Red Hat</em> nie 
+        jest
+        już oparta na dystrybucji <em>Fedora</em> tak jak wszystkie do tej 
+        pory, ale na <em>CentOS Stream</em> (nowa wersja non-stream tej 
+        dystrybucji nie jest już dostępna stąd
+        rozbicie społeczonościowych dystrybucji do zastosowań produkcyjnych na
+        <em>Rocky</em> oraz <em>Alma Linux</em>) i tej wersji będziemy używać 
+        na maszynach wirtualnych.
+      </p>
+      <h2 id="1.3.exampreparation">1.3. Przygotowania</h2>
+      <p>
+        Kiedy uznałem, że chce zdobyć <em>RHCSA</em>, uzyskałem 
+        <em>Red Hat</em> na zasadzie
+        <em>Non-cost RHEL Individual Developer Subscription</em>, gdzie
+        istotne informacje znajdują się w odnośniku obok: 
+        <a href="https://developers.redhat.com/articles/faqs-no-cost-red-hat-enterprise-linux">https://developers.redhat.com/articles/faqs-no-cost-red-hat-enterprise-linux</a>.
+        Przy użyciu tej subskrypcji uzyskamy dostęp do Red Hat przez rok na
+        16 instalacji (bez znaczenia czy to fizyczny komputer, czy maszyna
+        wirtualna). Po tym czasie należy zalogować się ponownie, zakceptować
+        warunki umowy i do około 30 minut powinnimy uzyskać ponowny rok
+        subskrypcji i tak co roku. Wszystko jest opisane na powyższej stronie.
+        System w wersji 9 zainstalowałem na komputerze przeznaczony do 
+        codziennego użytku. Najlepszym sposobem na nauczenie się
+        administracji systemem jest jego używanie na co dzień, a że jest 
+        entuzajstą a nie
+        profesjonalistą, mój kontakt z systemami tego typu jest raczej dość
+        mocno ograniczony. Dlatego też przesiadłem się na <em>RHEL</em>, póki 
+        co to ten
+        system poprostu działa, wcześniej korzystałem z <em>Fedory</em> 35 oraz
+        <em>Debiana</em> 11. Do celów dydaktycznych potrzebujemy peceta lub laptopa
+        z min. dwurdzeniowym procesorem z możliwością wirtualizacji 64-bitowych
+        systemów, 8GB pamięci operacyjnej oraz min. 40GB
+        wolnej przestrzeni na dysku na potrzeby utworzenia maszyn wirtualnych
+        z wymagną przez ćwiczenia przestrzenią dyskową. Do tego celu możemy 
+        użyć dowolnego środowiska wirtualizacji, które znamym. Jeśli nie
+        mieliśmy wcześniej żadnego kontatku z tego typu oprogramowaniem, to
+        najlepiej jest użyć oprogramowania <em>Oracle VirtualBox</em>, 
+        dającego najprostszy
+        interfejs do interakcji z maszynami, gdyż przy późniejszych
+        zagadnieniach będziemy musieli zmienić jej ustawienia lub dodać kilka
+        urządzeń. Czy ktoś zainstaluje na swoim 
+        komputerze <em>RHEL</em> czy nie to,
+        już indywidualna sprawa i nie wypłynie ona wykonanie ćwiczeń. Nie
+        mniej jednak, w podpunkcie odnośnie maszyn wirtualnych tego rodziału
+        przedstawie skrypt powłoki, który po uruchomieniu utworzy
+        automatycznie maszyny wymagane do wykonania ćwiczeń. Ale póki co 
+        przedstawie teraz instalacje <em>Oracle VirtualBox</em> na
+        <em>RHEL</em> 9.
+      </p>
+      <h3 id="1.3.1.vboxinstallationonrhel">1.3.1. Instalacja Oracle VirtualBox na RHEL 9.0</h3>
+      <p>
+        Pierwszą czynnością jest uruchomienie przeglądarki i przejście pod
+        adres: <a href="https://www.virtualbox.org/wiki/Linux_Downloads">https://www.virtualbox.org/wiki/Linux_Downloads</a>, na samym dole strony znajdują się pliki repozytorium
+        dla kilku dystrybucji Linuksa. Kopiujemy adres odnośnika do pliku
+        konfiguracyjnego repozytorium. Następnie możemy wydać polecenia:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo wget https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo -O /etc/yum.repos.d/virtualbox.repo
+[xf0r3m@primeb450 ~]$ sudo dnf update
+Updating Subscription Management repositories.
+Red Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)        6.3 kB/s | 4.1 kB     00:00    
+Red Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)            10 kB/s | 4.1 kB     00:00    
+Oracle Linux / RHEL / CentOS-9 / x86_64 - VirtualBox             99  B/s | 181  B     00:01    
+Oracle Linux / RHEL / CentOS-9 / x86_64 - VirtualBox            1.9 kB/s | 1.7 kB     00:00    
+Importowanie klucza GPG 0x98AB5139:
+ Identyfikator użytkownika: „Oracle Corporation (VirtualBox archive signing key) &lt;info@virtualbox.org&gt;”
+ Odcisk                   : 7B0F AB3A 13B9 0743 5925 D9C9 5442 2A4B 98AB 5139
+ Z                        : https://www.virtualbox.org/download/oracle_vbox.asc
+W porządku? [t/N]: t
+Oracle Linux / RHEL / CentOS-9 / x86_64 - VirtualBox                    8.6 kB/s | 7.8 kB     00:00    
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+[xf0r3m@primeb450 ~]$ sudo dnf install VirtualBox-6.1 kernel-devel
+Updating Subscription Management repositories.
+Ostatnio sprawdzono ważność metadanych: 0:04:10 temu w dniu sob, 13 sie 2022, 10:12:38.
+Rozwiązano zależności.
+...
+</pre>
+      <p>
+        Po instalacji restartujemy komputer.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo reboot
+</pre>
+      <p>
+        Teraz Oracle VirtualBox jest gotów do działania.
+      </p>
+      <p>
+        Jeśli chcemy możemy użyć <strong>RPMFusion</strong>. Po 
+        załadowaniu tych repozytoriów do swojego systemu możemy od razu wydać
+        polecenie:
+      </p>
+<pre class="code-block">
+[user@centos9 ~]$ sudo dnf install VirtualBox kernel-devel
+...
+[user@centos9 ~]$ sudo su
+[root@centos9 user]# akmods
+Checking kmods exist for 5.14.0-142.el9.x86_64 [  OK  ]
+[root@centos9 user]# sudo systemctl restart vboxdrv.service
+[root@centos9 user]# sudo systemctl status vboxdrv.service
+● vboxdrv.service - Linux kernel module init script
+     Loaded: loaded (/usr/lib/systemd/system/vboxdrv.service; enabled; vendor preset: enabled)
+     Active: active (exited) since Mon 2022-08-15 16:13:27 CEST; 6s ago
+    Process: 62653 ExecStart=/sbin/modprobe vboxdrv (code=exited, status=0/SUCCESS)
+    Process: 62657 ExecStart=/sbin/modprobe vboxnetflt (code=exited, status=0/SUCCESS)
+    Process: 62658 ExecStart=/sbin/modprobe vboxnetadp (code=exited, status=0/SUCCESS)
+   Main PID: 62658 (code=exited, status=0/SUCCESS)
+        CPU: 133ms
+...
+</pre>
+      <h3 id="1.3.2.gettingrheliso">1.3.2. Pozyskanie obrazu ISO z Red Hat Enterprise Linux 9</h3>
+      <p>
+        Aby pobrać potrzebny nam obraz musimy zarejestrować się w subskrypcji 
+        dla
+        indywidualnych deweloperów. Przechodzimy na stronę <a href="https://developers.redhat.com/register">https://developers.redhat.com/register</a> i rejestrujemy się. Następnie
+        logujemy i po zalogowaniu przechodzimy na stronę: <a href="https://developers.redhat.com/products/rhel/download">https://developers.redhat.com/products/rhel/download</a>.
+        w sekcji <em>All Downloads</em> znajdują się wszystkie dostępne wersje
+        <em>RHEL</em> objęte jeszcze wsparciem. Nas będzie interesować 
+        wyłącznie
+        wersja 9 i tą też pobieramy, oczywiście dla architektury <em>x86_64</em>
+        w wersji DVD.
+      </p>
+      <h3 id="1.3.3.createvmwithrhel">1.3.3. Tworzenie maszyn wirtualnych z RHEL</h3>
+      <p>
+        Tworzenie maszyn wirtualnych, nie jest zaganieniem
+        egzaminacyjnym. Na egzaminie dostaniemy dostęp do dwóch zdalnych
+        maszyn. Teoretycznie można by użyć fizycznych maszyn o ile ktoś ma
+        do takowych dostęp, jednak do drugiej maszyny trzeba dodać aż 8 dysków,
+        więc użycie wirtualnej maszyny, to chyba jedyne efektywne rozwiązanie. 
+        Poniżej znajdują się wymagania jakie powinna spełniać każda z nich:
+      </p>
+      <ul>
+        <li><strong>RHEL9-VM1</strong>:
+          <ul>
+            <li>64-Bitowy Red Hat Enterprise Linux 9.0,</li>
+            <li>1 wirtualny procesor,</li>
+            <li>1024 MB pamięci operacyjnej,</li>
+            <li>10GB dysk twardy, wyłącznie na instalacje systemu,</li>
+            <li>Karta sieciowa ustawiona na bridged.</li>
+            <li>Nazwa hosta ustawiona na server1.example.com</li>
+            <li>Stały adres IP, pozwalający na swobodną komunikację w sieci</li>
+          </ul></li>
+        <li><strong>RHEL9-VM2</strong>:
+          <ul>
+            <li>64-bitowy Red Hat Enterprise Linux 9.0,</li>
+            <li>1 wirtualny procesor</li>
+            <li>2048 MB pamięci operacyjnej</li>
+            <li>10 GB dysk twardy, na instalacje systemu</li>
+            <li>4 x 250 MB dysk twardy, dla ćwiczeń z LVM</li>
+            <li>2 x 10 GB dysk twardy, dla ćwiczeń z VDO</li>
+            <li>1 x 1 GB dysk twardy, dla ćwiczeń ze Stratis</li>
+            <li>Nazwa hosta ustawiona na server2.example.com</li>
+            <li>Stały adres IP, pozwalający na swobodną komunikację w sieci</li>
+          </ul></li>
+      </ul>
+      <p>
+        Maszyny możemy utworzyć ręcznie, zgodnie z wtycznymi dla używanego
+        przez nas środowiska wirtualizacji. Jeśli jednak korzystamy z 
+        <em>VirtualBox</em> możemy wykorzystać poniższe skrypty.
+        W przypadku drugiej maszyny dodatkowe dyski trzeba będzie dodać z
+        poziomu ustawień maszyny.
+      </p>
+      <ul>
+        <li><strong>RHEL9-VM1</strong>:
+<pre class="code-block">
+#!/bin/bash
+
+vboxmanage=$(which vboxmanage);
+vmname="RHEL9-VM1";
+bridged_if="";
+
+$vboxmanage createvm --name $vmname --ostype RedHat_64 --register;
+
+$vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/OS.vdi" --size \
+10240 --format VDI --variant Standard;
+$vboxmanage storagectl $vmname --name SATA0 --add sata;
+
+$vboxmanage modifyvm $vmname --memory 1024;
+$vboxmanage modifyvm $vmname --graphicscontroller vmsvga;
+$vboxmanage modifyvm $vmname --nic1 bridged;
+$vboxmanage modifyvm $vmname --bridgeadapter1 $bridged_if;
+
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 0 --type hdd --medium \
+"$HOME/VirtualBox VMs/${vmname}/OS.vdi";
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 1 --type dvddrive \
+--medium "$HOME/Pobrane/rhel-baseos-9.0-x86_64-dvd.iso";
+</pre>
+        </li>
+        <li><strong>RHEL9-VM2</strong>:
+<pre class="code-block">
+#!/bin/bash
+
+vboxmanage=$(which vboxmanage);
+vmname="RHEL9-VM2";
+bridged_if="";
+
+$vboxmanage createvm --name $vmname --ostype RedHat_64 --register;
+$vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/OS.vdi" --size \
+10240 --format VDI --variant Standard;
+
+$vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/VDO1.vdi" --size \
+10240 --format VDI --variant Standard;
+$vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/VDO2.vdi" --size \
+10240 --format VDI --variant Standard;
+
+$vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/Stratis.vdi" \
+--size 1024 --format VDI --variant Standard;
+
+$vboxmanage storagectl $vmname --name SATA0 --add sata;
+$vboxmanage modifyvm $vmname --memory 2048;
+$vboxmanage modifyvm $vmname --graphicscontroller vmsvga;
+$vboxmanage modifyvm $vmname --nic1 bridged;
+$vboxmanage modifyvm $vmname --bridgeadapter1 $bridged_if;
+
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 0 --type dvddrive \
+--medium "$HOME/Pobrane/rhel-baseos-9.0-x86_64-dvd.iso";
+
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 1 --type hdd --medium \
+"$HOME/VirtualBox VMs/${vmname}/OS.vdi";
+
+i=2;
+while [ $i -le 5 ]; do
+  $vboxmanage createhd --filename "$HOME/VirtualBox VMs/${vmname}/LVM${i}.vdi" --size \
+  250 --format VDI --variant Standard;
+  $vboxmanage storageattach $vmname --storagectl SATA0 --port $i --type hdd --medium \
+  "$HOME/VirtualBox VMs/${vmname}/LVM${i}.vdi";
+  i=$((i + 1));
+done
+
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 6 --type hdd --medium \
+"$HOME/VirtualBox VMs/${vmname}/VDO1.vdi";
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 7 --type hdd --medium \
+"$HOME/VirtualBox VMs/${vmname}/VDO2.vdi";
+
+$vboxmanage storageattach $vmname --storagectl SATA0 --port 8 --type hdd --medium \
+"$HOME/VirtualBox VMs/${vmname}/Stratis.vdi";
+</pre>
+        </li>
+      </ul>
+      <p>
+        Powyższe skrypt są również dostępne na moim profilu na github-ie. Pod
+        poniższymi linkami.
+      </p>
+      <ul>
+        <li><strong>RHEL9-VM1</strong>:<a href="https://github.com/xf0r3m/docs/raw/main/RHCSA/RHEL9-VM1.sh">https://github.com/xf0r3m/docs/raw/main/RHCSA/RHEL9-VM1.sh</a></li>
+        <li><strong>RHEL9-VM2</strong>:<a href="https://github.com/xf0r3m/docs/raw/main/RHCSA/RHEL9-VM2.sh">https://github.com/xf0r3m/docs/raw/main/RHCSA/RHEL9-VM2.sh</a></li>
+      </ul>
+      <p>
+        Korzystając ze skryptów <strong>należy pamiętać o zmianie intefejsu
+        sieciowego</strong> wykorzystywanego do mostkowania. Zmienna
+        <code class="code-inline">bridge_if</code>.
+      </p>
+      <p>
+        Po utworzeniu maszyn przyszedł czas na instalację.
+      </p>
+      <h3 id="1.3.4.rhelinstallation">1.3.4. Instalacja Red Hat Enterprise Linux 9.0</h3>
+      <p>
+        Zaraz po uruchomieniu maszyny rozpocznie się proces ładowania
+        zawartości płyty. Menu bootowania płyty zawiera trzy opcje. 
+      </p>
+      <ol>
+        <li><em>Install Red Hat Enterprise Linux 9.0</em></li>
+        <li><em>Test this media & install Red Hat Enterprise Linux 9.0</em></li>
+        <li><em>Troubleshooting</em></li>
+      </ol>
+      <p>
+        Domyślnie zaznaczoną jest opcja numer 2. Mamy minutę na zmianę
+        decyzji. Naciśnięcie dowolnego klawisza zatrzymuje odliczanie. Dając
+        nam czas do namysłu, jednak na ten moment nie ma co za bardzo rozmyślać
+        dlatego też wybieramy opcję numer 1. Po wybraniu tej opcji nastąpi
+        uruchomienie systemu oraz instalatora. Instalator używany przez RHEL 
+        oraz dystrybucje z nim związane
+        nazywa się <strong>Anaconda</strong>. Swoje działanie
+        rozpoczyna jeszcze w trybie tekstowym, następnie domyślnie uruchamia
+        tryb graficzny, gdzie odbywa się konfiguracja instalcji a następnie 
+        już właściwa instalacja.
+        Nie mniej jednak instalacja w trybie tekstowym jest również możliwa.
+        Podczas instalacji, poza głównym instalatorem będziemy mieć do
+        dyspozycji 
+        multipekser terminala, który do momentu uruchomienia właściwego 
+        instalatora (w wersji graficznej) był główną konsolą. W multiplekserze
+        będzie my mieć dostęp do komunikatów diagnostyczny, które w wersji 8
+        <em>RHEL</em> był wyświetlane na oddzielnych konsolach; kilka powłok z
+        uprawnieniami superużytkownika (uruchomione na konsolach 2, 3 i 5) 
+        oraz konsolę z komunikatami przechwytywanymi przez główny 
+        rejestrator systemu <em>rsyslog</em>. Udostępnienie tych funkcjonalności
+        podczas instalacji systemu, może pomóc w ewentualnym diagnozowaniu i
+        naprawie problemów z instalacją.
+        Pliki z komunikatami na czas instalacji przechowywane są w katalogu 
+        <em>/tmp</em>, po instalacji zostaną one przeniesione do katalogu
+        <em>/var/log/anaconda</em>. Według mnie jest dość przydatna
+        funkcjonalność, ponieważ na podstawie czasu modyfikacji tych plików
+        możemy dowiedzić się kiedy system został zainstalowany. Poniżej
+        znajduje się lista, opisująca za co odpowiada konkretna konsola
+        (kolejny ekran, dostępny po naciśnięciu klawiszy Ctrl + Alt + F1 - F6).
+      </p>
+      <ul>
+        <li><strong>CTLR + ALT + F1</strong> - multiplekser terminala,</li>
+        <li><strong>CTRL + ALT + F2</strong> - powłoka z dostępem do root,</li>
+        <li><strong>CTRL + ALT + F3</strong> - powłoka z dostępem do root,</li>
+        <li><strong>CTRL + ALT + F4</strong> - komunikaty diagnostyczne
+            rejestratora <em>syslog</em>.</li>
+        <li><strong>CTRL + ALT + F5</strong> - powłoka z dostępem do root,</li>
+        <li><strong>CTRL + ALT + F6</strong> - tryb graficzny.</li>
+      </ul>
+      <p>
+        Instalacja Red Hat Enterprise Linux rozpoczyna się od wyboru języka
+        procesu instalacji. Chcąc pracować już w takim prawowitym IT, należy
+        posługiwać się językiem angielskim i to technicznym. Systemy z którymi
+        zderzmy się w potencjalnej pracy raczej będą systemami o zasięgu
+        międzynarodowym, prawdopodobnie już o tym wspominałem ale egzamin
+        pozwalający uzyskać certyfikacje <em>RHCSA</em> również będzie po 
+        angielsku.
+        Dlatego też instalować jak i korzystać z systemu będziemy w języku
+        angielskim, na pierwszym ekranie wybieramy <em>English</em>
+        pozostawiając wariant <em>English (United States)</em>. Następnym
+        ekranem jest <em>Installation Summary</em> (lewy górny róg), jest tak
+        jakby pulpit programu instalacyjnego, na nim występują komponenty,
+        które możemy skonfigurować. W wersji 9.0, te komponenty są podzielone
+        na 4 sekcje: <em>Localization</em>, <em>Software</em>, <em>System</em>
+        oraz <em>User Settings</em>. W pierwszym procesie instalacji,
+        przejdziemy przez wszystkie z nich.
+      </p>
+      <p>
+        Zwróć my uwagę na to, iż system sam dokonał wstępnej konfiguracji
+        instalatora, na pozostało jedynie sprawdzić oraz skonfigurować tylko
+        te opcje oznaczone znakiem ostrzegawczym oraz czerwoną podpowiedzią. Po
+        ich konfiguracji program umożliwi nam zainstalowanie systemu.
+      </p>
+      <p>
+        W sekcji lokalizacyjnej do ustawienia są takie opcje, układ klawiatury,
+        język, oraz data i czas. Podczas ładowania pierwszego okna (moment 
+        wybrania języka instalacji), instalator na podstawie informacji 
+        <em>GeoIP</em>
+        postara się określić naszą przybliżoną lokalizację, o ile posiada on
+        na tym momencie połączenie z internetem. Dlatego też możemy
+        spotkać się z samoinstnie wybranym języku instalacji ustawionym na
+        Polski. Język został zmieniony, ale wybrana strefa czasowa może
+        pozostać, wręcz powinna. Dzięki tej funkcji możemy zaoszczędzić czas,
+        i przejść do kolejnej sekcji.
+      </p>
+      <p>
+        Kolejną sekcja dotyczy oprogramowania, tutaj konfigurowane będzie
+        na przykład połączenie z firmą <em>Red Hat</em>. <em>RHEL</em> jest 
+        system 
+        licencjonowanym i jeśli chcemy skorzystać z oficjalnych repozytoriów
+        należy "podłączyć" system do naszego konta założonego w celu
+        pozyskania obrazu płyty. Jednak na razie nie trzeba tego, będzie to
+        do zrobienia na późniejszych etapach nauki administracji systemem.
+        Kolejną opcją jest <em>Installation Source</em> (Źródło instalacji),
+        konfigurąc tę opcję możemy
+        wybrać czy będziemy korzystać pod czas instalacji z obrazu płyty lub
+        sieciowego repozytorium lub Red Hat CDN. Z racji tego, iż ściągneliśmy 
+        pełny obraz
+        ważący kilka gigabajtów, nie ma sensu używać instalacji sieciowej.
+        Tego typu źródło instalacji należy wybrać w momencie gdy pobraliśmy
+        minimalistyczną wersję obrazu, dlatego też zostaniemy przy standardowym
+        wyborze <em>Local media</em>. Ta opcja pozwala też na dodanie podczas
+        instalacji dodatkowego repozytorium, jednak na tym etapie nie będziemy
+        się tym zajmować. Ostanią opcją z tej sekcji jest <em>Software
+        selection</em>, ta opcja daje nam możliwość, wyboru rodzaju instalacji.
+        Na potrzeby nauki, wybierzemy opcję <em>Server with GUI</em>, jeśli
+        będziemy instalować <em>RHEL</em> na naszym komputerze do codziennego 
+        użytku
+        możemy wybrać <em>Workstation</em>. Wybierając rodzaj instalacji po
+        lewej stronie, po prawej wyświetają się dodatkowe pakiety lub
+        warianty do zainstalowania.
+      </p>
+      <p>
+        Sekcja <em>System</em>, służy głównie do wyboru docelowego miejsca dla
+        instalacji. W opcji <em>Instalation Destination</em>,
+        wskazujemy docelowy dysk do instalacji, możemy go spartycjonować 
+        ręcznie lub automatycznie możemy również zaszyfrować partycje,
+        jeśli jest taka potrzeba. W przypadku szyfrowania danych 
+        bardzo ważny jest układ klawiatury. Innymi opcjami
+        póki co dla nas ważnymi jest <em>Network &amp; Host name</em>, w
+        założeniach zadania, może być wymagane ustawienie odpowiedniego adresu
+        oraz nazwy dla maszyny, to te opcje
+        ustawiamy właśnie tam. Pozostałe opcje tej sekcji, poki co nie są
+        dla nas istotne.
+      </p>
+      <p>
+        Ostatnia sekcja ustawia hasło dla superużytkownika oraz tworzy konto
+        dla pierwszego użytkownika. Nie musi on posiadać uprawnień
+        administratora i nie będzie ich miał. Opcja utworzenia użytkownika
+        może się nie mieścić na ekranie, podczas instalacji systemu maszynie
+        witualnej, dlatego nie należy przejmować, że jej nie ma. Wystarczy
+        przewinąć wyświetlany oraz paskiem przewiajania po prawej stronie.
+      </p>
+      <p>
+        Teraz kiedy wszyskie (te istotne dla instalacji) opcje zostały opisane 
+        możemy
+        zainstalować system zgodnie założeniami pierwsze maszyny i powtorzyć
+        to na drugiej. I to jest pierwsze ćwiczenie.
+      </p>
+      <h3 id="exec1.1">Ćwiczenie 1: Instalacja Red Hat Enterprise Linux 9</h3>
+      <p>
+        Stwórz zgodnie założeniami podanymi w podrozdziale 
+        <em>Tworzenie maszyn wirtualnych z RHEL</em> maszynę <em>RHEL-VM1</em>.
+        Następnie korzystając z sugestii
+        podanych podczas opisu procesu instalacji zainstaluj na niej Red Hat
+        Enterprise Linux 9.
+        Powtórz tę czynność na drugiej maszynie przeznaczonej do laboratorium.
+        Pamiętaj, że założenia dla drugiej maszyny różnią się.
+      </p>
+      <h3 id="exec1.2">Ćwiczenie 2: Logowanie zdalne do RHEL</h3>
+      <p>
+        Wykorzystując program do obsługi protokołu SSH dla twoje systemu
+        operacyjnego zaloguj się na superużytkownika. Pamiętaj o tym, że
+        bezpośrednie logowanie na superużytkownika wymagało zaznaczenia opcji
+        w trakcie ustawiania hasła dla niego podczas instalacji.
+      </p>
+      <h2 id="ch1summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale przeszliśmy przez proces instalacji <em>RHEL</em>.
+        Dowiedzielśmy się, że możliwa jest instalacja w trybie tekstowym oraz
+        oraz, że nie należy ona do najtrudniejszych. Warto zwrócić uwagę na to
+        iż jeśli do tej pory korzystaliśmy z jakiś materiałów to dotyczą one
+        wersji 8 <em>RHEL</em>, my będziemy korzystać z wersji 9, bo to na niej
+        w 2022
+        roku będziemy przeprowadzany egzamin, a między tymi wersjami jest kilka
+        zmian.
+        W następnym rozdziale zapoznamy się z środowiskiem graficznym,
+        strukturą katalogów oraz podstawowym narzędziami do pracy w powłoce.
+      </p>
+      <h1 id="2.firststepsinRHEL9">2. Poruszanie się po systemie RHEL 9</h1> 
+      <p>
+        Wykonując ćwiczenia z pierwszego rozdziału, zainstalowaliśmy sobie
+        <em>Red Hat</em> w wersji 9 na maszynie wirtualnej. Jako wariant wyboru
+        oprogramowania wybraliśmy <em>Server with GUI</em> i od drobnego
+        omówienia środowiska graficznego rozpocznę ten rodział.
+      </p>
+      <h2 id="2.1.serverwithgui">2.1. Środowisko graficzne RHEL 9</h2>
+      <p>
+        <em>Red Hat</em> jest dystrybucją Linuksa przeznaczoną do zastosowań
+        produkcyjnych, więc system tego typu musi wykazywać się dużą
+        stabilnością. Znaczące zmiany są wprowadzane raczej w dużych wydania
+        jak <em>RHEL</em> 9, takim znaczącym przeskokiem jest zmiana linii 
+        jądra z
+        4.18 (w przypadku <em>RHEL</em> 8) na 5.14 (w przypadku <em>RHEL</em> 
+        9) oraz zastąpienie
+        klasycznego serwera <em>X Window</em> protokołem <em>Wayland</em>, to 
+        jednak nastąpiło z
+        wydaniem <em>RHEL</em> 8. Zmiany w <em>RHEL</em> 9, odnośnie środowiska
+         graficznego
+        to przejście z <em>Gnome</em> 3.38 na <em>Gnome</em> 40, ta zmiana 
+        przyniosła również
+        odświerzenie menedżera wyświetlania lub menedżera logowania czym w
+        przypadku środowiska <em>Gnome</em> jest <em>GDM</em>. Większość 
+        elementów pozostała
+        taka sama na górnej belce mamy datę oraz czas w prawyn górnym rogu
+        do wyboru opcje ułatwień dostępu, wskaźnik połączenia sieciowego oraz
+        porozwinięciu możliwość regulacji głośności i jasności ekranu oraz 
+        wyłączenia komputera. Wiecej opcji w tym miejscu będzie dostępne dopiero 
+        po zalogowaniu. Będzie można zmienić kilka ustawień jak np. sieć
+        bezprzewodwą. Zmianie uległ również sposób prezentacji kont użytkownika.
+        Z racji tego iż <em>root</em> nie jest zwykłym użytkownikiem nie będzie
+        pojawiać się na liscie, ale zalogowanie na niego jest możliwe za pomocą
+        kliknięcia w <em>Not Listed?</em> pod listą użytkowników, wówczas 
+        będzie mogli
+        ręcznie podać nazwę użytkownika oraz hasło. Ekranem startowym po
+        zalogowaniu jest ekran <em>Activities</em>, który pozwala na podgląd
+        wykonywanych czynności, rozpoczęcie nowych (wybierając aplikacje z 
+        doka lub z pełnej listy aplikacji, która jest dostępna po kliknięciu
+        na ikonę 9 kropek w doku) oraz przełacznie się między obszarami
+        roboczymi. Domyślnie <em>GNOME</em> daje dostęp do dwóch przestrzeni 
+        roboczych,
+        gdy tylko przeniesiemy aplikację do na nowy obszar, <em>GNOME</em> 
+        udostępni
+        nam kolejny i tak dalej. Wyszukiwarka nad podgląd obszaru roboczego
+        daje możliwość wyszukiwania nie tylko aplikacji ale także ustawień co
+        jest normą w <em>GNOME</em> od wersji 3. Na doku znajdują się ulubione
+        aplikacje, które możemy usuwać i dodawać za pomocą PPM i następnie
+        wybierając dodaj lub usuń z ulubionych.
+      </p>
+      <h2 id="2.2.hfs">2.2. Struktura katalogowa w Uniksach</h2>
+      <p>
+        Zanim jednak przejedziemy do obsługi wiersza poleceń omówimy sobie
+        hierachiczną strukturę katalogów, która występuje nie tylko w 
+        <em>RHEL</em> ale
+        i w innych Uniksach, ponieważ <em>HFS</em> 
+        (ang. <em>Hierarchy File System</em>)
+        jest ogólnym standardem. Na Uniksach możemy spotkać się z trzema typami
+        systemów plików.
+      </p>
+      <ul>
+        <li><strong><em>Disk-based</em> - dyskowe</strong> - są to klasyczne
+          pliki i katalogi przechowywane bezpośrednio na dysku.</li>
+        <li><strong><em>Network-based</em> - sieciowe</strong> - są to udziały
+          podmontowane w naszych systemach za pomocą róznych protokołów, nie
+          tylko SMB. Plik <em>network-based</em> są plikami <em>disk-based</em>,
+          ale na innych komputerach.</li>
+        <li><strong><em>Memory-based</em> - wirtualne</strong> - te systemy
+          plików są tworzone przez procesy na potrzeby działania systemu, takim
+          systemem może być katalog <em>/dev</em> lub <em>/proc</em>. Ich
+          trwałość często zależy od tego jak długo system pozostaje włączony
+          lub od wewnętrznych ustaleń samego systemu.</li>
+      </ul>
+      <p>
+        Struktura plików i katalogów na Uniksach ma postać odwróconego drzewa.
+        Korzeń (katalog główny) znajduje się na szczycie struktury i od niego
+        rozchodzą się poszczególne gałęzie (podkatalogi), gałęzię mogą zawierać
+        kolejne rozgałezienia, tworząc całe struktury. Na gałęziach
+        znajdują się również liscie czyli pliki i na liściach struktura się
+        kończy.
+      </p>
+      <p>
+        Dostęp do konkretnych plików i katalogów w strukturze określany jest
+        za pomocą ścieżek. Scieżki określają położenie plików i katalogów
+        wewnątrz <em>HFS</em>.
+        Separatorem elementów ścieżki (posczególnych podkatalogów), jest
+        ukośnik, slash (<strong>/</strong>).
+      </p>
+      <p>
+        Podczas pracy z elementami jak foldery oraz pliki możemy używać
+        <strong>scieżek bezwzględnych</strong> zaczynające się od
+        katalogu głównego, lub <strong>ścieżek względnych</strong>
+        zaczynających
+        się od elementu znajdującego w obecnym katalogu robocznym
+        (tym katalogu, w którym się obecnie znajdujemy).
+      </p>
+      <p>
+        Katalog główny jest miejscem do przechowywania wszystkich plików, jakie
+        znajdują się w systemie, jest pierwszym element znajdujący się na
+        ścieżce (bezwzględnej) i oznaczny jest on poprostu ukośnikiem
+        (<strong>/</strong>), od tego katalogu zaczyna się cała struktura.
+        Poniżej znajduje się lista najważniejszych podkatalogów katalogu
+        głównego, każdy z nich ma swoje znaczenie w systemie.
+      </p>
+      <ul>
+        <li><strong>/boot</strong> (<em>disk-based</em>) - katalog ten
+            przechowuje jądro, <em>initramfs</em> oraz konfiguracje programu
+            rozruchowego.</li>
+        <li><strong>/dev</strong> (<em>memory-based</em>) - katalog ten
+            przechowuje pliki urządzeń służące do komunikacji z sprzętowymi
+            komponentami komputera. Pliki te są tworzone
+            przez usługę <em>udevd</em> podczas podłączania urządzenia oraz
+            rozruchu systemu.</li>
+        <li><strong>/etc</strong> (<em>disk-based</em>) - skrót <em>etc</em>
+            możemy rozwinąć do ang. <em>etcetera</em> lub ang. <em>extended
+            text configration</em>. Jest to miejsce do przechowywania plików
+            konfiguracyjnych różnych programów.</li>
+        <li><strong>/home</strong> (<em>disk-based</em>) - ten katalog
+            przechowuje, katalogi domowe użytkowników.</li>
+        <li><strong>/opt</strong> (<em>disk-based</em>) - katalog przeznaczony
+            na dodatkowe oprogramowanie instalowane w systemie.</li>
+        <li><strong>/proc</strong> (<em>memory-based</em>) - wirtualna 
+            struktura podkatalogów, zawierająca informacje o procesach oraz
+            różne informacje o systemie, np. informacje o procesorze.</li>
+        <li><strong>/run</strong> (<em>memory-based</em>) - katalog
+            przechowywujący pliki wykorzystywane przez procesy podczas
+            wykonywania ich czynności. W tym katalogu znajduje się również
+            podkatalog <em>media</em> zawierący punkty montowania podłączanych
+            do systemu dysków wymiennych.</li>
+        <li><strong>/sys</strong> (<em>memory-based</em>) - katalog
+            przechowuje informacje o urządzeniach, sterownikach. Pewne
+            funkcjonalności jądra również są zawarte w tym katalogu. Dane
+            z tego katalogu są używane przez jądro do obsługi urządzeń.</li>
+        <li><strong>/tmp</strong> (<em>disk-based</em>) - miejsce 
+            przechowywania plików tymczasowych, pliki złożone w tym katalogu
+            przetrwają ponowne uruchomienie komputera. Okres przechowywania 
+            tych plików to 10 dni.</li>
+        <li><strong>/usr</strong> (<em>disk-based</em>) - skrót <em>usr</em>,
+            należy rozwinąć jako <em>ang. UNIX System Resources</em>. Ten
+            katalog jest kolejną dużą strukturą katalogów w systemie. W tym
+            katalogu przechowywane są wszystkie programy, więc wiekszość 
+            systemu. Na poniższej liście znajdują się rozpisane podkatalogi
+            tego katalogu:
+            <ul>
+              <li><strong>/usr/bin</strong> - katalog przechowuje większosć
+                  plików binarnych, wykorzystywanych w systemie, programów oraz
+                  poleceń.</li>
+              <li><strong>/usr/sbin</strong> - narzędzia administracyjne
+                  niedostępne dla zwykłych użytkowników, poza kilkoma
+                  programami. Ten katalog często nie jest ujęty podczas 
+                  wyszukiwania poleceń.</li>
+              <li><strong>/usr/lib</strong>, <strong>/usr/lib64</strong> - 
+                  biblioteki współdzielone oraz pliki statyczne, niektórych
+                  programów typu init.</li>
+              <li><strong>/usr/include</strong> - pliki nagłówkowe języka C</li>
+              <li><strong>/usr/local</strong> - miejsce przechowywania
+                  zewnętrznych programów instalowanych i
+                  wykorzystywanych przez administatorów, ten katalog zawiera w
+                  sobie podobną strukturę katalogową jak sam <em>/usr</em>.</li>
+              <li><strong>/usr/share</strong> - miejsce przechowywania stron
+                  podręcznika, dokumentacji czy przykładowych plików 
+                  konfiguracyjnych.</li>
+            </ul>
+        </li>
+        <li><strong>/var</strong> (<em>disk-based</em>) - katalog na zmienne
+            dane, katalog podobnie do <em>/usr</em> ma wewnątrz wiele znaczący
+            podkatalogów, takich jak:
+            <ul>
+              <li><strong>/var/log</strong> - katalog na pliki dzienników,
+                zbierane nie tylko z głównego rejestratora, ale i funkcji
+                rejestrowania samych usług.</li>
+              <li><strong>/var/opt</strong> - katalog na zmienne dane
+                oprogramowania instalowanego w katalogu <em>/opt</em></li>
+              <li><strong>/var/spool</strong> - katalog ten przechowuje dane
+                zanim zostaną przekazane lub pobrane przez właściwe komponenty,
+                na przykład poczta elektronicza w przypadku serwerów
+                pocztowych.</li>
+              <li><strong>/var/tmp</strong> - katalog przechowuje duże pliki
+                tymczasowe. Pliki złożone w tym katalogu przetrwają
+                ponowne uruchomienie systemu. Czas ich istnienia w tym katalog 
+                to 30 dni.</li>
+            </ul>
+        </li>
+      </ul>
+      <p>
+        Za pomocą polecenia <strong>tree</strong>, możemy wyświetlić strukturę
+        katalogą w postaci drzewa, jednak najpierw nauczymy się korzystać z
+        poleceń w <em>RHEL</em>.
+      </p>
+      <h2 id="2.3.usingcli">2.3. Obsługa wiersza poleceń i najprostsze polecenia</h2>
+      <p>
+        Obsługa wiersza poleceń zależy w znacznym stopniu od powłoki, ponieważ
+        to ona zajmuje się jego interpretacją i koniec końców wykonaniem
+        programu, którego nazwę podaliśmy chcąc wykonać polecenie. Aby móc
+        skorzystać w <em>RHEL</em> z wiersza poleceń musimy albo uruchomić w 
+        środowisku
+        graficznym aplikację <strong>Terminal</strong>, lub zalogować się
+        zdalnie za pomocą protokołu <em>SSH</em>. Uruchomienie terminala lub 
+        zalogowanie
+        się przez <em>SSH</em> uruchomi powłokę, która swoją gotowość na 
+        otrzymywanie
+        poleceń obwieści wyświetleniem <strong>znaku zachęty</strong>.
+      </p> 
+      <p>
+        Znak zachęty jest wskaźnikiem za kursorem po którym możemy wprowadzać 
+        do systemu
+        polecenia. Kiedyś znaki zachęty były pojedynczymi znakmi informującymi
+        o uprawnieniach z jakimi działa proces powłoki (o tym za chwilę). Teraz
+        znaki zwracają nazwę użytkownika, nazwę komputera oraz obecny katalog
+        roboczy wewnątrz nawiasu kwadratowego, następnie zanim znajduje się
+        znak krzyżyka (<strong>#</strong>) mówiący, że powłoka działa
+        uprawnieniami użytkownika <em>root</em> lub symbol dolara 
+        (<strong>$</strong>) mówiący, że połoka działa z uprawnieniami zwykłego
+        użytkownika. Poniżej przedstawiłem oba znaki:
+      </p>
+<pre class="code-block">
+[root@server1 ~]#
+
+[user@server1 ~]$
+</pre>
+      <p>
+        W różnych dystrybucjach, znak zachęty może różnorako wyglądąć. Możemy
+        dostować go do własnych potrzeb, wiele osób korzysta z jak 
+        najmniejszych
+        znaków zachęty, aby zaoszczedzić miejsce w wierszu polecenia. Teraz
+        możemy już wydawać polecenia.
+      </p>
+      <p>
+        Kazde polecenie w jakimkolwiek Uniksie, składa się z nazwy polecenia,
+        ewentualnych opcji oraz ewentualnych argumentów. Nie wszystkie
+        polecenia do uzyskania żądanych przez nas efektów wymagają opcji czy
+        argumentów.  
+      </p>
+<pre class="code-block">
+$ nazwa_polecenia [opcje] [argumenty]
+</pre>
+      <p>
+        Każde polecenie przed zatwierdzeniem możemy edytować, za pomocą
+        strzałek lub skrótów klawiszowych dostarczanych przez bibliotekę
+        <em>GNU Readline</em>. Więcej na ten temat znajdziemy w internecie.
+      </p>
+      <p>
+        Przez cały kurs będziemy poznawać jakieś polecenia ale w tym momencie
+        nauczymy się najprostszych z nich.
+      </p>
+      <h3 id="2.3.1.ls">2.3.1. Listowanie zawartości katalogu</h3>
+      <p>
+        Aby wyświetlić zawartość katalogu w powłoce, możemy użyć polecenia
+        <strong>ls</strong>. Polecenie bez podania argumentu w postaci
+        katalogu wyświetli zawartość folderu, w którym się znajdujemy.
+        Najważniejszymi opcjami między innymi są:
+      </p>
+      <ul>
+        <li><strong>-a</strong> - wyświetlanie wszystkich, elementów w katalogu
+            także tych, które normalnie nie są wyświetlane (plik i foldery,
+            których nazwa rozpoczyna się od kropki).</li>
+        <li><strong>-l</strong> - wyświetlenie szczegółowych informacji na
+            temat elementów. Informacja zwracana przez polecenie jest wówczas
+            podzielona na 9 pól, które kolejno oznaczają: typ pliku oraz
+            uprawnienia; liczbę dowiązań; nazwę użytkownika (właściciela pliku);
+            nazwę grupy do której należy ten plik; rozmiar w bajtach; czas
+            modyfikacji oraz nazwę elementu.</li>
+        <li><strong>-ld</strong> - wyświetla szczegółową informacje na temat
+            podanego jak argument katalogu, bez wyświetlania jego zawartości.
+            Jeśli nie podamy argumentu polecenie wyświetli informacje na temat
+            bierzącego katalogu.</li>
+        <li><strong>-lh</strong> - wyświetli szczegółowo informacje
+            na temat elementów w katalogu, wyświetlając ich rozmiar w
+            przeskalowanych wartościach, co ułatwi odczytanie go przez 
+            człowieka.</li>
+        <li><strong>-lt</strong> - wyświetli szczegółową listę elementów
+            posortową względem czasu modyfikacji od najnowszego pliku.</li>
+        <li><strong>-ltr</strong> - działanie podobne do <em>-lt</em>, ale
+            odwrócone, elementy zostaną wyświetlone od najstarszego.</li>
+        <li><strong>-R</strong> - wyświetlenie elementów w sposób 
+            rekurencyjny. Polecenie z tą opcją wyświetli zawartość katalogów
+            wraz z zawartością ich podkatalogów itd.</li>
+      </ul>
+      <p>
+        Poniżej znajduje się przykład najczęściej wykorzystywanego polecenia
+        <em>ls</em> wraz z opcjami:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# ls -al
+total 10576
+dr-xr-x---. 17 root root    4096 Jun 16 18:49 .
+dr-xr-xr-x. 18 root root     235 Jun  9 19:46 ..
+-rw-------.  1 root root    1197 Jun  9 19:59 anaconda-ks.cfg
+-rw-------.  1 root root    3908 Jun 16 18:50 .bash_history
+-rw-r--r--.  1 root root      18 Aug 10  2021 .bash_logout
+-rw-r--r--.  1 root root     141 Aug 10  2021 .bash_profile
+-rw-r--r--.  1 root root     429 Aug 10  2021 .bashrc
+drwxr-xr-x.  3 root root      17 Jun 16 18:14 bzipped
+drwx------.  8 root root     120 Jun 13 10:55 .cache
+-rw-r--r--.  1 root root      11 Jun 16 13:10 catfile1
+drwx------.  9 root root    4096 Jun 13 13:42 .config
+-rw-r--r--.  1 root root     100 Aug 10  2021 .cshrc
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Desktop
+drwxr-xr-x.  4 root root      30 Jun 16 16:44 dir20
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Documents
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Downloads
+drwxr-xr-x.  3 root root      55 Jun 16 11:34 etc
+-rw-r--r--.  1 root root 4986788 Jun 16 18:13 etc-bzipped.tar.bz2
+-rw-r--r--.  1 root root 5772869 Jun 16 18:12 etc-gzipped.tar.gz
+-rw-r--r--.  2 root root       0 Jun 16 17:26 file10
+-rw-r--r--.  2 root root       0 Jun 16 17:26 file20
+-rw-r--r--.  1 root root     579 Jun 16 11:07 fstab
+drwxr-xr-x.  3 root root      17 Jun 16 18:14 gzipped
+-rw-------.  1 root root      42 Jun 16 18:22 .lesshst
+drwx------.  3 root root      19 Jun 13 10:55 .local
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Music
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Pictures
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Public
+lrwxrwxrwx.  1 root root       6 Jun 16 17:30 soft10 -&gt; file10
+-rw-r--r--.  1 root root     129 Aug 10  2021 .tcshrc
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Templates
+drwxr-xr-x.  2 root root       6 Jun 13 10:55 Videos
+-rw-------.  1 root root    8264 Jun 16 18:38 .viminfo
+-rw-r--r--.  1 root root     464 Jun 16 18:38 vipractice
+</pre>
+      <p>
+        Podczas korzystania z wielu programów możemy natknąć się na wiele opcji.
+        Dzielą się one na długie i krótkie, opcje krótkie występują w
+        postaci pojedynczego znaku poprzedzonego jednym myślnikiem
+        (<strong>-</strong>). Opcje długie występuje w postaci pojedynczego
+        (najczęsciej, ponieważ to zależy od programu) słowa poprzedzonego dwoma 
+        myślnikami (<strong>--</strong>). W przypadku tak prostych poleceń jak
+        <em>ls</em> również możemy użyć długich opcji np. zamiast
+        <em>-a</em> możemy użyć <em>--all</em>.
+      </p>
+      <h3 id="2.3.2.pwd">2.3.2. Wyświetlenie bieżącego katalogu roboczego</h3>
+      <p>
+        Na pierwszy rzut oka mogłoby się wydawać po co nam to polecenie,
+        skoro w znaku zachęty na <em>RHEL</em> jest wyświetlona nazwa 
+        bieżącego
+        katalogu. Polecenie <strong>pwd</strong> wyświetla ścieżkę bezwzględną 
+        do bieżącego katalogu, a po drugie to polecenie ma bardzo ważną cechę
+        związaną z dowiązaniami, ale o tym będzie przy dowiązaniach. Do
+        normalnych zastosowań <em>pwd</em> nie potrzebuje żadnej opcji, ani
+        żadnego argumentu.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# pwd
+/root
+</pre>
+      <h3 id="2.3.3.cd">2.3.3. Poruszanie się wśrod katalogów</h3>
+      <p>
+        Generalnie, do zmiany bierzącego katalogu czy przejścia z/do 
+        innego katalogu służy polecenie <strong>cd</strong>. Pozwala ono na
+        kilka sztuczek.
+      </p>
+      <ul>
+        <li>Powrót do katalogu domowowego nie wymaga przy tym poleceniu żadnego
+          argumentu ani opcji, wystarczy wydać polecenie <em>cd</em>.</li>
+        <li>Polecenie zapamiętuje poprzedni katalog roboczy i powrót do niego
+          wymaga podania po poleceniu <em>cd</em> myślnika (<strong>-</strong>)
+          jako argumentu</li>
+        <li>W ścieżkach chcąć skrócić sobie pisanie, możemy użyć tyldy
+          (<strong>~</strong>) jako zamiennika katalogu domowego.</li>
+        <li>Chcąc przenieść się do katalogu nadrzędnego względem bierzącego
+          nie musimy znać jego nazyw wystarczy że poleceniu <em>cd</em> podamy
+          dwie kropki (<strong>..</strong>)</li>
+      </ul>
+      <p>
+        Poniżej zamieściłem przykłady kilku z nich.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# cd -
+/home/user
+[root@server1 user]# cd ..
+[root@server1 home]# cd 
+</pre>
+      <h3 id="2.3.4.tty">2.3.4. Identyfikacja urządzenia terminala</h3>
+      <p>
+        Czasmi może zajść potrzeba zidentyfikowania własnego urządania 
+        terminalowego służy do tego polecenie <strong>tty</strong>. Jeśli 
+        wynikiem działania tego polecenie będzie <em>/dev/pts*</em> oznacza to,
+        że korzystamy z emulatora terminala np. programu Terminal w środowisku
+        GNOME lub połączenia zdalnego za pomocą protokołu <em>SSH</em>. 
+        Jeśli naszę urządzenie to <em>/dev/tty*</em> oznacza to, że
+        korzystamy z jednej wirtualnych konsol dostępnych w systemie.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tty
+/dev/pts/0
+</pre>
+      <h3 id="2.3.5.uptime">2.3.5. Czas systemowy oraz załadowanie procesora</h3>
+      <p>
+        Większości dostępnych Uniksów zapewne zawierać będzie polecenie 
+        <strong>uptime</strong>. To niepozorne polecenie zawraca dużą ilość
+        informacji.
+      </p>
+      <ul>
+        <li>Czas systemowy,</li>
+        <li>Ilość czasu jaka upłyneła od uruchomienia systemu (tzw. 
+            <em>uptime</em>),</li>
+        <li>Ilość zalogowanych do systemu użytkowników,</li>
+        <li>Średnie załadowanie procesora w przeciągu minuty, 5 i 15 minut, ta
+            wartość pokazuje zużycie procesora, podając wartości ułamkowe jeśli
+            np. w ciągu jednej minuty jeden z wątków procesora był wykorzystany
+            w 50% otrzymamy wynik 0.50. Jeśli posiadamy procesor wielordzeniowy, 
+            ten wskaźnik może
+            wskazywać wartości powyżej 1, oznacza to że procesy wykorzystują
+            już więcej niż jeden wątęk/rdzeń.</li>
+      </ul>
+<pre class="code-block">
+[root@server1 ~]# uptime
+ 13:28:40 up 8 min,  1 user,  load average: 0.00, 0.12, 0.12
+</pre>
+      <h3 id="2.3.6.clear">2.3.6. Czyszczenie ekranu powłoki</h3>
+      <p>
+        Do czyszczenia terminala ze zbędnego wyjścia poleceń służy polecenie
+        <strong>clear</strong> lub kombinacja klawiszy <em>Ctrl+l</em>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# clear
+</pre>
+      <h3 id="2.3.7.which">2.3.7. Określanie ścieżki polecenia</h3>
+      <p>
+        Czasami w pewnych konfiguracjach lub też w skryptach powłoki niezbędne
+        będzie podanie ścieżki do konkretnego programu kryjącego się za nazwą
+        polecenia, w <em>RHEL</em> możemy zrobić to na trzy sposoby 
+        wykorzystując do
+        tego różne polecenia. Polecenia podałem w przykładzie w raz z
+        informacją zwracaną przez polecenie.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ which ls
+alias ls='ls --color=auto'
+       /usr/bin/ls
+[user@rhel90 ~]$ whereis ls
+ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz /usr/share/man/man1p/ls.1p.gz
+[user@rhel90 ~]$ type ls
+ls jest aliasem do ls --color=auto'
+</pre>
+      <p>
+        Które z tych poleceń będzie właściwe to już zależy, do czego będą nam
+        potrzebne tego typu informacje. Polecenie <em>whereis</em> wydaje się
+        szczególnie pomocne.
+      </p>
+      <h3 id="2.3.8.uname">2.3.8. Wyświetlenie informacji o systemie</h3>
+      <p>
+        Polecenie <strong>uname</strong> należy do poleceń, które są dość
+        niepozorne, ale za pomocą jego opcji możemy otrzymać wersję użytego
+        jądra, architekturę systemu i tym podobne informacje. Polecenie bez 
+        podania
+        żadnej z opcji zwraca wyłącznie nazwę systemu i jest to <em>Linux</em>.
+        Aby otrzymać wszelkie zwracane przez to polecenie informacje możemy 
+        użyć opcji <em>-a</em>. Resztę opcji znajdziemy na stronach
+        podręcznika (o tym będzie w dalszej części materiału).
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ uname -a
+Linux latitude-e5270 5.14.0-70.13.1.el9_0.x86_64 #1 SMP PREEMPT Thu Apr 14 12:42:38 EDT 2022 x86_64 x86_64 x86_64 GNU/Linux
+</pre>
+      <h3 id="2.3.9.lscpu">2.3.9. Wyświetlanie informacji o procesorze</h3>
+      <p>
+        W <em>RHEL</em> możemy łatwo sprawdzić informacje na temat zainstalowanego w
+        naszym komputerze procesora w przystępny sposób. Do dyspozycji mamy
+        bowiem polecenie <strong>lscpu</strong>. Wyświetla ono wszystkie
+        dostępne informacje jakie może znaleźć w systemie na temat tego
+        komponentu.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# lscpu
+Architecture:            x86_64
+  CPU op-mode(s):        32-bit, 64-bit
+  Address sizes:         39 bits physical, 48 bits virtual
+  Byte Order:            Little Endian
+CPU(s):                  1
+  On-line CPU(s) list:   0
+Vendor ID:               GenuineIntel
+  Model name:            Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz
+    CPU family:          6
+    Model:               78
+    Thread(s) per core:  1
+    Core(s) per socket:  1
+    Socket(s):           1
+    Stepping:            3
+    BogoMIPS:            5004.62
+    Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush
+                          mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology
+                          nonstop_tsc cpuid tsc_known_freq pni pclmulqdq monitor ssse3 cx16 pcid sse4_1 
+                         sse4_2 x2apic movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowpre
+                         fetch invpcid_single pti fsgsbase avx2 invpcid rdseed clflushopt md_clear flush
+                         _l1d
+Virtualization features: 
+  Hypervisor vendor:     KVM
+  Virtualization type:   full
+Caches (sum of all):     
+  L1d:                   32 KiB (1 instance)
+  L1i:                   32 KiB (1 instance)
+  L2:                    256 KiB (1 instance)
+  L3:                    3 MiB (1 instance)
+NUMA:                    
+  NUMA node(s):          1
+  NUMA node0 CPU(s):     0
+Vulnerabilities:         
+  Itlb multihit:         KVM: Mitigation: VMX unsupported
+  L1tf:                  Mitigation; PTE Inversion
+  Mds:                   Mitigation; Clear CPU buffers; SMT Host state unknown
+  Meltdown:              Mitigation; PTI
+  Spec store bypass:     Vulnerable
+  Spectre v1:            Mitigation; usercopy/swapgs barriers and __user pointer sanitization
+  Spectre v2:            Mitigation; Retpolines, STIBP disabled, RSB filling
+  Srbds:                 Unknown: Dependent on hypervisor status
+  Tsx async abort:       Not affected
+</pre>
+      <h2 id="2.4.gettinghelp">2.4. Uzyskiwanie pomocy</h2>
+      <h3 id="2.4.1.manpages">2.4.1. Strony podręcznika</h3>
+      <p>
+        W dystrybucjach Linuksa nie tylko w <em>RHEL</em> możemy znaleźć duża 
+        bazę
+        zawierającą opisy poleceń, plików konfiguracyjnych oraz innych
+        komponentów takich jak biblioteki. Służą temu strony podręcznika. Aby
+        uzyskać do nich dostęp wystarczy wydać polecenie <strong>man</strong>
+        podając jako argument interesujący nas komponent. Nie zawsze musi być
+        to polecenie. Strony podręcznika są podzielone na rozdziały czy też
+        sekcje ich opisy oraz numery sa zawarte na (o ironio) stronie
+        podręcznika polecenia <em>man</em>. Wydajmy poniższe polecenie aby
+        zapoznać się z nim oraz z ich organizacją.
+      </p>
+<pre class="code-block">
+[xf0r3m@hp-z600 ~]$ man man
+</pre>
+      <p>
+        Różne komponenty na Linuksie mogą mieć takie same nazwy. Polecenie
+        <em>man</em> zwraca pierwsze znalezione wystąpienie, jeśli wpiszemy
+        polecenie <code class="code-inline">man passwd</code> to otrzymamy
+        informacje na temat polecenia, ale jeśli interesowałoby nas poznanie
+        szczegółów pliku <em>/etc/passwd</em> musimy podać przed jego nazwą, 
+        numer rozdziału odpowiedzialny za pliki konfiguracyjne.
+      </p>
+<pre class="code-block">
+[xf0r3m@hp-z600 ~]$ man 5 passwd
+</pre>
+      <p>
+        Strony podręcznika, możemy przeszukiwać pod kątem występowania słów
+        kluczowych, w przypadku kiedy znamy zagadnienie ale nie znamy
+        odpowiedniego polecenia. Do tego celu możemy użyć opcji <em>-k</em>
+        polecenia <em>man</em> lub polecenia <strong>apropos</strong>. Wynik 
+        działania tych programów jest taki sam.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ apropos dos
+dos2unix (1)         - DOS/Mac to Unix and vice versa text file format converter
+dosfsck (8)          - check and repair MS-DOS FAT filesystems
+dosfslabel (8)       - set or get MS-DOS filesystem label or volume ID
+fatlabel (8)         - set or get MS-DOS filesystem label or volume ID
+filesystems (5)      - Linux filesystem types: ext, ext2, ext3, ext4, hpfs, iso9660, JFS, minix, msdos, ncpfs nfs, ntfs, proc, Reiserfs, smb, sysv, umsdos, vfat, XFS, xiafs
+fs (5)               - Linux filesystem types: ext, ext2, ext3, ext4, hpfs, iso9660, JFS, minix, msdos, ncpfs nfs, ntfs, proc, Reiserfs, smb, sysv, umsdos, vfat, XFS, xiafs
+fsck.fat (8)         - check and repair MS-DOS FAT filesystems
+fsck.msdos (8)       - check and repair MS-DOS FAT filesystems
+fsck.vfat (8)        - check and repair MS-DOS FAT filesystems
+mac2unix (1)         - DOS/Mac to Unix and vice versa text file format converter
+mkdosfs (8)          - create an MS-DOS FAT filesystem
+mkfs.fat (8)         - create an MS-DOS FAT filesystem
+mkfs.msdos (8)       - create an MS-DOS FAT filesystem
+mkfs.vfat (8)        - create an MS-DOS FAT filesystem
+unix2dos (1)         - DOS/Mac to Unix and vice versa text file format converter
+unix2mac (1)         - DOS/Mac to Unix and vice versa text file format converter
+vdosetuuid (8)       - sets a new uuid for the vdo volume stored on a backing store
+vdostats (8)         - Display configuration and statistics of VDO volumes
+</pre>
+      <p>
+        W pierwszej kolumnie znajduje się nazwa komponentu, w drugiej
+        (w nawiasie) numer rozdziału a następnie krótki opis.
+      </p>
+      <p>
+        Szukając opisu polecenia możemy posiłkować się poleceniem 
+        <strong>whatis</strong>. Polecenie to poszukuje konkretnego komponentu
+        na stronach podręcznika, a nie słowa kluczowego.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ whatis xdg-open 
+xdg-open (1)         - opens a file or URL in the user's preferred application
+</pre>
+      <p>
+        Polecenie <em>whatis</em>, zachowuje się identycznie jak polecenie
+        <em>man</em> z opcją <em>-f</em>.
+      </p>
+      <h3 id="2.4.2.helpincommand">2.4.2. Pomoc w samym poleceniu</h3>
+      <p>
+        Inny sposobem niż wertowanie stron podręcznika w celu znalezienia
+        odpowiedniej opcji jest po prostu wywołanie polecenia a opcją
+        <strong>--help</strong>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ ranger --help
+Usage: ranger [options] [path]
+
+Options:
+  --version             show program's version number and exit
+  -h, --help            show this help message and exit
+  -d, --debug           activate debug mode
+  -c, --clean           don't touch/require any config files.
+  --logfile=file        log file to use, '-' for stderr
+  --cachedir=dir        change the cache directory.
+                        (/home/xf0r3m/.cache/ranger)
+  -r dir, --confdir=dir
+                        change the configuration directory.
+                        (/home/xf0r3m/.config/ranger)
+  --datadir=dir         change the data directory.
+                        (/home/xf0r3m/.local/share/ranger)
+  --copy-config=which   copy the default configs to the local config
+                        directory. Possible values: all, rc, rifle, commands,
+                        commands_full, scope
+  --choosefile=OUTFILE  Makes ranger act like a file chooser. When opening a
+                        file, it will quit and write the name of the selected
+                        file to OUTFILE.
+  --choosefiles=OUTFILE
+                        Makes ranger act like a file chooser for multiple
+                        files at once. When opening a file, it will quit and
+                        write the name of all selected files to OUTFILE.
+  --choosedir=OUTFILE   Makes ranger act like a directory chooser. When ranger
+                        quits, it will write the name of the last visited
+                        directory to OUTFILE
+  --selectfile=filepath
+                        Open ranger with supplied file selected.
+  --show-only-dirs      Show only directories, no files or links
+  --list-unused-keys    List common keys which are not bound to any action.
+  --list-tagged-files=tag
+                        List all files which are tagged with the given tag,
+                        default: *
+  --profile             Print statistics of CPU usage on exit.
+  --cmd=COMMAND         Execute COMMAND after the configuration has been read.
+                        Use this option multiple times to run multiple
+                        commands.
+</pre>
+      <p>
+        Posiadanie tej opcji nie jest standardem, wiec nie wszystkie polecenia
+        będą ją mieć.
+      </p>
+      <h3 id="2.4.3.texinfo">2.4.3. Dokumentacja texinfo</h3>
+      <p>
+        Projekt <em>GNU</em>, zaproponował zmianę formatu dokumentacji 
+        programów, z
+        suchych stron podręcznika do dokumentów przypominających ksiązkę lub
+        inne dokumenty. Strony podręcznika nadal są podstawowym i wybudowanym
+        (w większość dystrybcji) źródłem  wiedzy na temat systemu i jego 
+        komponentów. 
+        Nie mniej jednak jeśli uznamy, że zawartość strony podręcznika nie jest
+        dla zadowalająca może spojrzeć też tam, o ile ten format jest
+        zainstalowany w naszym systemie. Dostęp do niego uzyskujemy za pomocą
+        polecenia <strong>info</strong> lub <strong>pinfo</strong>, następnie
+        podając nazwę polecenia jako argument. Wydając samo polecenie
+        <em>info</em>, możemy zobaczyć ile dokumentacji w formacie
+        <em>texinfo</em> znajduje się w systemie.
+      </p>
+      <h3 id="2.4.4.usrsharedoc">2.4.4. /usr/share/doc</h3>
+      <p>
+        Innym miejscem przechowującym jakieś informacje na temat poleceń czy
+        też programów może być katalog <em>/usr/share/doc</em>. Możemy w nim
+        znaleźć na przykład domyślne plik konfiguracyjne wielu usług 
+        (oczywiście zależy to czy zostaną one dodane do paczek z 
+        oprogramowaniem). Nie należy jednak
+        od razu skreślać tego katalogu, często mogą znajdować się tam
+        informacje, których nie znajdziemy na stronach podręcznika czy w
+        formacie <em>info</em> np. tutoriale lub gotowe konfiguracje.
+      </p>
+      <h3 id="2.4.5.rhdocs">2.4.5. Dokumentacja Red Hat Enterprise Linux</h3>
+      <p>
+        Innym źródłem informacji na temat obsługi systemu jest dokumentacja
+        <em>Red Hat</em> dostępna w internecie (dla <em>RHEL</em> 9) pod tym 
+        adresem:
+        <a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9</a>
+      </p>
+      <p>
+        Każdy zebranych tam tematów możemy pobrać w formacie HTML, PDF oraz
+        ePub (czytniki e-booków).
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Na egzaminie możemy korzystać ze wszystkiego co jest dostępne w systemie
+        warto pamiętać o tym. Jeśli będziemy mieć problemy z poleceniem
+        <em>man</em>, warto wydać polecenie <strong>mandb</strong> odświeży
+        to bazę danych stron podręcznika.
+      </p>
+      <h3 id="exec2.1">Ćwiczenie 1: Nawigacja pośród katalogów Linuksa</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie wirtualnej <em>server1</em>, 
+        wyświetl ścieżkę na której
+        się znajdujesz. W tym samym katalogu wyświetl wszystkie pliki.
+        Przjedź do katalogu <em>/etc</em> następnie wyświetl ścieżkę, na której
+        się znajdujesz, następnie powróć do poprzedniego katalogu i jeszcze
+        raz wyświetl ścieżkę.
+      </p>
+      <h3 id="exec2.2">Ćwiczenie 2: Rożne zadania</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie <em>server1</em> w terminalu 
+        polecenie <em>tty</em>.
+        Następnie uruchom kilka kart terminala wydaj w nich to samo polecenie
+        i porównaj zwracane wartości. Wyświetl czas pracy systemu oraz 
+        średnie obciążenie procesora. Za pomocą trzech poznanych poleceń 
+        wyświetl lokalizacje polecenia <em>vgs</em>.
+      </p>
+      <h3 id="exec2.3">Ćwiczenie 3: Informacje o systemie</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie <em>server1</em>
+        za pomocą poznanego polecenia wyświetl wszystkie informacje o systemie
+        (oczywście w miarę możliwości polecenia). Następnie użyj innego
+        polecenia aby sprawdzić informacje na temat zainstalowanego w
+        komputerze procesora.
+      </p>
+      <h3 id="exec2.4">Ćwiczenie 4: Używanie pomocy</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie <em>server1</em>
+        Wyświetl stronę podręcznika polecenia <em>uname</em> oraz stronę
+        podręcznika dla pliku <em>/etc/shadow</em>. Wykonaj trzy polecenia:
+        <code class="code-inline">apropos ext4</code>,
+        <code class="code-inline">man -k ext4</code>,
+        <code class="code-inline">whatis group</code>. Czym różnią się
+        informacje zwracane przez te polecenia?
+      </p>
+      <h2 id="ch2summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale skupiliśmy się na podstawach obsługi systemu,
+        poznaliśmy środowisko graficzne. Odświerzyliśmy sobie informacje na
+        temat hierachicznego systemu plików wykorzystywanego w Uniksach.
+        Zapoznaliśmy się z terminalem i podstawowymi poleceniami. Na koniec
+        dowiedzieliśmy się gdzie możemy szukać pomocy na temat poleceń, plików
+        konfiguracyjnych i tego typu rzeczy.
+      </p>
+      <h1 id="3.fileoperations">3. Operacje na plikach</h1>
+      <p>
+        W poprzedni rodziale poznaliśmy podstawy poruszania się po systemie,
+        przejrzeliśmy środowisko graficzne, zapoznaliśmy się z wierszem
+        polecenia oraz z najbardziej podstawowymi poleceniami. Było to swoiste
+        zapoznanie się z systemem operacyjny. Teraz pora w nim trochę 
+        popracować.
+        Ludzie zazwyczaj kiedy wspomagają swoją prace komputerem, pracują na
+        danych. Te dane są zazwyczaj zebrane w pliki i od omówienia rodzajów
+        plików dostępnych na Linuksie rozpoczniemy ten rozdział.
+      </p> 
+      <h2 id="3.1.filetypes">3.1. Rodzaje plików</h2>
+      <p>
+        W Uniksach możemy wymienić 7 rodzajów różnych plików. W tych systemach
+        nie jest istotne rozszerzenie oraz zawartość tych plików. Dla systemu
+        zawsze będzie to <strong>zwykły plik</strong>. Wszystkie pliki
+        niewymienione na poniższej liście, które przyjdą nam do głowy są 
+        plikami zwykłymi.
+      </p>
+      <p>
+        Zatem w Uniksach możemy wyróżnić takie rodzaje plików jak:
+      </p>
+      <ul>
+        <li><strong>Plik zwykły</strong> - plik zwykłe przechowywują dane, są
+          to wszelkiej maści pliki tekstowe, pliki binarne z programami oraz
+          inne.</li>
+        <li><strong>Katalog</strong> - jest struktura organizacyjna systemu
+          plików, stosowana w celach porządkowych zwykłych plików w systemie
+          plików.</li>
+        <li><strong>Plik urządzenia znakowego</strong> - w przypadku określenia
+          <em>znakowy</em> stosuje się także określenie <strong>surowy</strong>
+          (ang. <em>raw</em>). Pliki te wykorzystywane są do komunikacji z
+          urządzaniami wykorzysującymi interfejs szeregowy.</li>
+        <li><strong>Pliki urządzeń blokowych</strong> - Plików tych używa się
+          są do komunikacji z urządzeniami wykorzystującymi interfejs
+          równoległy. Głównie są to dyski.</li>
+        <li><strong>Dowiązania symboliczne</strong> - przypominają skróty znane
+          z innych systemów operacyjnych. Jest to plik wskazujący na inny
+          plik lub katalog.</li>
+        <li><strong>Nazwane potoki, gniazda</strong> - są to pliki, które
+          służą do komunikacji miedzyprocesowej. Omawianie ich tutaj wychodzi
+          poza ramy tego materiału.</li>
+      </ul>
+      <p>
+        Nie ma się też za bardzo co rozwodzić nad każdym z tych typów plików.
+        Rodzaju pliku możemy ustalić podczas wyświetlania zawartości katalogu.
+        Wskaźnikiem jest pierwszy znak w pierwszej kolumnie informacji 
+        zwracanej przez polecenie <em>ls -l</em>. Informacje zwracane dla 
+        poszczególnych typów wyglądają następująco:
+      </p>
+<pre class="code-block">
+#Zwykły plik:
+[root@server1 ~]# ls -l anaconda-ks.cfg 
+-rw-------. 1 root root 1197 Jun  9 19:59 anaconda-ks.cfg
+
+#Katalog:
+[root@server1 ~]# ls -ld bzipped/
+drwxr-xr-x. 3 root root 17 Jun 16 18:14 bzipped/
+
+#Urządzenie znakowe:
+[root@server1 ~]# ls -l /dev/console
+crw--w----. 1 root tty 5, 1 Jun 17 15:20 /dev/console
+
+#Urządzenie blokowe:
+[root@server1 ~]# ls -l /dev/sda1
+brw-rw----. 1 root disk 8, 1 Jun 17 15:20 /dev/sda1
+
+#Dowiązanie symboliczne:
+[root@server1 ~]# ls -l soft10 
+lrwxrwxrwx. 1 root root 6 Jun 16 17:30 soft10 -&gt; file10
+</pre>
+      <p>
+        Pierwsze znaki, pierwszej kolumny róznią się od siebie w zależności
+        od typu plików. Jest jeszcze kilka róznic. Pliki urządzeń nie posiadają
+        rozmiaru, tylko dwie liczby oddzielone od siebie przecinkiem. Te liczby
+        to numer główny oraz numer poboczny. Numer główny określa rodzaj
+        urządzenia (użyty sterownik urządzenia), z kolei numer poboczny jest 
+        jego unikalny identyfikatorem
+        w systemie. Innym rodzajem, jest dowiązanie symboliczne, które nazwa
+        wskazuje na ścieżke innego pliku, ale do tego typu plików 
+        wrócimy poźniej.
+      </p>
+      <p>
+        Te informacje które są zwracane oprócz nazwy pliku przez polecenie,
+        <em>ls</em> z odpowiednią opcją to tak zwane 
+        <strong>metadane</strong>. Większą ich ilość możemy wyświetlić za
+        pomocą polecenia <strong>stat</strong>. Na poniższym przykładzie
+        zamieszczono więcej metadanych zwykłego pliku z poprzedniego przykładu:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# stat anaconda-ks.cfg 
+  File: anaconda-ks.cfg
+  Size: 1197           Blocks: 8          IO Block: 4096   regular file
+Device: fd00h/64768d   Inode: 6126703     Links: 1
+Access: (0600/-rw-------)  Uid: (    0/    root)   Gid: (    0/    root)
+Context: system_u:object_r:admin_home_t:s0
+Access: 2022-06-16 10:37:11.765639347 +0200
+Modify: 2022-06-09 19:59:42.592326645 +0200
+Change: 2022-06-09 19:59:42.592326645 +0200
+ Birth: 2022-06-09 19:59:42.237318552 +0200
+</pre>
+      <p>
+        Zwykłe pliki na Uniksach nie muszą mieć rozszerzenia, więc aby przed
+        uruchomieniem pliku upewnić się co to jest, mamy do dyspozycji takie
+        narzędzie jak program <strong>file</strong>, który zbada zawartość
+        podanego mu w argumencie pliku. 
+      </p>
+<pre class="code-block">
+[root@server1 ~]# file test 
+test: Bourne-Again shell script, ASCII text executable
+</pre>
+      <p>
+        Plik nie ma rozszerzenia <em>.sh</em> a mimo to pozostaje skryptem
+        powłoki.
+      </p>
+      <h2 id="3.2.compressionandarchiving">3.2. Kompresja i archiwizowanie</h2>
+      <p>
+        Kompresja pozwala na zmniejszenie objętości plików za pomocą
+        zaawansowanych algorytmów, dzięki czemu możemy zaoszczędzić miejsce
+        na dysku. Wadą takiego przechowywania danych jest dłuższy
+        czas oczekiwania na ich gotowość do pracy, ponieważ dane przed tym
+        należy zdekompresować. Archizowanie może służyć do zebrania wielu
+        małych plików w jeden duży. Na Uniksach możemy wymienić dwa natywne
+        narzędzia służące do kompresji i jedno do archiwizowania.
+      </p>
+      <h3 id="3.2.1.gzip">3.2.1. gzip</h3>
+      <p>
+        Natywnym i dostępnym na każdym systemie sposobem na kompresje danych
+        jest <strong>gzip</strong>. Algorytmy zawarte w tym narzędziu
+        kompresują dane, powodując zmniejszenie ich objętość. Narzędzie do 
+        każdego skompresowanego pliku dodaje rozszerzenie <em>.gz</em>. Aby 
+        skompresować plik wystarczy podać jego nazwę lub ścieżkę do niego jako
+        argument poleceniu <em>gzip</em>.
+      </p>
+<pre class="code-block">
+#Plik przed kompresją
+[root@server1 ~]# ls -l fstab 
+-rw-r--r--. 1 root root 579 Jun 16 11:07 fstab
+
+#Kompresja
+[root@server1 ~]# gzip fstab
+
+#Plik po kompresji
+[root@server1 ~]# ls -l fstab.gz 
+-rw-r--r--. 1 root root 350 Jun 16 11:07 fstab.gz
+</pre>
+      <p>
+        Jak możemy zauważyć rozmiar pliku zmniejszył się. Zwróćmy uwagę na to
+        iż narzędzie nie działa na kopii pliki tylko kompresuje bezpośrednio
+        podany plik. Aby plik zdekompresować możemy użyć polecenia 
+        <strong>gunzip</strong>
+      </p>
+<pre class="code-block">
+[root@server1 ~]# gunzip fstab.gz
+</pre>
+      <p>
+        Dla plików skompresowanych za pomocą polecenia <em>gzip</em>, możemy
+        podejrzeć listę skompresowanych plików (w przypadku jednego pliku
+        może być to użyteczne do wyświetlenia statystki kompresji) 
+        wykorzystując 
+        opcje <em>-l</em> i podając jako argument skompresowany plik.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# gzip -l fstab.gz 
+         compressed        uncompressed  ratio uncompressed_name
+                350                 579  43.7% fstab
+</pre>
+      <h3 id="3.2.2.bzip">3.2.2. bzip2</h3>
+      <p>
+        Program <em>bzip2</em> jest obecnie standardem kompresji wśród wielu
+        Uniksów. Jest wolniejszy od <em>gzip</em>, ale skompresowane przez
+        niego pliki są mniejsze. Więc pozostaje w naszej gestii, który z nich
+        będziemy stosować. Do skompresowanych przez <em>bzip2</em> plików
+        dodawane jest rozszerzenie <em>.bz2</em>. A kompresja za pomocą tego
+        narzędzia wygląda następująco:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# ls -lh test
+-rw-r--r--. 1 root root 250M Jun 17 17:21 test
+[root@server1 ~]# bzip2 test 
+[root@server1 ~]# ls -lh test.bz2 
+-rw-r--r--. 1 root root 210 Jun 17 17:23 test.bz2
+</pre>
+      <p>
+        Dekompresja takiego pliku takiego pliku wyglada analogicznie do
+        narzędzia <em>gunzip</em>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# bunzip2 test.bz2
+[root@server1 ~]# ls -lh test 
+-rw-r--r--. 1 root root 250M Jun 17 17:25 test
+</pre>
+      <p>
+        W przypadku polecenia <em>bzip2</em> nie mamy możliwośći wyświetlenia
+        listy skompresowanych plików (statystyk kompresji).
+      </p>
+      <h3 id="3.2.3.tar">3.2.3. tar</h3>
+      <p>
+        Program <strong>tar</strong> nie służy do kompresji, a do archiwizcji.
+        Jego zadaniem jest stworzenie jednego pliku z wielu innych plików lub 
+        z całego katalogu. Na początku program swojego istnienia program 
+        <em>tar</em> domyślnie tworzył archiwa na napędach taśmowych, dlatego
+        też jeśli ma on tworzyć archiwum do pliku potrzebna będzie odpowiednia
+        opcja, i ta funkcjonalność pozostała po dziś dzień.
+      </p>
+      <p>
+        Opcje tego programu możemy podawać na trzy różne sposoby, wpisując
+        z myślnikami każdą opcje po kolei, wypisując opcje pod jednym
+        myślnikiem, lub nie używać myślnika w ogóle. Do stworzenia archiwum
+        potrzebujemy dwóch opcji, pierwszej <em>-c</em> - tworzącej archiwum
+        oraz drugiej <em>-f</em> - nakazujące stworzenie archiwum w podanym
+        jako argument opcji pliku. Poniżej znajdują się opisane wyżej użycia
+        polecenia <em>tar</em> do stworzenia archiwum.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -c -f etc_tarred.tar /etc
+tar: Removing leading `/' from member names
+[root@server1 ~]# tar -cf etc_tarred1.tar /etc
+tar: Removing leading `/' from member names
+[root@server1 ~]# tar cf etc_tarred2.tar /etc
+tar: Removing leading `/' from member names
+</pre>
+      <p>
+        Zwróćmy uwagę na komunikat programu, który usuwa ze scieżek
+        wskazujących pliki (ponieważ użyłem ścieżki bezwzględnej) początkowy
+        ukośnik, aby przy wypakowywaniu nie nadpisać ważnych plików 
+        systemowych. Warto dodać, iż ja tworzyłem te archiwa jako 
+        superużytkownik, w momencie gdy <em>root</em> używa polecenia
+        <em>tar</em>, używana jest domyślnie opcja <em>-p</em>, która powoduje
+        zachowanie wszystkich atrybutów plików, w przypadku zwykłego
+        użytkownika ta opcja musi zostać jawnie podana.
+      </p>
+      <p>
+        Rozpakowanie archiwum wymaga podania opcji <em>-x</em> oraz opcji
+        <em>-f</em> ze wskazaniem pliku archiwum.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -xf etc_tarred1.tar -C /tmp
+[root@server1 ~]# ls -ld /tmp/etc
+drwxr-xr-x. 132 root root 8192 Jun 17 15:20 /tmp/etc
+</pre>
+      <p>
+        W tym przykładzie użyłem jeszcze jednej ważnej opcji <em>-C</em>, która
+        nakazuje poleceniu <em>tar</em> zmianę katalogu przed wypakowaniem
+        archiwum.
+      </p>
+      <p>
+        Za pomocą opcji <em>-t</em>, możemy podejrzeć zawartość archiwum. Opcja
+        <em>-v</em> powoduje wyświetlanie komunikatów przez program.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -tvf etc_tarred2.tar
+drwxr-xr-x root/root         0 2022-06-17 15:20 etc/
+lrwxrwxrwx root/root         0 2022-06-09 19:47 etc/mtab -&gt; ../proc/self/mounts
+-rw-r--r-- root/root       579 2022-06-09 19:44 etc/fstab
+-rw------- root/root         0 2022-06-09 19:44 etc/crypttab
+drwxr-xr-x root/root         0 2022-06-09 19:47 etc/lvm/
+drwxr-xr-x root/root         0 2022-06-09 19:44 etc/lvm/devices/
+-rw-r--r-- root/root       286 2022-06-09 19:44 etc/lvm/devices/system.devices
+drwx------ root/root         0 2022-06-09 20:48 etc/lvm/archive/
+-rw------- root/root      1891 2022-06-09 20:48 etc/lvm/archive/rhel_00000-557804270.vg
+drwx------ root/root         0 2022-06-09 20:48 etc/lvm/backup/
+-rw------- root/root      1890 2022-06-09 20:48 etc/lvm/backup/rhel
+drwx------ root/root         0 2022-02-16 13:01 etc/lvm/cache/
+-rw-r--r-- root/root    111694 2022-02-16 13:01 etc/lvm/lvm.conf
+-rw-r--r-- root/root      2299 2022-02-16 13:01 etc/lvm/lvmlocal.conf
+...
+</pre>
+      <p>
+        Chcąc dodać plik do archiwum, wystarczy użyć opcji <em>-r</em> nie
+        trzeba go rozpakowywać i dodawać tych plikiów wystarczy wskazać
+        archiwum a następnie pliki, które chce się dodać. Plik zostanie dodany
+        na koniec archiwum.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -rvf etc_tarred2.tar vipractice.bz2 
+vipractice.bz2
+
+[root@server1 ~]# tar -tvf etc_tarred2.tar
+...
+-rw-r--r-- root/root       208 2022-06-09 19:46 etc/.updated
+-rw-r--r-- root/root       307 2022-06-16 18:38 vipractice.bz2
+</pre>
+      <p>
+        Dodawaniu plików do archiwum nie służy wyłącznia opcja <em>-r</em>, ale
+        również
+        <em>-u</em>, która dodaje nowsze pliki na końcu archwium.
+        Wyświetlając zawrtość takiego archiwum, możemy zobaczyć pliki o tych
+        samych nazwach. Te nazwy oczywiście odpowiadają różnym wersjom tych
+        plików.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -uvf etc_tarred.tar /etc/nanorc
+tar: Removing leading `/' from member names
+/etc/nanorc
+tar: Removing leading `/' from hard link targets
+
+[root@server1 ~]# tar -tvf etc_tarred2.tar
+...
+-rw-r--r-- root/root       208 2022-06-09 19:46 etc/.updated
+-rw-r--r-- root/root     10373 2022-06-19 09:47 etc/nanorc
+</pre>
+      <p>
+        Po zebraniu wszystkich plików do archiwum, może okazać się że jest to
+        sporych rozmiarów plik. Polecenie <em>tar</em>, pozwala na zastosowanie
+        poznanych wcześniej algorytmów kompresji podczas tworzenia archwium.
+      </p>
+      <ul>
+        <li><strong>gzip:</strong> opcja <em>-z</em>
+<pre class="code-block">
+[root@server1 ~]# tar -czf etc-gzipped.tar.gz /etc
+</pre>
+        </li>
+        <li><strong>bzip2:</strong> opcja <em>-j</em>
+<pre class="code-block">
+[root@server1 ~]# tar -cjf etc-bzipped.tar.bz2 /etc
+</pre>
+        </li>
+      </ul>
+      <p>
+        Rozpakowując skompresowane archiwa w RHEL możemy rozpakować podając
+        takie same opcje jak w przypadku nie skompresowanych archiwów.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tar -xf etc-gzipped.tar.gz -C /tmp
+</pre>
+      <p>
+        Program rozpozna po zawartości pliku algortym kompresji. Wiecej
+        informacji na temat polecenia <em>tar</em> znajduje na stronie
+        podręcznika.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Na egzaminie będziemy mieć określną ilość czasu na wykonanie zadań
+        egzaminacyjnych, dlatego też operacje kompresji czy archiwizacji
+        plików będą przeprowadzane na małych plikach, aby nie tracić czasu.
+      </p> 
+      <h2 id="3.3.vim">3.3. Edycja plików za pomocą edytora Vim</h2>
+      <p>
+        Podczas wykonywania zadań związanych z administracją systemem, 
+        niezbędna
+        może być edycja jakiegoś pliku. Edytor <strong>Vim</strong> jest 
+        standardem jeśli
+        chodzi o edycję plików. Ten edytor w wersji podstawowej jaką jest
+        program <em>Vi</em> jest dostępny w większości Uniksów. W przypadku
+        w wielu dystrybucji Linuksa preinstalowany jest <em>Vim</em>, ze
+        względu na to ten edytor jest jednym z podstawowych narzędzi. Lepiej
+        jest nauczyć się rozwiązania, które możemy zastosować domyślnie bez
+        zbędnej
+        ingerencji w system (bez instalacji ulubionego edytora, który znamy).
+      </p>
+      <p>
+        Edytor <em>Vim</em> może działać w trzech trybach:
+      </p>
+      <ul>
+        <li><strong>tryb poleceń</strong> - domyślny tryb pracy programu,
+          <em>Vim</em> oczekuje na wprowadzenie polecenia. Ten tryb jest
+          uruchamiany w momencie uruchomienia programu. Polecenia są
+          przypisane do poszczególnych znaków na klawiaturze.</li>
+        <li><strong>tryb wprowadzania</strong> - tryb ten służy do edycji
+          tekstu, uruchamiany za pomocą polecenia <em>i</em> lub <em>a</em>.</li>
+        <li><strong>tryb ostatniej lini</strong> - ten tryb możemy również
+          nazwać wierszem polecenia lub poprawnie trybem <em>ex</em>. 
+          Uruchamiany jest poprzez wciśnięcie
+          dwukropka (<strong>:</strong>) w trybie poleceń. Po tym znaku
+          podajemy polecenie.</li> 
+      </ul>
+      <h3 id="3.3.1.startingvim">3.3.1. Podstawy obsługi Vim</h3>
+      <p>
+        Edytor <em>Vim</em> uruchamiamy, jak każde inne polecenie. Podając jego
+        nazwę
+        w wierszu polecenia. Podczas uruchamiania możemy podać plik jako
+        argument lub też użyć polecenia trybu ostatniej linii <em>:o</em>
+        po czym podać ścieżkę do pliku.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# vim test.txt
+</pre>
+      </p>
+        Poruszanie po tekscie odbywa się w trybie poleceń za pomocą klawiszy:
+      </p>
+      <ul>
+        <li><strong>h</strong> - przesunięcie kursora w lewo</li>
+        <li><strong>j</strong> - przesunięcie kursora w dół</li>
+        <li><strong>k</strong> - przesunięcie kursora w górę</li>
+        <li><strong>l</strong> - przesunięcie kursora w prawo</li>
+      </ul>
+      <p>
+        Przejście do edycji tekstu, wymaga użycia polecenia <strong>i</strong> 
+        co spowoduje rozpoczęcie edycji w pozycji kursora lub polecenia 
+        <strong>a</strong>, które spowoduje przesunięcie kursora o jedną 
+        pozycję i rozpoczęcie edycji, polecenie <em>a</em> możemy tłumczyć 
+        jako dopisywanie (ang. <em>append</em>), a <em>i</em> jako wprowadzanie 
+        (ang. <em>insert</em>).
+      </p>
+      <p>
+        Opuszczenie trybu wprowadzania i powrót do trybu polecenia wymaga
+        naciśnięcia klawisza <em>Esc</em> (ang. <em>escape</em>). Przjście do 
+        trybu polecenia
+        jest wymagane, aby przenieść kursor w inne miejsce. W tym trybie 
+        również poprzez polecenia ostatniej linii zapisujemy zmiany w pliku
+        oraz opuszczamy edytor. Zmiany w tekscie również możemy
+        porzućić, nie musimy ich zapisywać. Poniżej umieściłem kilka poleceń
+        trybu ostatniej linii, służacych od zapisywania i opuszczania edytora.
+      </p>
+      <ul>
+        <li><strong>:w</strong> - zapisanie zmian w pliku oraz pozostanie w
+          w edytorze</li>
+        <li><strong>:x</strong> - zapisanie zmian w pliku oraz opuszczenie
+          <em>Vim</em></li>
+        <li><strong>:q</strong> - opuszczenie <em>Vim</em>.</li>
+      </ul>
+      <p>
+        Każdej z tych opcji może towarzyszyć wykrzyknik (<strong>!</strong>),
+        więc jeśli chcielibyśmy porzucić zmiany w pliku i wyjść należy użyć
+        polecenia <em>:q!</em>. Możemy czasami spotkać się z uprawnieniami,
+        które nie pozwolą nam zapisać zmian w pliku. Rozwiązać tego typu
+        problem możemy na dwa sposoby, wymusić zapisanie zamian za pomocą
+        wykrzyknika (działa to tylko w przypadku, gdy superużytkownik chce
+        zapisać zmiany w pliku tylko odczytu), lub podać ścieżkę do nowego 
+        pliku poleceniu <em>:w</em>, poźniej skopiować w plik w docelowe
+        miejsce.
+      </p>
+      <h3 id="3.3.2.othervimcommands">3.3.2. Pozostałe polecenia Vim</h3>
+      <p>
+        Vim posiada bogatą kolekcję komend trybu poleceń oraz trybu ostatniej
+        linii, na poniższej liście znajdują się część z nich, możemy
+        wykorzystać je do sprawniejszego używania edytora <em>Vim</em>.
+      </p>
+      <p><strong>Komendy trybu poleceń:</strong></p>
+      <ul>
+        <li><strong>^ - Shift + 6</strong> - przeniesie kursora na początek
+          linii.</li>
+        <li><strong>$ - Shift + 4</strong> - przeniesie kursora na koniec 
+          linii.</li>
+        <li><strong>Ctrl + f</strong> - przewinięcie tekstu o jedną stronę w
+          przód.</li>
+        <li><strong>Ctrl + b</strong> - przewinięcie tekstu o jedną stronę w
+          tył.</li>
+        <li><strong>x</strong> - usunięcie znaku wskazywanego przez kursor,
+          znak tak naprawdę zostaje wycięty i poźniej może zostać wklejony.</li>
+        <li><strong>dd</strong> - usunięcie/wycięcie całej linii, linia
+          podobnie jak znak może zostać wklejona.</li>
+        <li><strong>v</strong> - przejście <em>Vim</em> w tryb wizualny
+          (tutaj nie omawiany), pozwala zaznaczać tekst co ułatwia kopiowanie
+          oraz wycinanie.</li>
+        <li><strong>y</strong> - kopiowanie zaznaczenia w trybie wizualnym.</li>
+        <li><strong>d</strong> - wycinanie/usuwanie w trybie wizualnym.</li>
+        <li><strong>p</strong> - wklejanie.</p>
+        <li><strong>u</strong> - cofnięcie się o jedną zmianę, odpowiednik
+          <em>Ctrl+z</em>.</li>
+        <li><strong>Ctrl+r</strong> - tzw. <em>redo</em>, powrót do stanu przed
+          cofnięciem zmiany. Czasami bardzo przydatna funkcja.</li>
+        <li><strong>. - kropka</strong> - powtórzenie ostatniego polecenia.
+          Jeśli ostatnim poleceniem było wprowadzanie, to polecenie wklei
+          cały wprowadzony tekst do momentu zmiany polecenia.</li>
+        <li><strong>/ - slash</strong> - przeszukiwanie tekstu w przód.</li>
+        <li><strong>? - znak zapytania</strong> - przeszukiwanie tekstu w tył.</li>
+        <li><strong>n</strong> - następne wystąpienie frazy w tekście</li>
+        <li><strong>N</strong> - poprzednie wystąpienie frazy w tekscie. W
+          przypadku przeszukiwania w tył, działanie poleceń <em>n</em> oraz
+          <em>N</em> jest odwrócone.</li>
+      </ul>
+      <p>
+        W przypadku trybu poleceń, możemy zwielokrotnić działanie tych poleceń,
+        wprowadzając liczbę wykonywania tego polecenia przed poleceniem. Na 
+        przykład jeśli chcemy
+        usunąć 3 linie to zamiast wydawać trzykrotnie polecenie <em>dd</em>,
+        możemy nacisnąć <em>3</em> następnie <em>dd</em> i trzy linie spod
+        kursora zostaną usunięte/wycięte.
+      </p>
+      <p><strong>Polecenia trybu ostatniej linii:</strong></p>
+      <ul>
+        <li><strong>:set number</strong> - włącza numerowanie linii.</li>
+        <li><strong>:o</strong> - otwiera plik, jako argument podajemy ścieżkę
+          do pliku.</li>
+        <li><strong>:%s/old/new</strong> - zamiana pierwszego wstąpienia słowa 
+          <em>old</em> słowem <em>new</em>.</li>
+        <li><strong>:%s/old/new/g</strong> - zamiana wszystkich wystąpień słowa
+          <em>old</em> słowem <em>new</em>.</li>
+        <li><strong>:6,11co4</strong> - polecenie kopiuje zawartość linii od
+          6 do 11 i wkleja ją po 4 linii.</li>
+        <li><strong>:3,5m6</strong> - polecenie przenosii linię od 3 do 5 na
+          miejsce po linii numer 6.</li>
+        <li><strong>:6,8d</strong> - polecenie usuwa linie od 6 do 8.</li>
+        <li><strong>:r</strong> - polecenie wprowadza w miejscu kursora
+          zawartość pliku podanego jako argument.
+      </ul>
+      <p>
+        Podczas korzystania <em>Vim</em> istotna jest praktyka. Dlatego trzeba
+        przesiąść się na niego i zacząć tworzyć w nim pliki.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Podczas egzaminu, możemy spotkać się z zadaniem w którym trzeba
+        zmienić jakiś plik. Dostępność <em>Vim</em> na maszynie
+        egzaminacyjnej jest niemal pewna, dlatego też nauczenie się jego 
+        obsługi jest dość istotne.
+      </p>
+      <h2 id="3.4.filesanddirectories">3.4. Pliki i katalogi</h2>
+      <p>
+        Jaka kolwiek praca z komputerem prędzej czy poźniej będzie wymagać
+        operacji na plikach i katalogach. Poniżej przedstawiam najprostsze
+        czynności jakie możemy wykonywać na tych elementach. 
+      </p>
+      <h3 id="3.4.1.createfilesanddirs">3.4.1. Tworzenie plików i katalogów</h3>
+      <p>
+        Tworzenie plików może zrealizować na kilka sposób. Jednym z nich jest
+        wykorzystanie polecenia <strong>touch</strong>, które służy generalnie
+        do uaktualnienia czasów dostępu oraz modyfikacji, jednak kiedy podany
+        plik nie istnieje to zostanie on utworzony przez to polecenie.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# touch plik1
+[root@server1 ~]# ls -l plik1
+-rw-r--r--. 1 root root 0 Jun 19 14:52 plik1
+</pre>
+      <p>
+        Jak widać na powyższym przykładzie został utworzony plik, którego
+        wielkość to całe 0 bajtów. Innym sposobem na utworzenie pliku jest
+        wykorzystanie polecenia <em>Vim</em>, w którym zapisując zmiany w 
+        nowym pliku, tworzymy go mimochodem. Ostanim ze sposobów jest
+        utworzenie plików ze strumienia (stumienie będą opisywane w dalszej
+        części tego materiału), za pomocą polecenia <strong>cat</strong>,
+        które omówimy sobie w następnym podrozdziale. Wydając następujące
+        polecenie:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# cat &gt; plik2
+test1
+test2
+test3
+test4
+test5
+</pre>
+      <p>
+        Uruchamiając to polecenie przełączymy strumienie tak, aby wszystko
+        co zostanie wpisane do terminala trafi do pliku (w dużym skrócie). Taką
+        edycję pliku możemy zakończyć naciskając kombinacje klawiszy
+        <em>Ctrl+d</em>.
+      </p>
+      <p>
+        Za tworzenie katalogów odpowiedzialne jest polecenie 
+        <strong>mkdir</strong>. Polecenie to utworzy katalog o nazwie podanej
+        jako argument. Ważną opcją tego polecenia jest <em>-p</em>, za pomocą
+        którego jesteśmy wstanie tworzyć z poziomu pojedynczego polecenia całe
+        struktury katalogów. Opcja ta powoduje utworzenie katalogów podanych
+        na ścieżce, które nie istnieją.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# mkdir dir1
+</pre>
+      <h3 id="3.4.2.listingfiles">3.4.2. Wyświetlanie zawartości pliku</h3>
+      <p>
+        Na Uniksach do wyświetlania zawartości plików mamy kilka rozwiązań
+        pierwszym z nich jest wspomnianie już polecenie <strong>cat</strong>.
+        Polecenie wyświetli zawartość pliku podanego jako argument w terminalu.  
+      </p>
+<pre class="code-block">
+[root@server1 ~]# cat plik2 
+test1
+test2
+test3
+test4
+test5
+</pre>
+      <p>
+        Na Uniksach, obok polecenia <em>cat</em> występuje polecenie
+        <strong>tac</strong>, które ma takie samo zastosowanie jak to wyżej
+        wymienione, wyświetlając jednak zawartość pliku odwrotnie od końca. 
+        Poniższy przykład zaraz to zobrazuje:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tac plik2 
+test5
+test4
+test3
+test2
+test1
+</pre>
+      <p>
+        Podczas wyświetlania dużych plików ich zawartość może nie mieścić się 
+        na
+        ekranie, czy też w oknie terminala. Do wyświetlania tego typu plików
+        wykorzystuje się takie polecenia jak <strong>more</strong> czy
+        <strong>less</strong>. Oba dzielą wyświetloną treść plików na strony
+        wielkości ekranu bądź terminala. Program <em>more</em> nie jest za
+        bardzo zaawansowanym narzędziem. Wyświetlając pliki za jego pomocą nie
+        mamy zbyt dużego pola manewru. Możemy przesuwać stronę po stronie, do
+        końca pliku. Dlatego też znacznie lepszym rozwiązaniem jest
+        wykorzystanie polecenia <em>less</em>, który pozwala poruszać się
+        po tekscie w góre i w dół, ale również pozwala na wyszukiwanie fraz 
+        w tekscie, możemy również nawigować po za pomocą klawiszy znanych z 
+        programu <em>Vim</em>. Program <em>less</em> uruchomi się szybciej niż,
+        program <em>more</em>, ponieważ nie musi on załadować całego pliku od 
+        razu.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# less /var/log/messages
+</pre>
+      <p>
+        Ostatnim już sposobem na wyświetlenie zawartości plików jest, użycie
+        polecenia <strong>head</strong> oraz <strong>tail</strong>, ich
+        zadaniem jest wyświetlenie kilku początkowych (domyślnie 10) linii
+        z podanego jako argument pliku - polecenie <em>head</em> lub kilku
+        ostatnich (również 10) linii z podanego pliku - polecenie <em>tail</em>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail /var/log/messages
+Jun 19 13:59:33 server1 systemd[1]: Finished dnf makecache.
+Jun 19 14:18:23 server1 cupsd[964]: REQUEST localhost - - "POST / HTTP/1.1" 200 182 Renew-Subscription successful-ok
+Jun 19 15:16:43 server1 cupsd[964]: REQUEST localhost - - "POST / HTTP/1.1" 200 182 Renew-Subscription successful-ok
+Jun 19 15:28:22 server1 systemd[1]: Starting dnf makecache...
+Jun 19 15:28:23 server1 dnf[2173]: Updating Subscription Management repositories.
+Jun 19 15:28:23 server1 dnf[2173]: Unable to read consumer identity
+Jun 19 15:28:23 server1 dnf[2173]: This system is not registered with an entitlement server. You can use subscription-manager to register.
+Jun 19 15:28:23 server1 dnf[2173]: Metadata cache refreshed recently.
+Jun 19 15:28:23 server1 systemd[1]: dnf-makecache.service: Deactivated successfully.
+Jun 19 15:28:23 server1 systemd[1]: Finished dnf makecache.
+</pre>
+      <p>
+        Domyślną ilość wypisywanych linii możemy regulować poprzez podanie po
+        myślniku (<strong>-</strong>) żądanej liczby.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail -5 /var/log/messages
+Jun 19 15:28:23 server1 dnf[2173]: Unable to read consumer identity
+Jun 19 15:28:23 server1 dnf[2173]: This system is not registered with an entitlement server. You can use subscription-manager to register.
+Jun 19 15:28:23 server1 dnf[2173]: Metadata cache refreshed recently.
+Jun 19 15:28:23 server1 systemd[1]: dnf-makecache.service: Deactivated successfully.
+Jun 19 15:28:23 server1 systemd[1]: Finished dnf makecache.
+</pre>
+      <p>
+        Polecenie <em>tail</em> ma jedną bardzo istoną opcję, która pozwala
+        śledzić na bierząco zmiany w pliku, ta opcja to <em>-f</em>.
+      </p>
+      <p>
+        Poleceniem związanym z zawartością plików, ale nie z jej wyświetlaniem
+        może być polecenie <strong>wc</strong>, które domyślnie wyświetla
+        ilość linii, liczbę słów oraz bajtów. 
+      </p>
+<pre class="code-block">
+[root@server1 ~]# wc /var/log/messages
+  639  7503 61333 /var/log/messages
+</pre>
+      <h3 id="3.4.3.copyingandmoving">3.4.3. Kopiowanie i przenoszenie plików i katalogów</h3>
+      <p>
+        Pracując z plikami, być może wystąpić potrzeba skopiowania bądź
+        przeniesienia danych w inne miejsce. Za operację kopiowania
+        odpowiedzialnie jest polecenie <strong>cp</strong>. Jako pierwszy
+        argument przyjmuje ono ścieżkę lub plik źródłowy, jako drugi ścieżkę
+        lub plik docelowy.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# cp plik2 plik3
+</pre>
+      <p>
+        W przypadku gdy dany plik już istnieje w podanym katalogu polecenie
+        zapyta się czy nadpisać docelowy plik, ale tylko w przypadku
+        superużytkownika, bowiem on w konfiguracji swojej powłoki posiada 
+        <em>alias</em> (nazwę zastępczą) <em>cp</em> dla polecenia 
+        <em>cp -i</em>, opcja <em>-i</em> włącz tryb interaktywy, czyli właśnie
+        takie pytania.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# cp plik1 plik3 
+cp: overwrite 'plik3'? n
+</pre>
+      <p>
+        Za pomocą polecenia <em>cp</em> możemy kopiować całe katalogi z
+        podkatalogami przy użyciu opcji <em>-r</em>, która włącza kopiowanie
+        rekurencyjne. Jeśli atrybuty plików są dla nas ważne, to żeby nie
+        nadpisać ich należy użyć opcji <em>-p</em>.
+      </p>
+      <p>
+        Za przenoszenie plików odpowiedzialne jest polecenie 
+        <strong>mv</strong>, które ma jeszcze jedną ważną cechę ukrytą w
+        mechanice swojego działa. Otóż jeśli będzie przenosić plik lub katalog
+        w ramach tego samego katalogu, to zmieni on tylko swoją nazwę.
+      </p>
+      <p>
+        Polecenie <em>mv</em> w przypadku superużytkownika, posiada podobny
+        alias co w przypadku polecenia <em>cp</em>, polecenie jest uruchamiane
+        domyślnie z opcją pytającą o nadpisanie elementu docelowego.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# mv plik1 plik3 
+mv: overwrite 'plik3'? n
+</pre>
+      <p>
+        Polecenie <em>mv</em> nie potrzebuje żadnej opcji, aby
+        przenieść cały katalog wraz z podkatalogami.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# mv gzipped /tmp
+[root@server1 ~]# ls -ld /tmp/gzipped/
+drwxr-xr-x. 3 root root 17 Jun 16 18:14 /tmp/gzipped/
+</pre>
+      <h3 id="3.4.4.removefilesanddirs">3.4.4. Usuwanie plików i katalogów</h3>
+      <p>
+        Zbędne plik i katalogi możemy usunąć, za pomocą polecenia <em>rm</em>.
+        Polecenie do usunięcia katalogu wymaga podania nazwy pliku jako
+        argumentu.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# rm plik1 
+rm: remove regular empty file 'plik1'? y
+</pre>
+      <p>
+        Polecenie <em>rm</em> również jest aliasem, z tą samą opcją co
+        <em>cp</em> czy <em>mv</em>. Aby usunąć cały katalog wraz
+        podkatalogami, należy użyć kolejno opcji <em>-r</em> -
+        uruchamiającej usuwanie rekurencjne oraz opcji <em>-f</em>,
+        wymuszające odpowiedź <em>y</em> na wszystkie pytania.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# rm -rf /tmp/etc
+</pre>
+      <p>
+        Usuwanie plików i katalogów posiadając uprawnienia superużytkownika,
+        może skończyć się katastrofą. Pomyłka w tym poleceniu może uszkodzić
+        system. Dlatego też należy zachować szczególną ostrożność przy
+        korzystaniu z tego polecenia, a w szcególności w połączeniu z
+        <strong>nazwami wieloznacznymi</strong> (będzie o tym przy okazji
+        omawiania powłoki BASH).
+      </p>
+      <p>
+        Do usuwania pustych katalogów, możemy użyć polecenia 
+        <strong>rmdir</strong>, jak i opcji <em>-d</em> polecenia <em>rm</em>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# rm -d dir1/
+rm: remove directory 'dir1/'? y
+[root@server1 ~]# rmdir dir2
+</pre>
+      <p class="exap_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Polecenia manipulacji plikami są podstawowymi czynnościami związnymi
+        z administracją każdego Uniksa, więc warto przyswoić wiedzę zebraną
+        w tym podrozdziale. 
+      </p>
+      <h2 id="3.5.links">3.5. Dowiązania</h2>
+      <p>
+        Wśród systemów uniksowych, możemy w kategoriach manipulacji plikami
+        wyróżnić takie elementy jak <strong>dowiązania</strong>. Dowiązania
+        są najprościej rzecz biorąc są elementami, które wskazują na inne pliki.
+        Dowiązania możemy podzielić na <strong>twarde</strong> oraz 
+        <em>symboliczne</em>.
+      </p>
+      <h3 id="3.5.1.hardlinks">3.5.1. Dowiązania twarde</h3>
+      <p>
+        <strong>Twarde dowiązania</strong> nie są same w sobie stricte plikami.
+        Pliki bowiem znajdują na urządzeniach służacych do przechowywania
+        danych. Systemy plików przechowują metadane plików, ich atrybuty oraz
+        informacje w jakich obszarch, której z pamięci masowych należy szukać
+        zawartości pliku, aby ludzie mogli się nimi posługiwać używa się nazw
+        plików. Taką własnie nazwą jest twarde dowiązanie. Dla eksperymentu
+        utworzymy pusty plik, o nazwie <em>hard1</em>, oto jego artybuty
+      </p>
+<pre class="code-block">
+[root@server1 ~]# ls -li hard1 
+6043841 -rw-r--r--. 1 root root 0 Jun 19 17:31 hard1
+</pre>
+      <p>
+        Pierwsza kolumna zawiera numer <strong>i-node</strong> jest to 
+        identyfikator
+        wpisu w bazie danych systemu plików, ktory zawiera metadane na
+        temat pliku. W trzeciej kolumnie atrybutów znajduje się wartość
+        <code class="code-inline">1</code>. Ta kolumna przedstawia ilość
+        dowiązań twardych. Każdy zwykły plik posiada co najmniej jedno 
+        dowiązanie - identyfikującą bezpośrednio plik nazwę. Tworząc kolejne
+        twarde dowiązanie, podłączamy kolejną nazwę tego pliku. Teraz utwórzmy
+        dowiązanie o nazwie <em>hard2</em> do pliku <em>hard1</em>. Dowiązania
+        tworzymy za pomocą polecenia <strong>ln</strong>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# ln hard1 hard2
+[root@server1 ~]# ls -li hard*
+6043841 -rw-r--r--. 2 root root 0 Jun 19 17:31 hard1
+6043841 -rw-r--r--. 2 root root 0 Jun 19 17:31 hard2
+</pre>
+      <p>
+        Zwróć my uwagę na to, iż <code class="code-inline">hard2</code>
+        wskazuje na ten sam numer <em>i-node</em>, czyli wskazuje na ten sam
+        pliki. Liczba dowiązań uległa zmianie tak samo w przypadku
+        <code class="code-inline">hard1</code> jak i 
+        <code class="code-inline">hard2</code>, ponieważ na ten sam plik
+        wskazują dwa dowiązania. Zawartość pliku możemy zmieniać odwołując
+        czy to do <em>hard1</em> czy <em>hard2</em>, tak samo jest 
+        z atrybutami, ponieważ obie nazwy wskazują na ten sam węzeł
+        <em>i-node</em> (wpis w bazie danych systemu plików), jeśli usuń my 
+        teraz plik <em>hard1</em>, to tak naprawdę usuniemy jedno z dowiązań.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# rm hard1
+rm: remove regular empty file 'hard1'? y
+[root@server1 ~]# ls -li hard*
+6043841 -rw-r--r--. 1 root root 0 Jun 19 17:31 hard2
+</pre>
+      <p>
+        Dowiązania twarde mogą powodować bałagan w plikach, ponieważ mimo
+        usunięcia on dalej istnieje pod inną nazwą. Dopiero usunięcie
+        wszystkich dowiązań, ostatecznie kończy egzystencje pliku w pamięci
+        masowej, ponieważ systemy plików, pliki bez dowiązań uznają za
+        nie potrzebne i realokują miejsce przechowania zawartości tego pliku.
+      </p>
+      <h3 id="3.5.2.symlinks">3.5.2. Dowiązania symboliczne</h3>
+      <p>
+        Innym rodzajem dowiązań jest <strong>dowiązanie symboliczne</strong>.
+        Często są one porównywane do skrótów znanych z systemów Windows i tak
+        na prawdę taka jest ich rola. Dowiązania symboliczne mają wskazywać
+        na inne pliki. W przeciwieństwie do dowiązań twardych, te dowiązania
+        są jednak odrębnymi plikami (tak jakby), posiadają one bowiem wpis
+        w bazie danych systemu plików, ale w miejscu przeznaczonym na adres
+        przechowywania danych pliku na dysku lub innej pamięci znajduje się
+        scieżka do pliku źródłowego, na który wskazuje dowiązanie. Zatem tego
+        rodzaju elementy mają własne atrybuty. Wielkość dowiązania
+        symbolicznego zależy od ilość znaków na ścieżce do pliku źródłowego.
+        Dowiązania symboliczne tworzymy za pomocą tego samego narzędzia co
+        dowiązania twarde, dodając tylko opcję <em>-s</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ln -s symfile symlink1
+[user@server1 ~]$ ls -l symlink1
+lrwxrwxrwx. 1 user user 7 Jun 20 19:28 symlink1 -&gt; symfile
+</pre>
+      <p>
+        Dowiązania symboliczne mogłoby  wydawać się, że są w wstanie zastąpić
+        kopiowanie. Kopiując plik, odwzrowywuje się jego zawartość w innym
+        miejscu na pamięci masowej, tworząc odrębny nienaruszony plik. Tworząc
+        dowiązanie, podłączamy się pod istniejący już plik, który może być
+        zmieniony
+        nie tylko przez użytkowników, ale też programy. Dowiązania 
+        symbolicznego
+        możemy użyć jak wymienionego wcześniej skrótu, chcąc zaoszczędzić
+        sobie pisania długich ścieżek do głęboko osadzonych katalogów w 
+        systemie
+        ewentualnie ułatwić pisanie ścieżek w skryptach oraz programach.
+      </p>
+      <p>
+        Przechodząc do folderu wskazywanego przez dowiązanie symboliczne jeśli
+        wyświetlimy scieżkę obecnego katalogu roboczego, zobaczymy ścieżkę
+        z uwzględeniem tego dowiązania. Aby odkryć prawdziwą ścieżkę należy
+        polecenia <strong>pwd</strong> z opcją <em>-P</em>.
+      </p>
+      <h3 id="exec3.1">Ćwiczenie 1: Archiwa</h3>
+      <p>
+        Na maszynie <em>server1</em> jako superużytkownik, utwórz
+        skompresowane za pomocą programu <em>gzip</em> archiwum z zawartością
+        katalogu <em>/etc</em>. Powtórz czynność tym razem z użyciem programu
+        <em>bzip2</em>. Porównaj wielkość tych archiwów. Na koniec rozpakuj
+        oba archiwa bez zaznaczania algorytmu kompresji (bez podawania
+        odpowiedniej opcji).
+      </p>
+      <h3 id="exec3.2">Ćwiczenie 2: Praktyka z Vim-a</h3>
+      <p>
+        Na maszynie <em>server1</em> jako zwykły użytkownik, utworz przepisując
+        treść ćwiczenia nr. 1, każde zdanie w odrębnej linii, zapisz zmiany w 
+        pliku o nazwie <em>vimpractice</em> i zamknij edytor. Otwórz plik w
+        edytorze ponownie, wyświetl numery linii. Skopiuj linię 2 i 3 na koniec
+        pliku, tak aby było łącznie 6 linii. Przenieś linię nr. 3 w miejsce
+        pierwszej. Przejdź na koniec pliku i dodaj do niego zawartośc w pliku
+        <em>.bash_profile</em> (znajdziesz go w katalogu domowym użytkownika).
+        Zamień wszystkie wszystkie wystąpienia słowa <em>profile</em> na
+        <em>pro file</em>. Usuń linię od 5 do 8, zapisz zmiany w pliku i
+        opuść edytor. Na koniec wyświetl podsumowanie pliku za pomocą polecenia
+        <em>wc</em>.
+      </p>
+      <h3 id="exec3.3">Ćwiczenia 3: Manipulacja plikami</h3>
+      <p>
+        Na maszynie <em>server1</em> jako zwykły użytkownik, utwórz jeden
+        dowolny plik oraz jeden katalog, wyświetl ich atrybuty, sprawdź
+        uprawnienia, nazwę właściciela oraz grupę do której ten plik należy.
+        Co się stanie gdy spróbujesz przenieść utworzony wcześniej plik do
+        katalogu <em>/var/log</em>. Przenieś plik oraz katalog do katalogu
+        <em>/tmp</em>. Utwórz duplikat pliku i zmień jego nazwę na jakąkolwiek 
+        inną. Usuń wszystkie pliki utworzone na potrzeby tego ćwiczenia.
+      </p>
+      <h2 id="ch3summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale zapoznaliśmy się, z typowymi zadaniami związanymi z
+        administracją plikami w systemie. Poznaliśmy edytor Vim, którego
+        nauka wymaga zachodu, aczkolwiek nie pójdzie ona na marne. Ten edytor
+        w uboższej podstawowej wersji w postaci programu <em>Vi</em> 
+        spotkamy w każdym Uniksie, zatem będzie potrafili sprawnie edytować
+        pliki w każdym systemie, niezależnie od tego czy nasz ulubiony edytor
+        jest dostępny. Ciekawszą rzeczą w tym rodziale z pewnością były 
+        dowiązania symboliczne. W następnym rodziale skupimy się na
+        uprawnieniach plików i katalogów, oraz przekonamy się jak potężnym
+        narzędziem jest polecenie <em>find</em>.
+      </p>
+      <h1 id="4.advancedfilemanagement">4. Zaawansowane zarządzanie plikami</h1> 
+      <p>                                                                       
+        W Uniksach możemy zabezpieczyć pliki i katalogi przed ingerencją 
+        innych użytkowników. Służą temu specjalny rodzaj zabezpieczeń jakim są   
+        uprawnienia.                                                            
+      </p>                                                                      
+      <h2 id="4.1.basicspermission">4.1. Uprawnienia podstawowe</h2>            
+      <p>                                                                       
+        Uprawnienia przypisywane są w trzech klasach, klasie użytkownika        
+        (<strong>u</strong>) nazwywanego również właścicielem elementu; grupie  
+        (<strong>g</strong>), do której należy ten plik oraz                    
+        oraz innym użytkownikom systemu (<strong>o</strong>), ta klasa          
+        uprawnień jest również oznaczna jako uprawnienia publiczne.             
+      </p>                                                                      
+      <p>                                                                       
+        Każdej z tych klas możemy przypisać odpowiednie uprawnienia takie jak:  
+        prawo do odczytu (<strong>r</strong>), prawo do zapisu                  
+        (<strong>w</strong>) oraz prawo do wykonania (<strong>x</strong>).
+      </p>
+      <p>
+        Za nim zaczniemy zmieniać uprawnienia, nauczymy się je identyfikować.
+        Uprawnienia do pliku możemy wyświetlić za pomocą polecenia <em>ls -l</em>
+        lub polecenia <em>stat</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l file1
+-rw-r--r--. 1 user user 0 Jun 21 14:21 file1
+</pre>
+      <p>
+        Uprawnienia znajdują się w pierwszej kolumnie:
+        <code class="code-inline">-rw-r--r--.</code>, łącznie 11 znaków, ale
+        nas będzie interesować tylko 9 w środku. Pierwszy znak oznacza typ 
+        pliku, natomiast kropka związana jest z kontekstem <em>SELinux</em>,
+        nie będziemy się teraz tym zajmować. Te dziewięć pól są to miejsca
+        przeznaczone na uprawnienia poszczególnych klas. Pierwsze trzy pola 
+        z lewej to uprawnienia użytkownika (właściciela), kolejne trzy pola
+        to uprawnienia grupy do której należy ten plik natomiast pozostałe 
+        trzy to uprawnienia publiczne, stosowane wobec użytkowników nie
+        związanych z tym elementem. Uprawnienia przypisane każdej z klas
+        układają się kolejno w <em>rwx</em>, myślnik na którymś z tych miejsce
+        oznacza brak takiego prawa w danej klasie.
+      </p>
+      <p>
+        Każde z określonych praw pozwala nam, na wykonanie innych czynności
+        związanych z tym elementem. Prawo <em>read</em> pozwala na odczyt
+        zawartości pliku oraz jego skopiowanie, w przypadku
+        katalogów pozwala na wyświetlenie jego zawartości. Prawo <em>write</em>
+        pozwala na modyfikowanie elementu, wraz z jego usunięciem. Ostatnie
+        prawo <em>execute</em> pozwala na uruchomienie pliku o ile jest to
+        plik wykonywalny, w przypadku katalogów to prawo jest niezbędne aby
+        użytkownik mógł przejść do niego (za pomocą polecenia <em>cd</em>).
+      </p>
+      <p>
+        Zatem w przypadku pliku z powyższego przykładu, właściciel może czytać 
+        i pisać, a grupa
+        oraz wszyscy inni mogą tylko czytać, dla nich wówczas ten plik jest
+        plikiem tylko do odczytu.
+      </p>
+      <p>
+        Prawdopodobnie kiedyś bedziemy chcieli ukryć jakieś pliki lub będziemy
+        musieli dać uprawnienia jednemu z użytkowników do innych plików
+        w systemie, wówczas wymagana będzie zmiana uprawnień.
+      </p>
+      <p>
+        Poszczególnym klasom (<strong>u</strong>, <strong>g</strong>, 
+        <strong>o</strong>) możemy nadać (<strong>+</strong>), obebrać
+        (<strong>-</strong>)
+        lub przypisać (<strong>=</strong>) odpowiednie uprawnienia. Do
+        manipulacji uprawnieniami służy polecenie <strong>chmod</strong>, jako
+        pierwszy argument przyjmuje on sekwencje zmiany uprawnień (uprawnienia)
+        a jako drugi plik lub katalog, którego mają się tyczyć uprawnienia.
+      </p> 
+      <p>
+        Załóżmy, że plik z powyższego przykładu jest skryptem i musimy nadać
+        użytkownikowi prawo do wykonania, grupie prawo do zapisu i wykonania
+        a pozostałym użytkownikom zabrać uprawnienia, ponieważ ten plik nie
+        powinien być stosowany poza grupą. Aby zrealizować tę zmianę
+        uprawnień należy wydać poniższe polecenie:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ chmod u+x,g+wx,o-r file1
+</pre>
+      <p>
+        Po zmianie, uprawnienia do tego pliku prezentują się w następujący
+        sposób:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l file1
+-rwxrwx---. 1 user user 0 Jun 21 14:21 file1
+</pre>
+      <p>
+        Zapis uprawnień w tej postaci, który swoją drogą nazwa się zapisem
+        symbolicznym, wymaga dużo pisania. Uprawnienia można zmieniać łatwiej
+        jednak wymagać to będzie więcej myślenia. 
+      </p>
+      <p>
+        Każde z omówionych wcześniej praw posiada swoją wagę, te wagi sumują
+        się dając uprawnienia dla konkretnej klasy. A więc: prawo do odczytu
+        (<strong>r</strong>) posiada wagę <strong>4</strong>, prawo do zapisu
+        (<strong>w</strong>) posiada wagę <strong>2</strong> a prawo do 
+        wykonania (<strong>x</strong>) posiada wagę
+        <strong>1</strong>. Brak prawa (<strong>-</strong>) ma wagę 
+        <strong>0</strong>. Tak złożone razem sumy tych wag dają uprawnienia
+        do pliku czy katalogu. Chcąc określić uprawnienia pliku z pierwszego
+        przykładu jescze przed zmianą uprawnień, będą one wynosić:
+        <strong>644</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l file1
+-rw-r--r--. 1 user user 0 Jun 21 14:21 file1
+----------------------------------------------
+u = rw- = 4 + 2 + 0 = 6
+g = r-- = 4 + 0 + 0 = 4
+o = r-- = 4 + 0 + 0 = 4
+ugo = 644
+</pre>
+      <p>
+        Natomiast uprawnienia po zmianie bedą wynosić:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l file1
+-rwxrwx---. 1 user user 0 Jun 21 14:21 file1
+----------------------------------------------
+u = rwx = 4 + 2 + 1 = 7
+g = rwx = 4 + 2 + 1 = 7
+o = --- = 0 + 0 + 0 = 0
+ugo = 770
+</pre>
+      <p>
+        W ten sposób przeliczonymi uprawnieniami (tzw. uprawnieniami 
+        bezwględnymi, ponieważ przypisują one uprawnienia każdej z klas) możemy
+        posługiwać się podczas ich zmiany przy użyciu polecenia <em>chmod</em>
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ chmod -v 644 file1
+mode of 'file1' changed from 0770 (rwxrwx---) to 0644 (rw-r--r--)
+[user@server1 ~]$ chmod -v 770 file1
+mode of 'file1' changed from 0644 (rw-r--r--) to 0770 (rwxrwx---)
+</pre>
+      <p>
+        Na powyższym przykładzie zastosowałem opcję <em>-v</em>, która
+        wyświetla jak zmieniają się uprawnienia oraz przedstawia je w obu
+        formach. W przypadku wyświetlonej wartości liczbowej, pierwsze
+        zero z lewej strony jest miejscem na uprawnienia specjalne o których
+        będzie za chwilę, w przypadku standardowych uprawnienień nie ma ono
+        znaczenia.
+      </p>
+      <p>
+        Zapis uprawnień bezwzględnych w zapisie symbolicznym wyglądał by
+        następująco:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ chmod -v u=rw,g=r,o=r file1
+mode of 'file1' changed from 0770 (rwxrwx---) to 0644 (rw-r--r--)
+</pre>
+      <p>
+        Definiując uprawnienia bezwzględne, posługujemy się cyframi od 0 do 7.
+        Są to wszystkie cyfry systemu liczbowego o podstawie 8 (tzw. ósemkowy 
+        lub oktalny) dlatego też często nazwa się takie ustalanie uprawnień 
+        trybem oktalnym. 
+      </p>
+      <p>
+        Podczas ustalania uprawnień dla plików lub katalogów, nie ma znaczenia
+        jakiego trybu użyjemy, nie ma lepszego i gorszego. Jest tryb
+        czytelniejszy oraz szybszy do zapisania.
+      </p>
+      <p>
+        Na koniec jako ciekawostke podam iż istnieje czwarta dodatkowa klasa
+        oznaczająca 
+        wszystkie klasy (<strong>a</strong>), za jej pomocą można nadawać,
+        odbierać i przypisywać takie same uprawnienia dla wszystkich klas.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ chmod -v a=rwx file1
+mode of 'file1' changed from 0644 (rw-r--r--) to 0777 (rwxrwxrwx)
+</pre>
+      <h3 id="4.1.1.defaultpermissions">4.1.1. Uprawnienia domyślne</h3>
+      <p>
+        Każdy nowoutworzony plik czy katalog Uniksie ma już z góry przypisane 
+        uprawnienia i są nimi 666 dla plików oraz 777 dla katalogów. 
+        Uprawnienia te są korygowane za pomocą wartości <strong>umask</strong>. 
+      </p>
+      <p>
+        Wartość <em>umask</em> (ang. <em>user mask</em>) jest maską uprawnień
+        stosowaną na tworzonych przez użytkowników nowych plikach i katalogach.
+        Każdy użytkownik ma swoją indywidualną maskę i może ją dowolnie 
+        zmieniać.
+        Maska ma za zadanie usunięcie tych praw, których nie życzymy sobie
+        widzieć w poszczególnych klasach. Aby wyświetlić maskę użytkownika
+        należy wydać poniższe polecenie: 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ umask
+0022
+</pre>
+      <p>
+        Maska w przypadku <em>RHEL</em> 9 wygląda tak jak na powyszym 
+        przykładzie. Ta
+        wartość usunie z klasy grupy oraz z klasy pozostałych użytkowników
+        prawo do zapisu. Rachunek uprawnień jest bardzo prosty.
+      </p>
+<pre class="code-block">
+#W przypadku plików:
+
+0666
+0022 -
+------
+0644
+
+#W przypadku katalogów:
+
+0777
+0022 -
+------
+0755
+</pre>
+      <p>
+        Chcąc zmienić maskę wystarczy wydać polecenie:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ umask 002
+[user@server1 ~]$ umask
+0002
+</pre>
+      <p>
+        Tak zdefiniowana maska usunie tylko prawo do zapisu w klasie
+        pozostałych użytkowników dla każdego nowego pliku i katalogu. Maska
+        o tej wartości była domyślną maską dla zwykłych użytkowników w 
+        <em>RHEL</em> 8.
+        Wartość maski zdefiniowanej z poziomu wiersza poleceń, utrzyma się
+        tylko przez czas trwania otwartej sesji terminala. Po jego zamknięciu 
+        lub
+        wylogowaniu się maska wróci do poprzedniej wartości. Jeśli chcemy aby
+        wartości tej maski została zapisana na stałe, należy umieść polecenie
+        <em>umask</em> w jednym z plików uruchomieniowych powłoki, będzie o tym
+        w dalszej części tego materiału.
+      </p>
+      <h3 id="4.1.2.changefileowner">4.1.2. Zmiana właściciela oraz grupy pliku</h3>
+      <p>
+        Do zmiany właściciela pliku oraz grupy, do której on należy służy
+        polecenie <strong>chown</strong>, które przyjmuje jako pierwszy
+        argument trzy możliwe wersje: parę <strong>właściciel:grupa</strong>;
+        samego właściela lub nazwę grup poprzedzoną dwukropkiem
+        (<strong>:</strong>) a następnie pliki. Poniższy przykład obrazuje
+        wszystkie trzy możliwe zmiany właściciela oraz grup, do której należy
+        plik.
+      </p>
+<pre class="code-block">
+[root@server1 tmp]# chown user100:user100 acluser
+[root@server1 tmp]# ls -l acluser 
+-rw-rw-r--. 1 user100 user100 9 Jun 22 18:25 acluser
+[root@server1 tmp]# chown user acluser
+[root@server1 tmp]# ls -l acluser 
+-rw-rw-r--. 1 user user100 9 Jun 22 18:25 acluser
+[root@server1 tmp]# chown :user acluser
+[root@server1 tmp]# ls -l acluser
+-rw-rw-r--. 1 user user 9 Jun 22 18:25 acluser
+</pre>
+      <h2 id="4.2.specialpermissions">4.2. Uprawnienia specjalne</h2>
+      <p>
+        Poza podstawowym rodzajem uprawnień w Uniksach istnieją dodatkowe
+        uprawnienia, których zadaniem może być podniesienie uprawnień w
+        systemie, zaoszczędzenie czasu lub ochrona przed skasowaniem pliku w
+        miejscach gdzie wszyscy mają uprawnienia zapisu. Teraz omówimy sobie
+        każdy z nich.
+      </p>
+      <h3 id="4.2.1.setuid">4.2.1. Uprawnienia bitu setuid</h3>
+      <p>
+        Każde z podstawowych praw, możemy określić mianej bitu, z uprawnieniami
+        specjalnymi jest podobnie, każde z nich jest kolejnym bitem (prawem) o
+        szczególnym znaczeniu. Tak jest i tym przypadku. Bit 
+        <strong>setuid</strong> służy do podniesienia uprawnień. Jest on
+        oznaczany małą lub wielką literą <em>s</em> w klasie
+        użytkownika/właściciela. Ma on 
+        zastosowanie głównie na plikach wykonywalnych. Kiedy uruchomimy program
+        z ustawionym takim bitem, program ten będzie działać z uprawnieniami
+        właściciela tego pliku. Bit ten jest wykorzystywany najczęściej
+        do uruchomienia programu z uprawnieniami <em>root</em> przez
+        zwykłego użytkownika. Takim przykładem może być program <strong>su</strong>,
+        który służy przełączaniu się miedzy użytkownikami, bez tego bitu
+        przelogowanie nie było by możliwe. Dla eksperymentu możemy usunać ten
+        bit, następnie spróbować jako zwykły użytkownik przelogować na kogoś
+        innego. 
+      </p>
+<pre class="code-block">
+[root@server1 ~]# chmod -v u-s /usr/bin/su
+mode of '/usr/bin/su' changed from 4755 (rwsr-xr-x) to 0755 (rwxr-xr-x)
+[user@server1 ~]$ su user100
+Password: 
+su: Authentication failure
+</pre>
+      <p>
+        Jak widać przełączanie na użytkownika 
+        <code class="code-inline">user100</code> nie powiodło się
+        mimo iż polecenie zapytało o hasło (polecenie <em>su</em> nie pyta o
+        hasło tylko superużytkownika). Zwróćmy również uwagę na to jak wygląda
+        bit <em>setuid</em> w oktalnym zapisie uprawnień. Do wskazywania 
+        uprawnień specjalnych wykorzystywana jest nieużywana przy zwykłych
+        uprawnieniach czwarta liczba całkiem z lewej strony. Teraz przywrócimy
+        <em>setuid</em> temu programowi.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# chmod -v +4000 /usr/bin/su
+mode of '/usr/bin/su' changed from 0755 (rwxr-xr-x) to 4755 (rwsr-xr-x)
+[user@server1 ~]$ su user100
+Password: 
+[user100@server1 user]$ 
+</pre>
+      <p>
+        Podczas przywracania uprawnień, nie naruszyłem tych podstawowych
+        używając wartości <code class="code-inline">+4000</code>, nie
+        potrzeba wskazywać klasy, ponieważ program sam wie, że ten bit należy
+        nadać w klasie właściciela. 
+      </p>
+      <p>
+        Czasami bit <em>setuid</em> może występować w postaci wielkiej litery
+        <em>S</em>, oznacza to tyle iż w klasie właściciela nie występuje
+        prawo do wykonywania (bit <em>x</em>).
+      </p>
+      <h3 id="4.2.2.setgid">4.2.2. Uprawnienia bitu setgid</h3>
+      <p>
+        Zastosowania bitu <strong>setgid</strong>, mogą być dwa jedno podobne
+        do bitu <em>setuid</em>, ale tyczące się grupy, drugie zaś dotyczy się
+        katalogów współdzielonych. Bit <em>setgit</em> oznaczany jest
+        małą lub wielką literą <em>s</em> w klasie grupy. 
+      </p>
+      <p>
+        Kiedy katalog posiada ustawiony bit <em>setgid</em>, to grupa, która
+        jest właścicielem takiego katalogu będzie przypisywana jako grupa
+        każdemu nowemu elementowi utworzonemu w tym katalogu. 
+      </p>
+<pre class="code-block">
+[user2000@server1 sdir]$ ls -ld /sdir
+drwxrws--T. 3 root sgrp2 65 Jun 21 17:31 /sdir
+[user2000@server1 sdir]$ mkdir user2000dir
+[user2000@server1 sdir]$ ls -l
+total 4
+-rw-rw-r--. 1 user1000 sgrp2 5 Jun 20 16:00 user1000file
+drwxrwsr-x. 2 user2000 sgrp2 6 Jun 21 17:30 user2000dir
+[user2000@server1 sdir]$ touch user2000file
+[user2000@server1 sdir]$ ls -l
+total 4
+-rw-rw-r--. 1 user1000 sgrp2 5 Jun 20 16:00 user1000file
+drwxrwsr-x. 2 user2000 sgrp2 6 Jun 21 17:30 user2000dir
+-rw-rw-r--. 1 user2000 sgrp2 0 Jun 21 17:31 user2000file
+</pre>
+      <p>
+        Katalog <em>/sdir</em> jest własnością grupy <em>sgrp2</em> oraz
+        posiada ustawiowiony bit <em>setgid</em> (bit <em>s</em> w miejscu
+        <em>x</em> w klasie grupy). Utworzyłem katalog oraz plik, oba elementy
+        odziedziczyły grupę <em>sgrp2</em> właśnie dzięki tym uprawnieniom.
+        Zwróćmy uwagę również na fakt iż nowoutworzony katalog odziedziczył
+        również bit <em>setgid</em>. Tego typu funkcjonalność możemy
+        wykorzystać tworząc katalogi do pracy grupowej, aby zaoszczędzić
+        użytkownikom grupy zmianę uprawnień przy każdym nowym pliku lub
+        podkatalogu w tego typu folderach.
+      </p>
+      <p>
+        Innym przykładem jest wykorzystanie pliku wykonywalnego z ustawionym
+        bitem <em>setgid</em>. Weźmy pod lupe taki plik jak program
+        <strong>write</strong>, ten program służy do przesyłania wiadomości
+        między użytkownikami (między terminalami).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /usr/bin/write 
+-rwxr-sr-x. 1 root tty 24472 Feb 24 11:25 /usr/bin/write
+</pre>
+      <p>
+        Posiada on bit <em>setgid</em>, którym pozwoli mu w tym przypadku
+        skorzystać z uprawnień grupy na plikach urządzeń. Pierwsza konsola
+        wirtualna w systemie:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /dev/tty0 
+crw--w----. 1 root tty 4, 0 Jun 21 15:13 /dev/tty0
+</pre>
+      <p>
+        Grupa <em>tty</em> posiada prawo do zapisu na tym urządzeniu. Sprawdźmy
+        jeszcze pierwsze urządzenie pseudoterminala (okno programu
+        <em>Terminal</em> lub połączenie przez SSH).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /dev/pts/0
+crw--w----. 1 user tty 136, 0 Jun 21 17:51 /dev/pts/0
+</pre>
+      <p>
+        Tutaj grupa również posiada prawo zapisu. Usuwanie i przypisywanie
+        tego bitu jest analogiczne do bitu <em>setuid</em>, wymaga
+        tylko zmiany kilku wartości
+      </p>
+<pre class="code-block">
+[root@server1 ~]# chmod -v g-s /usr/bin/write
+mode of '/usr/bin/write' changed from 2755 (rwxr-sr-x) to 0755 (rwxr-xr-x)
+[root@server1 ~]# chmod -v +2000 /usr/bin/write
+mode of '/usr/bin/write' changed from 0755 (rwxr-xr-x) to 2755 (rwxr-sr-x)
+</pre>
+      <p>
+        Przeglądając atrybuty plików i katalogów możemy natknąć sie na bit
+        <em>setgid</em> zapisany wielką literą, jest to ten sam bit, tylko że
+        w klasie grupy brakuje prawa do wykonania (bitu <em>x</em>).
+      </p>
+      <h3 id="4.2.3.stickybit">4.2.3. Uprawnienia bitu sticky</h3>
+      <p>
+        Bit <strong>sticky</strong> ma za zadanie zabezpieczyć pliki i katalogi
+        przed nieuprawnionym usunięciem w ogólodostępnych katalogach (tam
+        gdzie wszyscy mają prawo do zapisu). Jeśli katalog ma ustawiony taki
+        bit, to wówczas tylko właściciel pliku bądź podkatalogu będzie mógł go
+        usunąć. Bit <em>sticky</em> oznaczany jest za pomocą małej lub
+        wielkiej litery <em>t</em> w klasie publicznej 
+        (pozostałych użytkowników). 
+      </p>
+      <p>
+        Usunięcie lub przypisanie tego bitu może odbywać się tak jak w
+        przypadku poprzednich bitów.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# chmod -v -o-t /sdir
+mode of '/sdir' changed from 3770 (rwxrws--T) to 2770 (rwxrws---)
+[root@server1 ~]# chmod -v +1000 /sdir
+mode of '/sdir' changed from 2770 (rwxrws---) to 3770 (rwxrws--T)
+</pre>
+      <p>
+        Tutaj zwróćmy uwagę na to, iż bit <em>sticky</em> jest zapisany wielką
+        literą, otóż działanie tego bitu się nie zmienia, jest jedynie 
+        informacja, że klasie publicznej brakuje prawa do wykonania
+        (<em>x</em>). Wszystkie bity specjalne umieszczane w poszczególnych
+        klasach, rezydują w miejscu prawa do wykonywania.
+      </p>
+      <h2 id="4.3.find">4.3. Polecenie find</h2>
+      <p>
+        Polecenie <strong>find</strong>, jak sama nazwa wskazuje służy do
+        wyszukiwania plików i katalogów. Najczęściej jest ono wykorzystywane 
+        przez
+        użytkowników w podstawowym zakresie, zwracając gigantyczną ilość danych.
+        Często korzystając z tego narzędzia nie wykorzystuje się w pełni jego
+        potencjału, który ukrywa się w dużej ilości opcji zawężających wyniki
+        poszukiwania oraz możliwości wykonania akcji w wyszukanych plikach.
+      </p>
+      <p>
+        Najprostszy sposób na użycie polecenia <em>find</em> znajduje się 
+        poniżej:
+      </p>
+<pre class="code-block">
+[root@server1 user]# find / -name network
+/run/systemd/network
+/tmp/gzipped/etc/sysconfig/network
+/tmp/gzipped/etc/vmware-tools/scripts/vmware/network
+/etc/sysconfig/network
+/etc/vmware-tools/scripts/vmware/network
+/root/bzipped/etc/sysconfig/network
+/root/bzipped/etc/vmware-tools/scripts/vmware/network
+/usr/lib/systemd/network
+</pre>
+      <p>
+        Polecenie przeszukało cały główny system plików pod kątem plików
+        o nazwie <code class="code-inline">network</code>. Sama opcja
+        <code class="code-inline">-name</code> jest zawężeniem wyników
+        wyszukiwania, bez tej opcji polecenie zwróciłoby wszystkie pliki
+        znalezione w podanym katalogu czyli w tym przypadku minimum kilka 
+        tysięcy.
+      </p>
+      <p>
+        Poniżej zamieszczam najważniejsze opcje służące do bardziej
+        szczegółowego wyszukiwania plików.
+      </p>
+      <ul>
+        <li><strong>-iname</strong> - wyszukuje pliki o nazwie podanej jako
+          argument tej opcji, ignorując przy tym wielkość znaków.
+<pre class="code-block">
+[root@server1 user]# find . -iname do*
+./Downloads
+./Documents
+./.cache/mozilla/firefox/r7fvuapl.default-default/cache2/doomed
+</pre>
+        </li>
+        <li><strong>-size</strong> - wyszukiwanie plików na podstawie rozmiaru.
+          Jeśli chcemy aby program znalazł pliki mniejsze niż podana
+          wartość stawiamy przed nią myślnik (<strong>-</strong>), a jeśli
+          większe to plus (<strong>+</strong>). Poniższy przykład zaprezentuje
+          wyszukiwanie plików powyżej 1G w moim katalogu domowym:
+<pre class="code-block">
+[xf0r3m@latitude-e5270 ~]$ find ~ -size +1G -exec ls -ldh {} \;
+-rw-r--r--. 1 xf0r3m xf0r3m 2,1G 06-18 18:12 /home/xf0r3m/Pobrane/Fedora-MATE_Compiz-Live-x86_64-35/Fedora-MATE_Compiz-Live-x86_64-35-1.2.iso
+-rw-r--r--. 1 xf0r3m xf0r3m 1,4G 06-18 19:44 /home/xf0r3m/Pobrane/Fedora-LXDE-Live-x86_64-35-1.2.iso
+-rwxr-xr-x. 1 xf0r3m xf0r3m 11G 2017-01-25  /home/xf0r3m/Pobrane/rhel-8.6-x86_64-dvd.iso
+-rwxr-xr-x. 1 xf0r3m xf0r3m 8,0G 2017-02-11  /home/xf0r3m/Pobrane/rhel-baseos-9.0-x86_64-dvd.iso
+-rwxr-xr-x. 1 xf0r3m xf0r3m 2,9G 06-21 19:50 /home/xf0r3m/Dokumenty/RHEL9-VM1_21.06.ova
+-rwxr-xr-x. 1 xf0r3m xf0r3m 2,3G 06-21 19:54 /home/xf0r3m/Dokumenty/RHEL9-VM2_21.06.ova
+-rwxr-xr-x. 1 xf0r3m xf0r3m 2,6G 06-21 20:00 /home/xf0r3m/Dokumenty/RHEL8-VM1_21.06.ova
+-rw-------. 1 xf0r3m xf0r3m 6,2G 06-22 16:06 '/home/xf0r3m/VirtualBox VMs/RHEL9-VM1/RHEL9-VM1_21.06-disk001.vmdk'
+-rw-------. 1 xf0r3m xf0r3m 4,8G 06-21 22:26 '/home/xf0r3m/VirtualBox VMs/RHEL9-VM2/RHEL9-VM2_21.06-disk001.vmdk'
+-rw-------. 1 xf0r3m xf0r3m 6,3G 06-21 22:28 '/home/xf0r3m/VirtualBox VMs/RHEL8-VM1/RHEL8-VM1_21.06-disk001.vmdk'
+</pre>
+          Opcję <code class="code-block">-exec</code>, omówimy pod koniec
+          tego podrozdziału. 
+        </li>
+        <li><strong>-user, -group</strong> - wyszukiwanie plików na podstawie
+          nazwy właściciela oraz grupy do której plik należy. W przykładzie
+          przedstawie polecenie, które wyszuka wszystkie pliki należące do
+          użytkownika <em>user</em>, ale i nie należące do grupy sgrp2:
+<pre class="code-block">
+[root@server1 user]# find / -user user -not -group sgrp2 
+/dev/pts/0
+/proc/1688
+/proc/1688/task
+/proc/1688/task/1688
+/proc/1688/task/1688/fd
+/proc/1688/task/1688/fd/0
+/proc/1688/task/1688/fd/1
+/proc/1688/task/1688/fd/2
+...
+</pre>
+          Aby zanegować, któreś z kryteriów należy poprzedzić je opcją
+          <em>-not</em> lub wykrzyknikiem (<strong>!</strong>).
+        </li>
+        <li><strong>-maxdepth, -mindepth</strong> - te opcje wskazują poleceniu
+          <em>find</em>, jak głęboko w strukturę katalogów ma sięgać polecenie
+          podczas wyszukiwania (<em>-maxdepth</em>) lub od którego poziomu
+          podkatalogów ma zacząć wyszukiwanie (<em>-mindepth</em>).
+<pre class="code-block">
+[root@server1 user]# find / -maxdepth 3 -name network
+/run/systemd/network
+/etc/sysconfig/network
+
+[root@server1 user]# find / -mindepth 4 -name network
+/tmp/gzipped/etc/sysconfig/network
+/tmp/gzipped/etc/vmware-tools/scripts/vmware/network
+/etc/vmware-tools/scripts/vmware/network
+/root/bzipped/etc/sysconfig/network
+/root/bzipped/etc/vmware-tools/scripts/vmware/network
+/usr/lib/systemd/network
+</pre>
+          Zwróćmy uwagę na to, iż te opcje są opcjami globalnymi, nie mają
+          bezpośredniego wpływu na wyszukiwanie, dlatego też należy je
+          umieszczać przed opcjami mającymi zawęzić kryteria.
+        </li>
+        <li><strong>-type</strong> - wyszukiwanie na podstawie typu
+          plików. Poniższy przykład pokazuje również jak zapisać różne
+          wartości przy jednej opcji:
+<pre class="code-block">
+[root@server1 user]# find / -type p,s -exec ls -ld {} \;
+srwxr-xr-x. 1 chrony chrony 0 Jun 22  2022 /run/chrony/chronyd.sock
+srwxr-xr-x. 1 root root 0 Jun 22  2022 /run/mcelog-client
+srw-rw-rw-. 1 root root 0 Jun 22  2022 /run/.heim_org.h5l.kcm-socket
+srw-rw-rw-. 1 root root 0 Jun 22  2022 /run/avahi-daemon/socket
+srw-rw-rw-. 1 root root 0 Jun 22  2022 /run/lsm/ipc/simc
+srw-rw-rw-. 1 root root 0 Jun 22  2022 /run/lsm/ipc/sim
+srw-rw-rw-. 1 root root 0 Jun 22  2022 /run/cups/cups.sock
+prw-------. 1 root root 0 Jun 22  2022 /run/initctl
+prw-------. 1 root root 0 Jun 22  2022 /run/dmeventd-client
+prw-------. 1 root root 0 Jun 22  2022 /run/dmeventd-server
+</pre>
+        Polecenie wyszukuje w systemie wszystkie gniazda i nazwane potoki
+        (typy plików, nieomawiane w tym materiale). Jak widać inną wartość dla
+        tej opcji należy podać po przecinku.
+      </li>
+      <li><strong>-mtime, -mmin</strong> - wyszukiwanie pliku na podstawie
+        ilości czasu upłyniętego od daty ostatniej modyfikacji, z czego
+        opcja <em>-mtime</em> przyjmuje wartości w liczbie dni, która upłynęła
+        od ostatniej modyfikacji, a <em>-mmin</em> w minutach.
+<pre class="code-block">
+[xf0r3m@latitude-e5270 ~]$ find ~ -maxdepth 2 -mtime -7
+/home/xf0r3m
+/home/xf0r3m/.mozilla/firefox
+/home/xf0r3m/.local/share
+/home/xf0r3m/Pobrane
+/home/xf0r3m/Pobrane/Fedora-MATE_Compiz-Live-x86_64-35.torrent
+/home/xf0r3m/Pobrane/Fedora-MATE_Compiz-Live-x86_64-35
+/home/xf0r3m/Pobrane/Fedora-LXDE-Live-x86_64-35.torrent
+/home/xf0r3m/Pobrane/Fedora-LXDE-Live-x86_64-35-1.2.iso
+/home/xf0r3m/Pobrane/Fedora-Workstation-Live-x86_64-35.torrent
+
+[xf0r3m@latitude-e5270 ~]$ find ~ -maxdepth 3 -mmin -360
+/home/xf0r3m
+/home/xf0r3m/.mozilla/firefox
+/home/xf0r3m/.mozilla/firefox/qlw3f0ci.default-default
+/home/xf0r3m/.local/share
+/home/xf0r3m/.local/share/gnome-shell
+/home/xf0r3m/.local/share/gvfs-metadata
+/home/xf0r3m/.local/share/recently-used.xbel
+/home/xf0r3m/.local/share/ranger
+/home/xf0r3m/.local/state/wireplumber
+/home/xf0r3m/Dokumenty/docs/.git
+/home/xf0r3m/Dokumenty/docs/angielski
+</pre>
+        Powyższe polecenia przedstawiają pliki, które były modyfikowane w
+        przeciągu ostatnich 7 dni, oraz ostatnich 6 godzin. Użyłem tutaj
+        również modyfikatorów głębokości.
+      </li>
+      <li><strong>-perm</strong> - wyszukiwanie plików na podstawie uprawnień.
+        Chcąc wyszukać pliki po konkretnych uprawnieniach pliku, podajemy je w
+        wersji oktalnej po opcji. Możemy również skorzystać z innych opcji 
+        wprowadzania
+        uprawnień: uprawnienień minimalnych podanych po myślniku
+        (<strong>-</strong>), wówczas każdy z podanych tam praw będzie musiało
+        wystąpić w danej klasie lub uprawnień dowolnych podanych po ukośniku
+        (<strong>/</strong>), wówczas przypasowany zostanie plik, który będzie
+        posiadać, minimum jedno z praw, z minimum jednej klasy.
+<pre class="code-block">
+[root@server1 user]# find / -perm 111 -exec ls -ld {} \;
+---x--x--x. 1 root root 87168 Aug 26  2021 /usr/bin/sudoreplay
+
+[root@server1 user]# find /dev -type c -perm -222 -exec ls -ld {} \;
+crw-rw-rw-. 1 root kvm 10, 241 Jun 22  2022 /dev/vhost-vsock
+crw-rw-rw-. 1 root kvm 10, 238 Jun 22  2022 /dev/vhost-net
+crw-rw-rw-. 1 root root 10, 196 Jun 22  2022 /dev/vfio/vfio
+crw-rw-rw-. 1 root root 10, 200 Jun 22  2022 /dev/net/tun
+crw-rw-rw-. 1 root render 226, 128 Jun 22  2022 /dev/dri/renderD128
+crw-rw-rw-. 1 root root 10, 229 Jun 22  2022 /dev/fuse
+crw-rw-rw-. 1 root tty 5, 2 Jun 22 17:28 /dev/ptmx
+crw-rw-rw-. 1 root tty 5, 0 Jun 22  2022 /dev/tty
+crw-rw-rw-. 1 root root 1, 9 Jun 22  2022 /dev/urandom
+crw-rw-rw-. 1 root root 1, 8 Jun 22  2022 /dev/random
+crw-rw-rw-. 1 root root 1, 7 Jun 22  2022 /dev/full
+crw-rw-rw-. 1 root root 1, 5 Jun 22  2022 /dev/zero
+crw-rw-rw-. 1 root root 1, 3 Jun 22  2022 /dev/null
+
+[root@server1 user]# find /dev -type c -perm /222 -exec ls -ld {} \;
+crw-rw----. 1 root dialout 4, 64 Jun 22 17:30 /dev/ttyS0
+crw-rw-rw-. 1 root tty 5, 2 Jun 22 17:30 /dev/ptmx
+crw-r--r--. 1 root root 10, 235 Jun 22 17:30 /dev/autofs
+</pre>
+        Powyżej przedstawiłem wymienione sposoby na zapis uprawnień w przy
+        opcji <em>-perm</em>. Tej opcji możemy również przekazać uprawnienia
+        w postaci symbolicznej na przykład:
+<pre class="code-block">
+[root@server1 user]# find /usr -perm -u=s -exec ls -ld {} \;
+-rwsr-xr-x. 1 root root 36880 Feb 16 15:46 /usr/bin/fusermount3
+-rwsr-xr-x. 1 root root 74880 Dec  3  2021 /usr/bin/chage
+-rwsr-xr-x. 1 root root 78744 Dec  3  2021 /usr/bin/gpasswd
+-rwsr-xr-x. 1 root root 42448 Dec  3  2021 /usr/bin/newgrp
+-rwsr-xr-x. 1 root root 36872 Jan 12 18:21 /usr/bin/fusermount
+-rwsr-xr-x. 1 root root 49152 Feb 24 11:25 /usr/bin/mount
+-rwsr-xr-x. 1 root root 36784 Feb 24 11:25 /usr/bin/umount
+-rwsr-xr-x. 1 root root 57616 Feb 24 11:25 /usr/bin/su
+-rwsr-xr-x. 1 root root 32608 Mar 11 16:34 /usr/bin/pkexec
+-rwsr-xr-x. 1 root root 53704 Aug  9  2021 /usr/bin/crontab
+-rwsr-xr-x. 1 root root 32648 Aug 10  2021 /usr/bin/passwd
+---s--x--x. 1 root root 185456 Aug 26  2021 /usr/bin/sudo
+-rwsr-xr-x. 1 root root 16240 Oct 15  2021 /usr/bin/vmware-user-suid-wrapper
+-rws--x--x. 1 root root 32712 Feb 24 11:25 /usr/bin/chfn
+-rws--x--x. 1 root root 24464 Feb 24 11:25 /usr/bin/chsh
+-rwsr-xr-x. 1 root root 57920 Aug  9  2021 /usr/bin/at
+-rwsr-xr-x. 1 root root 16128 Dec  2  2021 /usr/sbin/pam_timestamp_check
+-rwsr-xr-x. 1 root root 24544 Dec  2  2021 /usr/sbin/unix_chkpwd
+-rwsr-xr-x. 1 root root 15608 Mar 10 18:18 /usr/sbin/grub2-set-bootflag
+-rws--x--x. 1 root root 45232 Dec  9  2021 /usr/sbin/userhelper
+-rwsr-xr-x. 1 root root 20416 Mar 11 16:34 /usr/lib/polkit-1/polkit-agent-helper-1
+-rwsr-x---. 1 root sssd 119512 Jan 17 20:47 /usr/libexec/sssd/krb5_child
+-rwsr-x---. 1 root sssd 53240 Jan 17 20:47 /usr/libexec/sssd/ldap_child
+-rwsr-x---. 1 root sssd 28536 Jan 17 20:47 /usr/libexec/sssd/proxy_child
+-rwsr-x---. 1 root sssd 32656 Jan 17 20:47 /usr/libexec/sssd/selinux_child
+-rwsr-x---. 1 root dbus 36848 Aug  9  2021 /usr/libexec/dbus-1/dbus-daemon-launch-helper
+-rwsr-xr-x. 1 root root 16104 Feb 10 11:13 /usr/libexec/Xorg.wrap
+-rwsr-x---. 1 root cockpit-wsinstance 57600 Mar  3 13:28 /usr/libexec/cockpit-session
+</pre>
+        Powyższe polecenie szuka wszystkich programów z ustawionym bitem
+        <em>setuid</em>.
+      </li>
+      </ul>
+      <h3 id="4.3.1.actionoptions">4.3.1. Opcje akcji polecenia find</h3>
+      <p>
+        Na powyższych przykładach stosowałem wielkrotnie dodatkową opcję
+        <strong>-exec</strong>. Jest to opcja akcji
+        podejmowana na pliku gdy tylko zostanie znaleziony. Składania opcji
+        <em>-exec</em> może wyglądać następująco:
+      </p>
+<pre class="code-block">
+$ find ... -exec ls -ld {} \;
+</pre>
+      <p>
+        Po opcji <em>-exec</em> podajemy zwykłe polecenie, tak jak gdybyśmy
+        wpisywali je do wiersza polecenia. Odniesieniu do znalezionego pliku
+        służy zapisana para nawiasów klamrowych 
+        <code class="code-inline">{}</code> każde polecenie wydawane za pomocą
+        opcji <em>-exec</em> czy innej musi zostać za terminowane
+        zacytowanym średnikiem (<strong>\;</strong>), ponieważ jest koniec
+        polecenia wprowadzonego do tej opcji, a nie koniec polecenia
+        <em>find</em>. Wynik działania przykładowego użycia opcji 
+        <em>-exec</em> znajduje się w przykładach na początku tego 
+        podrozdziału.
+      </p>
+      <p>
+        Poza poleceniem <em>-exec</em>, istnieją jeszcze dwa polecenia akcji
+        <strong>-delete</strong>, które usuwa pliki oraz <strong>-ok</strong>,
+        które różni się tym od <em>-exec</em>, że pyta sie użytkownika czy
+        wykonać podane polecenie na pliku.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Polecenie <em>find</em>, wydaje się bardzo pomocne, posiada masę opcji
+        część znich znajduje się tutaj, pozostałe są rozpisane na stronach
+        podręcznika. Powinniśmy umieć się posługiwać tym narzędziem, zarówno
+        zaweżać obszar poszukiwania jak i prawidłowo używać opcji 
+        <em>-exec</em>.
+      </p>
+      <h2 id="4.4.acl">4.4. Lista kontroli dostępu</h2>
+      <p>
+        Oprócz klasycznego zestawu uprawnień w Uniksach oraz określenia
+        właściciela i grupy do której należy plik bądź katalog, w <em>RHEL</em>
+        możemy
+        dodatkowo wskazać innych użytkowników oraz grupy i przypisać im 
+        uprawnienia
+        nieżależne od tych klasycznych (<strong>standardu ugo/rwx</strong>).
+        Temu właśnie służy <strong>lista kontroli dostępu</strong>. Ten
+        mechanizm obsługiwany jest za pomocą dwóch poleceń, pierwszym z nich
+        jest <strong>getfacl</strong> i służy ono do wypisania listy kontroli
+        dostępu. Stwórzmy w katalogu <em>/tmp</em> plik o nazwie 
+        <em>aclfile</em>, następnie wykonajmy polecenie <em>getfacl</em>
+        podając ten plik jako argument.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ cd /tmp
+[user@server1 tmp]$ touch acluser
+[user@server1 tmp]$ getfacl acluser 
+# file: acluser
+# owner: user
+# group: user
+user::rw-
+group::rw-
+other::r--
+
+[user@server1 tmp]$ ls -l acluser
+-rw-rw-r--. 1 user user 9 Jun 22 18:25 acluser
+</pre>
+      <p>
+        Kiedy plik niema zdefiniowanych żadnych dodatkowych użytkowników oraz
+        grup, jego lista kontroli dostępu jest równoznaczna z klasycznymi 
+        uprawnieniami Uniksa i te listy oznaczają kolejno właściciela, grupę
+        do której należy ten plik oraz pozostałych użytkowników.
+        Listy kontroli dostępu możemy modyfikować 
+        za pomocą polecenia <strong>setfacl</strong>. Zanim jednak poznamy
+        jak należy modyfikować <em>ACL</em>, poniżej znajduje się lista 
+        najważniejszych
+        opcji tego polecenia. Są one dość istotne, ponieważ pozwalają na 
+        manipulowanie listami elementu.
+      </p>
+      <ul>
+        <li><strong>-b</strong> - usuwa wszystkie listy dostępowe,</li>
+        <li><strong>-d</strong> - ustawia listy jako domyślne,</li>
+        <li><strong>-k</strong> - usuwa wszystkie listy domyślne,</li>
+        <li><strong>-m</strong> - modyfikuje lub ustawia listy,</li>
+        <li><strong>-n</strong> - chroni przed automatycznym przeliczaniem
+          maski,</li>
+        <li><strong>-R</strong> - ustawia listy rekurencyjnie, listy katalogu
+          są stosowane na elementy w nim zawarte,</li>
+        <li><strong>-x</strong> - usuwa pojedynczą listę.</li>
+      </ul>
+      <p>
+        Listy kontroli możemy zastoswać dla trzech podmiotów:
+      </p>
+      <ul>
+        <li><strong>użytkownika</strong>:
+          <code class="code-inline">u[ser]:nazwa/uid:uprawnienia</code></li>
+        <li><strong>grupy</strong>:
+          <code class="code-inline">g[roup]:nazwa/gid:uprawnienia</code></li>
+        <li><strong>innych</strong>:
+          <code class="code-inline">o[ther]:uprawnienia</code></li>
+      </ul>
+      <p>
+        To co zostało ujęte w nawiasach kwadratowych, jest zapisem opcjonalnym.
+        Identyfikator podmiotu możemy zapisać albo za pomocą numerów <em>UID</em>
+        oraz <em>GID</em>, lub za pomocą nazw. Jeśli nazwa lub 
+        <em>UID</em>/<em>GID</em> zostaną pominiete to listy <em>user</em>
+        oraz <em>group</em> będą tyczyć się właściciela oraz grupy, do której
+        należy dany element. Uprawnienia mogą być podane
+        za pomocą symboli lub sumy wag dla pojedynczej klasy. Ustawię teraz
+        listę dla jednego z użytkowników w systemie.
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ setfacl -m u:user100:rw acluser
+[user@server1 tmp]$ ls -l acluser
+-rw-rw-r--+ 1 user user 9 Jun 22 18:25 acluser
+</pre>
+      <p>
+        Pierwsze polecenie ustawia prawo do czytania oraz pisania użytkownikowi
+        <code class="code-inline">user100</code> za pomocą list dostępu.
+        Wyświetliłem szczegóły pliku. Zwróćmy uwagę na to, iż kropka na końcu
+        uprawnień została zastąpiona plusem (<strong>+</strong>), taki zapis
+        informuje użytkowników, że uprawnienia tego pliku są rozszerzone za
+        pomocą <em>ACL</em>. Teraz przyjrzymy sie jak wyglądają listy pliku:
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ getfacl -c acluser
+user::rw-
+user:user100:rw-
+group::rw-
+mask::rw-
+other::r--
+</pre>
+      <p>
+        W tym przykładzie użyłem opcji <em>-c</em>, która nie wyświetla
+        wcześniej pokazywanego nagłówka. Nie jest on nam potrzebny. Nowy wpis
+        pojawia się pod wpisem właśiciela. Mówi on wprost, że użytkownik
+        <code class="code-inline">user100</code> posiada prawo do czytania oraz
+        modyfikowania pliku <code class="code-inline">acluser</code>, mimo iż
+        na podstawie klasycznych uprawnień oraz praw własności nie jest on 
+        nijak związany z tym plikiem.
+      </p>
+      <p>
+        Poza uprawnienia dla użytkownika pojawi się wpis oznaczony słowem
+        <code class="code-inline">mask</code>. Jest to maska list kontroli
+        i wyznacza ona maksymalne uprawnienia jakie można dać danemu
+        podmiotowi. Przy każdej zmianie list kontroli dostosowuje się ona do
+        najwyższych uprawnień na liście. Dodam teraz drugiego użytkownika z
+        wyższymi od <em>user100</em> uprawnieniami, bedziemy mogli wówczas
+        zaobserowować jak zmienia się maska.
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ setfacl -m u:user200:7 acluser
+[user@server1 tmp]$ getfacl -c acluser
+user::rw-
+user:user100:rw-
+user:user200:rwx
+group::rw-
+mask::rwx
+other::r--
+</pre>
+      <p>
+        Maska została ponownie przeliczona i wskazuje teraz uprawnienia o
+        sumie wag równej 7 (<em>rwx</em>). Teraz wymuszę inną wartość dla
+        maski:
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ setfacl -m m:4 acluser 
+[user@server1 tmp]$ getfacl -c acluser
+user::rw-
+user:user100:rw-               #effective:r--
+user:user200:rwx               #effective:r--
+group::rw-                         #effective:r--
+mask::r--
+other::r--
+</pre>
+      <p>
+        Na powyższym przykładzie za pomocą selektora (<em>u: - user</em>, itd.)
+        <code class="code-inline">m:</code> wskazuje uprawnienia dla maski
+        <em>ACL</em>.
+        Teraz przy zdefiniowanych przez nas listach użytkowników, pojawił się
+        komentarz <code class="code-inline">#effective:r--</code>. Oznacza to,
+        iż uprawnienia zostały zmniejszone ponieważ, przekraczają nałożoną na 
+        plik maskę list kontroli. Zrócmy uwagę, ze to ograniczenie
+        uprawnień maską dotknęło grupę, do której należy plik. Aby wyłączyć
+        automatyczne przeliczanie maski, należy użyć opcji <em>-n</em>. Usunę 
+        teraz
+        jedną z list, aby zaprezentować jak można to zrobić kiedy listy dla
+        poszczególnych użytkowników nie będą nam potrzebne:
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ getfacl -c acluser 
+user::rw-
+user:user100:rw-
+user:user200:rwx
+group::r--
+mask::rwx
+other::r--
+
+[user@server1 tmp]$ setfacl -x u:user200 acluser 
+[user@server1 tmp]$ getfacl -c acluser 
+user::rw-
+user:user100:rw-
+group::r--
+mask::rw-
+other::r--
+</pre>
+      <p>
+        Teraz oczyszcze plik z list, ponieważ nie są nam już one potrzebne.
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ setfacl -b acluser
+[user@server1 tmp]$ getfacl -c acluser
+user::rw-
+group::r--
+other::r--
+</pre>
+      <p>
+        Po usunięciu list z tak rygorystczną maską możemy zaobserwować, że 
+        zostały zmodyfikowane uprawnienia grupy. Przed usunięciem
+        list należy ustawić maskę aby odzworowywała wcześniejsze uprawnienia.
+      </p>
+      <h3 id="4.4.1.defaultacl">4.4.1. Domyślne listy kontroli dostępu</h3>
+      <p>
+        Domyślne listy kontroli dostępu są stosowane w udostępnionych
+        katalogach, aby zapewnić spójny zestaw uprawnień dla elementów w nim
+        zawartych. Listy kontroli zdefiniowane dla takiego katalogu są
+        dzieczone przez elementy, które się w nim znajdują. Dzięki czemu
+        nie trzeba poprawiać uprawnień przy każdym nowym pliku lub katalogu.
+        Dziedziczenie nieco różni się w przypadku plików i podkatalogów:  
+      </p>
+      <ul>
+        <li>Pliki otrzymują domyślne listy katalogu nadrzędnego jako zwykłe
+          listy kontoli dostępu (<em>access ACL</em>, poznaliśmy je na
+          początku tego podrozdziału).</li>
+        <li>Podkatalogi przyjmują od katalogu nadrzędnego zarówno, zwykłe jak
+          i domyślnie listy kontroli.</li>
+      </ul>
+      <p>
+        Domyślnie listy definiuje się tak samo jak zwykłe, jednak robi się to
+        tylko na katalogach za pomocą polecenia <em>setfacl</em> z dodatkową
+        opcją <em>-d</em>.
+        Utworzę teraz podkatalog o nazwie <em>projekty</em> w 
+        katalogu
+        <em>/tmp</em>, następnie nadam mu dwie domyślnie listy dając dwóm
+        użytkownikom systemu pełne uprawnienia do niego.
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ mkdir projekt
+[user@server1 tmp]$ setfacl -dm u:user100:7,u:user200:7 projekt/
+[user@server1 tmp]$ getfacl -c projekt/
+user::rwx
+group::r-x
+other::r-x
+default:user::rwx
+default:user:user100:rwx
+default:user:user200:rwx
+default:group::r-x
+default:mask::rwx
+default:other::r-x
+</pre>
+      <p>
+        Następnie utworzę plik o nazwie <em>zalozenia_projektu.txt</em>,
+        poniżej znajdują sie jego szczegóły:
+      </p>
+<pre class="code-block">
+[user@server1 projekt]$ touch zalozenia_projektu.txt
+[user@server1 projekt]$ ls -l
+total 0
+-rw-rw-r--+ 1 user user 0 Jun 23 15:56 zalozenia_projektu.txt
+</pre>
+      <p>
+        Jak widzimy posiada on już jakieś zdefiniowane listy. Są to listy
+        odziedziczone po katalogu nadrzędnym. Oto listy tego pliku:
+      </p>
+<pre class="code-block">
+[user@server1 projekt]$ getfacl -c zalozenia_projektu.txt 
+user::rw-
+user:user100:rwx               #effective:rw-
+user:user200:rwx               #effective:rw-
+group::r-x                     #effective:r--
+mask::rw-
+other::r--
+</pre>
+      <p>
+        Zauważmy, że wpływ na listy mają uprawnienia domyślne elementów
+        (plików i katalogów) oraz wartość <em>umask</em>. Maska <em>ACL</em>
+        przyjmuje wartość najwyższych zdefiniowanych uprawnień, w przypadku
+        plików jest <em>6</em> (odczyt oraz zapis). Następnie odziedziczone
+        listy są konfrontowane z maską i zdefiniowane w nich uprawnienia albo
+        pozostają bez zmian, albo ustawiane są tylko te bity występujące na
+        masce, dlatego też efektywne listy kontroli są takie a nie inne.
+        Teraz do zwykłych list katalogu <em>projekty</em> dodam listy dwóch 
+        użytkowników dodanych jako listy domyślnie i utworze podkatalog.
+      </p>
+<pre class="code-block">
+[user@server1 tmp]$ setfacl -m u:user100:7,u:user200:7 projekt
+[user@server1 tmp]$ getfacl -c projekt/
+user::rwx
+user:user100:rwx
+user:user200:rwx
+group::r-x
+mask::rwx
+other::r-x
+default:user::rwx
+default:user:user100:rwx
+default:user:user200:rwx
+default:group::r-x
+default:mask::rwx
+default:other::r-x
+
+[user@server1 tmp]$ cd projekt/
+[user@server1 projekt]$ mkdir commonfiles
+[user@server1 projekt]$ getfacl -c commonfiles/
+user::rwx
+user:user100:rwx
+user:user200:rwx
+group::r-x
+mask::rwx
+other::r-x
+default:user::rwx
+default:user:user100:rwx
+default:user:user200:rwx
+default:group::r-x
+default:mask::rwx
+default:other::r-x
+</pre>
+      <p>
+        Jak możemy zauważyć, listy kontroli są identyczne. Teraz dwaj pozostali
+        użytkownicy posiadają możliwości zapisywania oraz odczytywania, w
+        przypadku katalogów i plików stworzonych przeze mnie. Jednak ja jako
+        <em>user</em> będę chciał zapisać coś w plikach innych 
+        użytkowników to nie mam takich uprawnień, ponieważ listy dotyczą tylko 
+        tych dwóch użytkowników zdefiniowanych na listach.
+      </p>
+      <h3 id="4.4.2.aclbug">4.4.2. Dziwny problem z listami kontroli dostępu</h3>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Zapoznając się ze zwykłymi listami dostępu po zdefiniowaniu list o 
+        uprawnieniach
+        dających pełne prawa jednemu z użytkowników nie mogłem
+        (jako on) zapisać nic do pliku znajdującego się w katalogu 
+        <em>/tmp</em> za pomocą jakiego kolwiek edytora. Dane 
+        mogłem zapisać natomiast przekierowując strumień na przykład z 
+        polecenia <em>echo</em>. Ten problem zauważyłem w <em>RHEL</em> 9, w 
+        wersji 8.6 
+        nie występował. Problem nie występuje na <em>RHEL</em> 9, gdy plik 
+        odziedziczy listy
+        od katalogu, a uprawnienia zostaną zmniejszone przez maskę, wówczas
+        użytkownicy z mogą zapisywać zmiany za pomocą edytorów.  
+      </p>
+      <h3 id="exec4.1">Ćwiczenie 1: Manipulowanie uprawnieniami pliku</h3>
+      <p>
+        Jak zwykły użytkownik na maszynie server1, stwórz dwa pliki 
+        <em>file11</em> oraz <em>dir11</em>. Uruchom polecenie 
+        <em>umask</em> aby określić obecną maskę użytkownika. Używając 
+        zapisu symbolicznego ustaw maskę użytkownika na wartość 0035. Utwórz
+        plik o nazwie <em>file22</em> oraz katalog o nazwie <em>dir22</em> 
+        w katalogu domowym. Sprawdź i porównaj uprawnienia plików i katalogów
+        utworzonych na potrzeby tego ćwiczenia. Używając polecenia
+        <em>chmod</em> zmień uprawnienia pliku <em>file11</em> aby były takie
+        jak uprawnienia pliku <em>file22</em> oraz zmień uprawnienia katalogu
+        <em>dir22</em> tak aby identyczne jak uprawnienia folderu 
+        <em>dir11</em>. Nie usuwaj jeszcze tych plików.
+      </p>
+      <h3 id="exec4.2">Ćwiczenie 2: Konfiguracja katalogu do pracy grupowej</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>, utwórz katalog
+        <em>/sdir</em> następnie utwórz grupę (<em>groupadd</em>) <em>sgrp</em>
+        oraz dwóch użytkowników <em>user1000</em> oraz <em>user2000</em> 
+        (<em>useradd</em>). Dodaj tych dwóch użytkowników do wcześniej
+        utworzonej grupy. Ustaw właściela katalogu na użytkownika
+        <em>root</em> oraz <em>sgrp</em> jako grupę do której należy, następnie
+        ustaw odpowiednie uprawnienia: grupa=rwx; inni=--- poza tym ustaw bity
+        <em>setgid</em> oraz <em>sticky</em>. Zaloguj się jako <em>user1000</em>
+        i utwórz w wyżej wspomnianym katalogu plik, następnie zaloguj się jako
+        <em>user2000</em> dokonaj zmian w utworzonym przez <em>user1000</em>
+        pliku. Na koniec spróbuj go usunąć. Zapisanie zmian powinno się
+        zakończyć się sukcesem, ale próba usunięcia już nie.
+      </p>
+      <h3 id="exec4.3">Ćwiczenie 3: Wyszukiwanie plików</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>, wyszukaj wszystkie
+        pliki w całej strukturze katalogu głównego, które zostały zmodyfikowane
+        w ciągu ostatnich 300 minut i wyświetl ich typ. Wyszukaj w całej
+        strukturze katalogu głównego pliki nazwanych potoków oraz gniazd.
+      </p>
+      <h3 id="exec4.4">Ćwiczenie 4: Zaawansowane wyszukiwanie plików</h3>
+      <p>
+        Jak superużytkownik na maszynie <em>server1</em>, wyszukaj katalogu
+        <em>/usr</em> zwykłe pliki z czasem dostępu starszym niż 100 dni oraz
+        rozmiarem nie przekraczającym 5 MB, których właścicielem jest 
+        <em>root</em>.
+      </p>
+      <h3 id="exec4.5">Ćwiczenie 5: Ustawianie list dostępu</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>, utwórz plik
+        <em>testfile</em> w katalogu <em>/tmp</em>. Utwórz uzytkowników
+        <em>user3000</em> oraz <em>user4000</em>. Stwórz na wszcześniej
+        utworzonym pliku listy kontroli, ustawiając użytkownikowi 
+        <em>user2000</em> uprawnienia równe 7, dla <em>user3000</em>
+        uprawnienia równe 6, a dla użytkownika <em>user4000</em> uprawnienia
+        równe 4. Usuń listę użytkownika user2000 i wyświetl pozostałe listy.
+        Następnie oczyść plik z list dostępu oraz sprawdź czy nie pozostały
+        żadne listy.
+      </p>
+      <h2 id="ch4summary">Podsumowanie</h2>
+      <p>
+        W tej części materiału zapoznaliśmy się z podstawowymi uprawnieniami
+        plików i katalogów, nauczyliśmy się je ustawiać w dwóch różnych
+        formach zapisu. Poznaliśmy uprawnienia specjalne oraz jak je
+        przypisywać. Dowiedzielśmy się jak ważnym narzędziem jest polecenie 
+        <em>find</em>. Na koniec poznaliśmy sposób na rozszerzenie uprawnień
+        poza standard <em>ugo/rwx</em> za pomocą list kontroli dostępu. W 
+        następnym rozdziale zajmiemy się użytkownikami.
+      </p>
+      <h1 id="5.userbasics">5. Podstawy zarządzania użytkownikami</h1>
+      <p>
+        Użytkownik jest encją, czyli odwzrowaniem rzeczywistego elementu.
+        Obecność użytkowników w systemie ma jeden cel - wyznaczać granice,
+        bowiem każdy z użytkowników posiada swój katalog domowy, w którym
+        przechowuje swoje pliki osobiste oraz programy. W tym rozdziale
+        nauczymy się tworzyć użytkowników oraz modyfikować ich podstawowe
+        informacje, jak np. położenie katalogu domowego czy zmianę numeru
+        <em>UID</em>. Na początku jednak zapoznamy się z metodami sprawdzenia
+        aktywności użytkowników w systemie, prześledzimy ich próby uzyskania
+        dostępu do systemu.
+      </p>
+      <h2 id="5.1.whoandw">5.1. Kto jest zalogowany do systemu i co robi</h2>
+      <p>
+        Za pomocą polecenia <strong>who</strong>, możemy sprawdzić kto jest
+        zalogowany w systemie, na jakim terminalu pracuje, o której się
+        zalogował, jeśli jest połączenie zdalne wówczas po czasie zalogowania
+        zobaczymy adres IP w nawiasie. W moim systemie obecnie zalogowanych
+        jest dwóch użytkowników:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ who
+root     pts/0        2022-06-25 15:06 (192.168.8.192)
+user     pts/1        2022-06-25 15:06 (192.168.8.192)
+</pre>
+      <p>
+        Innym poleceniem zwracającym bieżącą aktywność użytkowników systemie
+        jest polecenie <strong>w</strong>. Poniżej znajduje się wynik 
+        uruchomienia polecenia na jednym z moich systemów.
+      </p>
+<pre class="code-block">
+user@server1 ~]$ w
+ 15:09:43 up 4 min,  2 users,  load average: 0.11, 0.23, 0.12
+USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
+root     pts/0     15:06    7.00s  0.10s  0.09s /usr/bin/python3 -s /usr/bin/ranger
+user     pts/1     15:06    1.00s  0.00s  0.00s w
+</pre>
+      <p>
+        Pierwsza linia informacji zwracanych przez to polecenie jest identyczna
+        z informacjami, które zwraca polecenie <em>uptime</em>. Następnie
+        zwraca ono tabele z nazwą użytkownika 
+        (<code class="code-inline">USER</code>), nazwą terminala
+        (<code class="code-inline">TTY</code>), czasem zalogowania się
+        (<code class="code-inline">LOGIN@</code>), czasem bezczynności
+        (<code class="code-inline">IDLE</code>), czasem procesora zużytym na
+        wykonanie wszystkich zadań po podłączeniu się do terminala wraz z
+        zadaniami wykonywanymi w tle (<code class="code-inline">JCPU</code>),
+        czasem procesora zużytym na wykonanie bieżącego procesu
+        (<code class="code-inline">PCPU</code>) oraz nazwę procesu, która jest
+        obecnie wykonywana (<code class="code-inline">WHAT</code>).
+      </p>
+      <h3 id="5.1.1.loginattempts">5.1.1. Monitorowanie prób logowania się do systemu</h3>
+      <p>
+        Monitorując aktywność systemu nie należy zapominać o sprawdzaniu
+        prób zalogowania się do niego. W dystrybucjach Linuksa istnieją trzy
+        polecenia przeznaczone do tego celu. Pierwszym z nich jest polecenie
+        <strong>last</strong>, które zwraca listę ostatnio zalogowanych
+        użytkowników.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# last
+user     pts/1        192.168.8.192    Sat Jun 25 15:06   still logged in
+root     pts/0        192.168.8.192    Sat Jun 25 15:06   still logged in
+reboot   system boot  5.14.0-70.13.1.e Sat Jun 25 17:05   still running
+user     pts/0        192.168.8.182    Fri Jun 24 14:20 - 17:14  (02:53)
+reboot   system boot  5.14.0-70.13.1.e Fri Jun 24 16:19 - 17:14  (00:54)
+root     pts/1        192.168.8.182    Thu Jun 23 15:54 - 17:27  (01:32)
+user     pts/0        192.168.8.182    Thu Jun 23 14:18 - 17:27  (03:08)
+user     pts/0        192.168.8.182    Thu Jun 23 11:04 - 14:17  (03:13)
+...
+</pre>
+      <p>
+        Polecenie poza tym kto się zalogował, do jakiego terminala, czy
+        zdalnie czy lokalnie, zwraca również informacje, o której system
+        został uruchomiony - wpisy rozpoczynające się od 
+        <code class="code-block">reboot</code>. Nieścisłości czasowe
+        wynikają z tego iż, zegar RTC na serwerze ustawiony jest z
+        uzględniem strefy czasowej oraz zmian czasu lokalnego (powinien
+        wskazywać na czas UTC), poźniej te dane są skorygowane po
+        skomunikowaniu się z serwerami czasu. Chcąc wyświetlić tylko listę,
+        kiedy dokonano startu systemu wydajemy to polecenie z
+        argumentem <em>reboot</em>, ten argument jest tak naprawdę nazwą
+        użytkownika.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# last reboot
+reboot   system boot  5.14.0-70.13.1.e Sat Jun 25 15:42   still running
+reboot   system boot  5.14.0-70.13.1.e Sat Jun 25 17:05 - 15:42  (-1:23)
+reboot   system boot  5.14.0-70.13.1.e Fri Jun 24 16:19 - 17:14  (00:54)
+reboot   system boot  5.14.0-70.13.1.e Thu Jun 23 11:23 - 17:27  (06:03)
+reboot   system boot  5.14.0-70.13.1.e Wed Jun 22 17:30 - 00:17  (06:47)
+reboot   system boot  5.14.0-70.13.1.e Tue Jun 21 15:13 - 18:14  (03:00)
+reboot   system boot  5.14.0-70.13.1.e Mon Jun 20 21:11 - 19:47  (-1:23)
+reboot   system boot  5.14.0-70.13.1.e Mon Jun 20 11:54 - 16:18  (04:24)
+...
+</pre>
+      <p>
+        Dane wyświetlane przez to polecenie przechowywane są w pliku
+        <em>/var/log/wtmp</em>.
+      </p>
+      <p>
+        Alternatywnie do listy ostatnio zalogowanych użytkowników, możemy
+        przejrzeć listę prób logowania się do systemu, które się nie powiodły.
+        Temu służy polecenie <strong>lastb</strong>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# lastb
+user     ssh:notty    192.168.8.182    Thu Jun 23 14:18 - 14:18  (00:00)
+user     ssh:notty    192.168.8.182    Thu Jun 23 14:18 - 14:18  (00:00)
+user1000 pts/0                         Tue Jun 21 17:28 - 17:28  (00:00)
+user     ssh:notty    192.168.8.182    Mon Jun 20 19:27 - 19:27  (00:00)
+user100  pts/1                         Mon Jun 20 13:00 - 13:00  (00:00)
+user     ssh:notty    192.168.8.182    Mon Jun 20 10:44 - 10:44  (00:00)
+root     pts/0                         Fri Jun 10 17:59 - 17:59  (00:00)
+</pre>
+      <p>
+        W przypadku połączeń SSH oznaczenie 
+        <code class="code-inline">notty</code>, mówi nam że nie przydzielono
+        terminala z powodu niepowodzenia logowania. Kiedy w drugiej kolumnie 
+        zobaczymy oznaczenie <em>pts/X</em> (X oznacza numer urządzenia), to
+        możemy stwierdzić, że nie powiodło się przełączenie na wskazanego w
+        pierwszej kolumnie użytkownika. Na serwerach, które mają otwarty port
+        22 oraz pozwalają na zalogowanie się za pomocą hasła polecenie będzie
+        zwracać zazwyczaj bardzo długą listę. Wiele automatów na całym świecie
+        próbuje zalogować się na serwer poprzez zagdywanie użytkownika i hasła.
+      </p>
+      <p>
+        Plikiem, który przechowuje informacje zwracane przez to polecenie
+        jest <em>/var/log/btmp</em>.
+      </p>
+      <p>
+        Ostanim narzędziem pozwalającym na sprawdzenie kto logował się do
+        systemu jest polecenie <strong>lastlog</strong>, wyświetla ono 
+        ostatnie logowanie na podstawie listy użytkowników. 
+      </p>
+<pre class="code-block">
+[root@server1 ~]# lastlog
+...
+user             pts/1    192.168.8.192                             Sat Jun 25 15:06:16 +0200 2022
+vboxadd                                                             **Never logged in**
+user100          pts/1                                              Thu Jun 23 15:55:01 +0200 2022
+user200          pts/0                                              Fri Jun 24 16:55:08 +0200 2022
+user1000         pts/0                                              Tue Jun 21 17:28:44 +0200 2022
+user2000         pts/0                                              Tue Jun 21 17:28:50 +0200 2022
+user3000                                                            **Never logged in**
+user4000                                                            **Never logged in**
+user3            pts/0                                              Thu Jun 23 12:13:34 +0200 2022
+user4            pts/0                                              Thu Jun 23 12:33:09 +0200 2022
+user4100                                                            **Never logged in**
+user4200                                                            **Never logged in**
+user4300         pts/0                                              Thu Jun 23 13:01:04 +0200 2022
+</pre>
+      <p>
+        Napis <code class="code-inline">**Never logged in**</code> oznacza, że
+        użytkownik nie logował się do systemu. Informacje zwracane przez to
+        polecenie są przechowywane w pliku <em>/var/log/lastlog</em>.
+      </p>
+      <h3 id="5.1.2.idandgroup">5.1.2. Informacje o użytkowniku</h3>
+      <p>
+        Podczas pracy z użytkownikami, możemy potrzebować informacji na jego
+        temat. Równie dobrze moglibyśmy sprawdzić go w pliku 
+        <em>/etc/passwd</em>, ale jest lepszy sposób. Na Linuksach dostępne
+        jest polecenie <em>id</em>, które zwraca <em>UID</em>, <em>GID</em>
+        podstawowej grupy oraz grup, do których należy użytkownik podany jak
+        argument tego polecenia:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# id user100
+uid=1001(user100) gid=1001(user100) groups=1001(user100),9999(sgrp)
+</pre>
+      <p>
+        Wówczas jeśli jako my sami potrzebuje wyświetlić, grupy do których
+        należymy możemy użyć polecenia <strong>groups</strong>.
+      </p>
+<pre class="code-block">
+[user100@server1 ~]$ groups
+user100 sgrp
+</pre>
+      <h2 id="5.2.userauthfiles">5.2. Pliki autentykacji użytkowników</h2>
+      <p>
+        Każdy użytkownik, chcący skorzystać z systemu musi się uwierzytelnić
+        za pomocą tylko jemu znanych poświadczeń, wówczas zostaje on
+        autoryzowany do wykonywania różnych czynności w systemie. Sam system
+        do uwierzytelniania użytkowników stosuje kilka plików. 
+      </p>
+      <h3 id="5.2.1.passwdfile">5.2.1. Pliki /etc/passwd</h3>
+      <p>
+        Ten plik jest swoistą bazą danych o użytkownikach w systemie. Każdy
+        jeden wpis to jeden użytkownik.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail -5 /etc/passwd
+user:x:1000:1000:user:/home/user:/bin/bash
+user100:x:1001:1001::/home/user100:/bin/bash
+user200:x:1002:1002::/home/user200:/bin/bash
+user1000:x:1003:1003::/home/user1000:/bin/bash
+user2000:x:1004:1004::/home/user2000:/bin/bash
+</pre>
+      <p>
+        Każdy z tych wpisów zawiera kilka pól oddzielonych od siebie
+        dwukropkiem (<strong>:</strong>). Natomiast same pola oznaczają
+        kolejno:
+      </p>
+      <ul>
+        <li><strong>Nazwę użytkownika</strong> - 
+          <code class="code-inline">user</code>. Nazwy użytkowników na
+          Linuksie nie powinny przekraczać 255 znaków oraz zawierać innych
+          znaków specjalnych niż podkreślnik (<strong>_</strong>) lub 
+          myślnik (<strong>-</strong>) i niepowinny zawierać wielkich liter,
+        </li>
+        <li><strong>Hasło</strong> - <code class="code-inline">x</code>,
+          w tym przypadku <em>x</em> oznacza, że hasło jest zaszyforwane w 
+          pliku <em>/etc/shadow</em>, w tym polu może znajdować się również
+          gwiazdka (<strong>*</strong>), która oznacza że konto jest wyłączone.
+        </li>
+        <li><strong>UID</strong> - <code class="code-inline">1000</code>, jest
+          identyfikator użytkownika, jądro odwołując się do użytkowników
+          używa tych identyfikatorów. W systemie istnieją zakresy 
+          <em>UID</em>, które są przypisywane poszczególnym użytkownikom.
+          Identyfikator 0, jest zarezerwowany dla <em>root</em>, identyfikatory
+          do 1 do 999 są przeznaczone dla użytkowników systemowych (przeważnie
+          tworzonych na potrzeby usług, w RHEL istnieje podział, na 
+          <em>UID</em>-y od 1 do 200 są przeznaczone dla użytkowników
+          przypisanych do wewętrznych usług systemowych a <em>UID</em>-y od 201 
+          do 999 dla pozostałych).</li>
+        <li><strong>GID</strong> - <code class="code-inline">1000</code>, jest
+          to identyfikator grupy podstawowej użytkownika (podczas tworzenia
+          użytkownika, tworzona jest także grupa o takiej samej nazwie jak
+          użytkownik i jest ona nazywana podstwową grupą użytkownika. Istnienie
+          takiej grupy zapewnia spójność uprawnień plików).</li>
+        <li><strong>Komentarz</strong> - <code class="code-inline">user</code>,
+          Komentarz, dawniej pole <em>GECOS</em>, jest miejscem na dodatkowe
+          informacje o użytkowniku, np. numer telefonu lub adres e-mail.</li>
+        <li><strong>Katalog domowy</strong> -
+          <code class="code-inline">/home/user</code>, to pole zawiera ścieżkę
+          do katalogu domowego.</li>
+        <li><strong>Powłoka</strong> -
+          <code class="code-inline">/bin/bash</code>, miejsce dla domyślnego
+          programu uruchamianego zaraz po zalogowaniu najczęsciej jest to
+          jedna z dostępnych w systemie powłok.</li>
+      </ul>
+      <h3 id="5.2.2.shadowfile">5.2.2. Plik /etc/shadow</h3>
+      <p>
+        Plik <em>/etc/shadow</em>, koreluje z plikem <em>/etc/passwd</em> ich
+        wspólnym kluczem jest nazwa użytkownika. Plik ten zamiast ogólnych
+        informacji o użytkowniku zawiera jego hasło oraz zasady związane z
+        hasłami. Tak jak w przypadku pliku <em>passwd</em> każdy wpis
+        odpowiada jedemu użytkownikowi.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail -5 /etc/shadow
+user:$6$bNlZFNZV/wWKGQU8$DgIHeUdALGWs7bZ7Foet2UeHFSANSvYcEtLmn6aLm5QxLcx10jZNkUg.dphdmizej/k5Xe.oEqSCeHAf5/7Gv0::0:99999:7:::
+user100:$6$N3norXlohg0yE1pi$FyeKcBNl4mj/nLbNRlx7KaAQnddG0y/kXpQ9pbgjTV9ti3dQ5q3pIpXm1poa85oxFHFVT9HPTyBmaRNkrSJPX.:19163:0:99999:7:::
+user200:!!:19163:0:99999:7:::
+user1000:!!:19163:0:99999:7:::
+user2000:!!:19163:0:99999:7:::
+</pre>
+      <p>
+        Każdy z tych wpisów zawiera kilka pól oddzielonych od siebie
+        dwukropkiem (<strong>:</strong>). Natomiast same pola oznaczają
+        kolejno:
+      </p>
+      <ul>
+        <li><strong>Nazwę użytkownika</strong> -
+          <code class="code-inline">user</code>, odpowiadającą nazwie
+          użytkownika z pliku <em>/etc/passwd</em>.</li>
+        <li><strong>Zaszyfrowane hasło</strong> -
+          <code class="code-inline">$6$bNlZFNZV/wWKGQU8$DgIHeUdALGWs7bZ7Foet2UeHFSANSvYcEtLmn6aLm5QxLcx10jZNkUg.dphdmizej/k5Xe.oEqSCeHAf5/7Gv0</code>, utworzone na podstawie hasła wpisanego
+          przez użytkownika. RHEL w przypadku przesłonionych haseł używa
+          algorytmu SHA-512. Jeśli to pole zawiera wykrzyknik
+          (<strong>!</strong>), to wówczas użytkownik nie może zalogować się
+          do systemu za pomocą hasła. Puste pole oznacza, że uzytkownik może
+          zalogować się bez wprowadzania hasła.</li>
+        <li><strong>Ostatnia zmiana hasła</strong> - 
+          <code class="code-inline">19163</code>, to pole zawiera liczbę
+          dni, która upłyneła od północy 1 stycznia 1970r. (początku czasu
+          Uniks) do momentu zmiany hasła. To pole można uznać za liczbową
+          datę.</li>
+        <li><strong>Minimalny wiek hasła</strong> -
+          <code class="code-inline">0</code>, wyznacza liczbę dni, która musi
+          upłynąć przed następną zmianą hasła. Puste pole lub zero oznacza
+          iż, nie ustalono minimalnego wieku dla hasła tego użytkownika.</li>
+        <li><strong>Maksymalny wiek hasła</strong> -
+          <code class="code-inline">99999</code>, wyznacza liczbę dni, po
+          której należy zmienić hasło. Hasła, których ważność osiągnie tę 
+          wartość mogą być dalej ważne, jednak system przy następnym logowaniu
+          będzie wymagał jego zmiany.</li>
+        <li><strong>Okres ostrzegania</strong> - 
+          <code class="code-inline">7</code>, określa ilość dni, w których
+          użytkownik będzie informowany o tym, że mija termin ważności jego
+          hasła i musi je zmienić, aby dalej móc się logować do systemu.</li>
+        <li><strong>Okres nieaktywności hasła</strong> - określa ilość dni,
+          przez które przeterminowane hasło będzie jescze akceptowane. Po
+          zalogwaniu system będzie żądać zmiany hasła. W przypadku naszego
+          przykładu, to pole jest puste, a więc nie ma zdefiniowanego tego
+          okresu.</li>
+        <li><strong>Data wygaśnięcia konta</strong> - określa ilość dni od
+          północy 1 stycznia 1970r., po których nie będzie można używać
+          konta do logowania się. Zero bądź puste pole (tak jak na
+          przykładzie) oznacza iż konto nigdy nie wygaśnie.</li>
+        <li><strong>Pole zarezerowane</strong> - pole zarezerowowane do użycia
+          w przyszłości.</li> 
+      </ul>
+      <p>
+        W przypadku pól od zaszyfrowanego hasła do pola zarezerowanego, puste
+        pole lub 0 wyłącza przeznaczone im właściwości. Część z tych opcji 
+        ustawiana jest w pliku <em>/etc/login.defs</em> i nazwane są 
+        <strong>zasadami ważności haseł</strong> lub ang.
+        <em>pasword aging</em>. Na koniec zwróćmy uwagę na szczegóły tego pliku:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# ls -l /etc/shadow
+----------. 1 root root 2012 Jun 25 18:53 /etc/shadow
+</pre>
+      <p>
+        Nikt nie ma żadnych uprawnień do tego pliku. Możliwa jest jego
+        modyfikacja za pomocą specjalnego mechanizmu, który będzie omawiany
+        przy okazji <em>SELinux</em>.
+      </p>
+      <h3 id="5.2.3.group">5.2.3. Plik /etc/group</h3>
+      <p>
+        Plik <em>/etc/group</em> jest odpowiednikiem dla pliku 
+        <em>/etc/passwd</em> tylko, że dla group. Ten plik ma podobną budową
+        do plików <em>/etc/passwd</em> lub <em>/etc/shadow</em> posiada jednak
+        mniejszą ilość pól.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail -5 /etc/group
+user:x:1000:
+user100:x:1001:
+user200:x:1002:
+sgrp:x:9999:user100,user200
+sgrp2:x:8888:user1000,user2000
+</pre>
+      <p>
+        A każde z pół przechowuje kolejno:
+      </p>
+      <ul>
+        <li><strong>Nazwę grupy</strong> - 
+          <code class="code-inline">sgrp</code>.</li>
+        <li><strong>Hasło grupy</strong> -
+          <code class="code-inline">x</code> oznacza, że hasło jest
+          zaszyfrowane w pliku <em>/etc/gshadow</em>. Hasła grupy służą
+          zablokowaniu przełączania się między grupami za pomocą polecenia
+          <strong>newgrp</strong>, aby użytkownicy nie mogli uzyskać dostępu
+          plików innych grup.</li>
+        <li><strong>GID</strong> -
+          <code class="code-inline">9999</code>, identyfikator grupy.</li>
+        <li><strong>Lista członków grupy</strong> -
+          <code class="code-inline">user100,user200</code>, lista użytkowników
+          oddzielonych przecinkami przypisanych do tej grupy. W przypadku
+          podstawowych grup użytkowników (nazwa grupy jest identyczna z nazwą
+          użytkownika), a członek jest domyślny i nie widnieje na liście.</li>
+      </ul>
+      <h3 id="5.2.4.gshadowfile">5.2.4. Plik /etc/gshadow</h3>
+      <p>
+        Grupy jak i użytkownicy również mają swoje hasła. W opisie pola hasła
+        przy okazji pliku <em>/etc/group</em> wyjaśniłem dlaczego tak jest. Te
+        hasła muszą być gdzieś składowane i to w bezpieczny sposób. Hasła grup
+        również są przesłonione jak hasła użytkowników. Miejscem składowania
+        haseł grup jest jest plik <em>/etc/gshadow</em>, zawiera on podobne
+        wpisy jak plik <em>/etc/group</em> i jest z nim powiązany wspólnym
+        kluczem jakim jest nazwa grupy.
+      </p>
+<pre class="code-block">
+[root@server1 user]# tail /etc/gshadow
+user:!::
+user100:!::
+user200:!::
+dba:!::
+user1000:!::
+user2000:!::
+dbagrp:!::
+user90:!::
+g1:!::
+</pre>
+      <p>
+        Plik <em>/etc/gshadow</em> zawiera 4 pola tak jak plik 
+        <em>/etc/group</em>, każde z tych pól oznacza kolejno:
+      </p>
+      <ul>
+        <li><strong>Nazwa grupy</strong> -
+          <code class="code-inline">user</code>, identyczna z nazwą zawartą w
+          we wpisach w pliku <em>/etc/group</em>.</li>
+        <li><strong>Zaszyforwane hasło</strong>, jeśli tym polu pojawia się
+          inny znak taki jak <code class="code-inline">!</code> lub gwiazdka
+          (<strong>*</strong>) oznacza to, że użytkownicy nie mogą za pomocą
+          hasła uzyskać dostępu do grupy.</li>
+        <li><strong>Administratorz grupy</strong>, lista użytkowników mogących
+          zarządzać grupą, mogą oni dodawać i usuwać członków przy użyciu 
+          polecenia <strong>gpasswd</strong>.</li>
+        <li><strong>Członkowie grupy</strong>, oddzielona przecinkami lista
+          użytkowników należąca do tej grupy.</li>
+      </ul>
+      <h2 id="5.3.basicsofusermanagement">5.3. Podstawy zarządzania użytkownikami</h2>
+      <p>
+        W tym podrozdziale poznamy podstawy zarządzania użytkownikami. Będziemy
+        tworzyć użytkowników, zmieniać informacje o nich oraz ich usuwać. 
+        Tworząc nowego 
+        użytkownika wydajemy proste polecenie i podajemy jego nazwę. Taki 
+        użytkownik tworzony jest z domyślnymi wartościami. Zanim zaczniemy
+        tworzyć użytkowników poznamy dwa miejsca, skąd mogą brać się te
+        domyślne wartości.
+      </p>
+      <h3 id="5.3.1.usersdefaultinformations">5.3.1. Domyślnie informacje użytkowników</h3>
+      <p>
+        Informacje o tym jaką przydzielić użytkownikowi powłokę, czy między
+        jakimi wartościami powinien znajdować się jego <em>UID</em> są w
+        systemie z góry określone. Takimi miejscami, w których możemy szukać
+        domyślnych wartości jest plik <em>/etc/default/useradd</em>,
+        którego zawartość dostępna jest po wydaniu poniższego polecenia:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ useradd -D
+GROUP=100
+HOME=/home
+INACTIVE=-1
+EXPIRE=
+SHELL=/bin/bash
+SKEL=/etc/skel
+CREATE_MAIL_SPOOL=yes
+</pre>
+      <p>
+        Z tych informacji możemy wynioskować początkowy <em>GID</em>
+        (<code class="code-inline">GROUP</code>), jednak
+        ta opcja używana jest gdy opcja <em>USERGROUPS_ENAB</em>, w pliku
+        <em>/etc/login.defs</em> (drugim z plików) jest ustawiona na <em>NO</em>.
+        Poza tym znamy domyślną lokalizację tworzenia katalogów domowych
+        (<code class="code-inline">HOME</code>), czas nieaktywność
+        (<code class="code-inline">INACTIVE</code>), który określa liczbę dni
+        pomiędzy wygaśnięciem hasła a trwałym zablokowaniem konta, domyślną
+        datę wygaśnięcia konta (<code class="code-inline">EXPIRE</code>), 
+        domyślną powłokę (<code class="code-inline">SHELL</code>), lokalizację
+        katalogu szkieletowego (<code class="code-inline">SKEL</code>) - 
+        katalog ten przechowuje pliki kopiowane do każdego katalogu domowego
+        nowego użytkownika w momencie jego utworzenia. Ostatnią wartością jest
+        zmienną określająca czy tworzyć pliki skrzynki mailowej każdemu 
+        użytkownikowi
+        (<code class="code-inline">CREATE_MAIL_SPOOL</code>). Nie które z tych
+        wartości możemy modyfikować używając tego samego polecenia, więcej
+        informacji na ten temat znajduje się na stronie podręcznia polecenia
+        <em>useradd</em>.
+      </p>
+      <p>
+        Innym źródłem wartości domyślnych wykorzystywanych podczas tworzenia
+        użytkowników jest plik <em>/etc/login.defs</em>. Zawartość tego pliku
+        najlepiej jest wyświetlić za pomocą poniższego polecenia, które
+        odfiltruje komentarz i puste linie:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep -v ^# /etc/login.defs | grep -v ^$
+MAIL_DIR       /var/spool/mail
+UMASK          022
+HOME_MODE      0700
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_WARN_AGE  7
+UID_MIN                  1000
+UID_MAX                 60000
+SYS_UID_MIN               201
+SYS_UID_MAX               999
+SUB_UID_MIN               100000
+SUB_UID_MAX            600100000
+SUB_UID_COUNT              65536
+GID_MIN                  1000
+GID_MAX                 60000
+SYS_GID_MIN               201
+SYS_GID_MAX               999
+SUB_GID_MIN               100000
+SUB_GID_MAX            600100000
+SUB_GID_COUNT              65536
+ENCRYPT_METHOD SHA512
+USERGROUPS_ENAB yes
+CREATE_HOME    yes
+HMAC_CRYPTO_ALGO SHA512
+</pre>
+      <p>
+        Wewnątrz tego pliku znajdują się definicje takich wartości jak
+        maska użytkownika (<code class="code-inline">umask</code>), elementy
+        polityki haseł (<code class="code-inline">PASS_...</code>) czy zakresy
+        wartości <em>UID</em> oraz <em>GID</em>. W tym pliku również znajduje
+        się nazwa algorytmu używanego do przesłaniania haseł. Opisy
+        poszczególnych wartości zawartych w tym pliku znajdują się na
+        stronie podręcznika.
+      </p>
+      <h3 id="5.3.2.useradd">5.3.2. Tworzenie użytowników</h3>
+      <p>
+        Do tworzenia użytkowników systemie służy polecenie 
+        <strong>useradd</strong>,
+        domyślnie wymaga on wyłącznie podania nazwy użytkownika. Podczas tej
+        czynności zostaną dodane wpisy do plików autentykacyjnych, które 
+        omwialiśmy
+        wcześniej, zostanie utworzony katalog domowy i przekopiowane zostaną
+        do niego pliki z katalogu szkieletowego (<em>/etc/skel</em>). Utworzymy
+        sobie teraz testowego użytkownika.
+      </p>
+<pre class="code-block">
+[root@server1 user]# useradd user1
+</pre>
+      <p>
+        To polecenie utworzy użytkownika z domyślnymi wartościamy identyfkatora,
+        powłoki oraz innymi. Polecenie to daje możliwość zmiany tych wartości
+        podczas tworzenie nowego użytkownika. Poniżej znajduje się lista opcji,
+        na której zawarto najważniejsze z nich:
+      </p>
+      <ul>
+        <li><strong>-d</strong>, pozwala na podanie ścieżki do katalogu
+          domowego użytkownika.</li>
+        <li><strong>-g</strong>, pozwala na podanie <em>GID</em>-u lub nazwy
+          podstawowej grupy użytkownika.</li>
+        <li><strong>-G</strong>, pozwala na wprowadzenie grup, do których ma
+          należeć użytkownik, nazwy podajemy po przecinku (o ile więcej niż
+          jedna).</li>
+        <li><strong>-o</strong>, każdy identyfikator czy to użytkownika czy
+          grupy musi być unikatowy. Ta opcja pozwala na współdzielenie
+          (w tym przypadku) <em>UID</em>-u, choć konieczność użycia tej opcji
+          zachodzi tylko w specyficznych przypadkach.</li>
+        <li><strong>-s</strong>, pozwala na ustalenia domyślnego programu,
+          który uruchamiany jest zaraz po zalogowaniu się użytkownika. Tym
+          programem najczęściej jest powłoka.</li>
+        <li><strong>-u</strong>, pozwala na podanie identyfikatora użytkownika
+          <em>UID</em>, identyfikator powinien być unikatowy w cały systemie,
+          chyba że podano opcję <em>-o</em>.</li>
+      </ul>
+      <p>
+        Chcąc użyć tych opcji podaje się je po nazwie polecenia przed nazwą
+        użytkownika. W ramach ćwiczeń możemy utworzyć kilku użytkowników z
+        losowymi wartościami opcji podanych powyżej. W tym rozdziale poznamy
+        narzędzie, które służy do usuwania użytkowników, ale za nim to zrobimy
+        poznamy polecenie, dzięki któremu będziemy mogli zmienić opcje już
+        utworzonych użytkowników.  
+      </p>
+      <p>
+        Tak utworzonym użytkowników pozostało tylko nadać hasło, przy użyciu
+        polecenia <strong>passwd</strong>.
+      </p>
+      <p>
+        Tutaj podano tylko część opcji tego polecenia, więcej znajduje się
+        na stronie podręcznika. Nie uczmy się także opcji na pamięć, raczej
+        zawsze będziemy mieć dostęp do stron podręcznika.
+      </p>
+      <h3 id="5.3.3.usermod">5.3.3. Zmiana informacji użytkownika</h3>
+      <p>
+        Zmianie informacji użytkownika służy polecenie <strong>usermod</strong>,
+        ma ono prawie identyczne opcje jak polecenie <em>useradd</em>. Poza
+        kilkoma wyjątkami.
+      </p>
+      <ul>
+        <li><strong>-l</strong> - opcja pozwala na podanie nowej nazwy
+          użytkownika.</li>
+        <li><strong>-d</strong> - opcja pozwala na zmianę katalogu domowego.
+          Nie było by tej opcji na tej liście gdyby nie fakt, iż aby katalog
+          został utworzony na podanej ścieżce, ta opcją musi zostać użyta w
+          raz z opcją <em>-m</em>, której zadaniem jest przeniesienie danych
+          z poprzedniego katalogu.</li>
+      </ul>
+      <p>
+        Na poniższym przykładzie pokazano zmianę katalogu domowego użytkownika
+        <em>user90</em>:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# tail /etc/passwd
+...
+user90:x:5003:5003::/home/user90:/bin/bash
+
+[root@server1 ~]# usermod -d /usr/home90 -m user90
+[root@server1 ~]# tail /etc/passwd
+...
+user90:x:5003:5003::/usr/home90:/bin/bash
+
+[root@server1 ~]# ls -al /usr/home90
+total 12
+drwx------.  3 user90 user90  78 Jun 26 16:06 .
+drwxr-xr-x. 13 root   root   158 Jun 27 14:31 ..
+-rw-r--r--.  1 user90 user90  18 Nov  5  2021 .bash_logout
+-rw-r--r--.  1 user90 user90 141 Nov  5  2021 .bash_profile
+-rw-r--r--.  1 user90 user90 492 Nov  5  2021 .bashrc
+drwxr-xr-x.  4 user90 user90  39 Jun 26 13:48 .mozilla
+</pre>
+      <p>
+        Pozostałe opcje, które znajdują się na stronie podręcznika tego
+        polecenia możemy używać w ten sam sposób jak w przypadku
+        <em>useradd</em>.
+      </p>
+      <h3 id="5.3.4.userdel">5.3.4. Usuwanie użytkowników</h3>
+      <p>
+        Kiedy użytkownicy przestają być potrzebni, ze względów bezpieczeństwa
+        można, albo ich zablokować albo usunąć. W tym rodziale zajmiemy się
+        wyłącznie usuwaniem. Polecenie do usuwania użytkowników to
+        <strong>userdel</strong>. Jest ono prostolinijne i niewymaga 
+        dodatkowych opcji, wystarczy podać nazwę użytkownika jako
+        argument polecenia i użytkownik zostanie usunięty, jednak jego dane
+        pozostaną w systemie. Użytkownika wraz z danymi możemy usunąć za
+        przy użyciu opcji <em>-r</em>.
+      </p> 
+<pre class="code-block">
+[root@server1 ~]# userdel -r user90
+[root@server1 ~]# tail /etc/passwd
+chrony:x:986:981::/var/lib/chrony:/sbin/nologin
+dnsmasq:x:985:980:Dnsmasq DHCP and DNS server:/var/lib/dnsmasq:/sbin/nologin
+tcpdump:x:72:72::/:/sbin/nologin
+systemd-oom:x:978:978:systemd Userspace OOM Killer:/:/usr/sbin/nologin
+user:x:1000:1000:user:/home/user:/bin/bash
+user100:x:1001:1001::/home/user100:/bin/bash
+user200:x:1002:1002::/home/user200:/bin/bash
+user5000:x:5000:7000::/home/user5000:/bin/bash
+user1000:x:5001:5001::/home/user1000:/bin/bash
+user2000:x:5002:5002::/home/user2000:/bin/bash
+[root@server1 ~]# ls -al /usr/home90
+ls: cannot access '/usr/home90': No such file or directory
+</pre>
+      <h3 id="5.3.5.nologinusers">5.3.5. Użytkownicy bez możliwości logowania</h3>
+      <p>
+        Tak jak na początku powiedzieliśmy sobie, że użytkownicy w systemie
+        istnieją, po to aby wyznaczać granice. Takim użytkownikami
+        są najczęściej są użytkownicy systemowi, którzy są związani z róznego
+        rodzaju usługami. Cechą która ich wyróżnia jest fakt, iż nie mają
+        oni możliwości logowania do systemu, inaczej mówiac są 
+        <strong>użytkownikami nieinteraktywnymi</strong>. Użytkownicy tego 
+        typu w miejscu powłoki mają
+        wskazany program <strong>/sbin/nologin</strong>. Ten mały program przy
+        próbie zalogowania zwróci informacje o tym, że to konto jest obecnie
+        niedostępne. Treść tego komunikatu możemy zmieniać, wpisująć nasz
+        komunikat do pliku <em>/etc/nologin.txt</em>. Użytkownikiem bez
+        możliwości logowania może być każdy, kto ma zamiast powłoki ustawiony
+        właśnie ten program. Poniżej znajduje się polecenie, które zmieni
+        użytkownika <em>user2000</em> w użytkownika nieinteraktywnego.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# usermod -s /sbin/nologin user2000
+[root@server1 ~]# tail /etc/passwd
+chrony:x:986:981::/var/lib/chrony:/sbin/nologin
+dnsmasq:x:985:980:Dnsmasq DHCP and DNS server:/var/lib/dnsmasq:/sbin/nologin
+tcpdump:x:72:72::/:/sbin/nologin
+systemd-oom:x:978:978:systemd Userspace OOM Killer:/:/usr/sbin/nologin
+user:x:1000:1000:user:/home/user:/bin/bash
+user100:x:1001:1001::/home/user100:/bin/bash
+user200:x:1002:1002::/home/user200:/bin/bash
+user5000:x:5000:7000::/home/user5000:/bin/bash
+user1000:x:5001:5001::/home/user1000:/bin/bash
+user2000:x:5002:5002::/home/user2000:/sbin/nologin
+</pre>
+      <p>
+        Kiedy spróbuje się na niego zalogować otrzymam wspomniany komunikat.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# su - user2000
+This account is currently not available.
+</pre>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Jeśli w systemie użytkownik, który teoretycznie nie powinien mieć
+        możliwości logowania, zaloguje się do systemu to znaczy, że mamy
+        poważny problem z bezpieczeństwem. Wówczas należy sprawdzić 
+        w pliku <em>/etc/passwd</em> czy wszyscy użytkownicy nieinteraktywni 
+        mają ustawiony domyślny program na <em>/sbin/nologin</em>.
+      </p>
+      <h3 id="exec5.1">Ćwiczenie 1: Sprawdzenie prób logowania użytkowników</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>. Zapisz przy użyciu
+        polecenia <em>Vim</em> ostaniego użytkownika, któremu udało się
+        zalogować oraz ostatniego którego logowanie nie powiodło się. Zapisz 
+        ostatnie
+        uruchomienie systemu, poza obecnym włączniem oraz listę użytkowników, 
+        którzy nigdy się nie logowali do systemu.
+      </p>
+      <h3 id="exec5.2">Ćwiczenie 2: Weryfikacja użytkownika oraz grupy</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>, uruchom polecenie
+        <em>who</em> oraz <em>w</em> porównaj wyniki ich działania. Uruchom
+        polecnia <em>id</em> oraz <em>groups</em> następnie omów informacje
+        zwracane przez nie.
+      </p>
+      <h3 id="exec5.3">Ćwiczenie 3: Tworzenie użytkowników</h3>
+      <p>
+        Jak superużytkownik na maszynie <em>server1</em>, utwórz użytkownika o
+        nazwie <em>user4100</em>, o identyfikatorze <em>4100</em>, katalogu
+        domowym znajdującym się katalogu <em>/usr</em>. Następnie utworz
+        użytkownika <em>user4200</em> z domyślnymi ustawieniami. Przypisz obu
+        hasło. Następnie wyświetl dotyczące ich wpisy w plikach autentykacji
+        (<em>/etc/{passwd,shaddow,group,gshadow}</em>).
+      </p>
+      <h3 id="exec5.4">Ćwiczenie 4: Tworzenie użytkowników nieinteraktywnych</h3>
+      <p>
+        Jako superużytkownik na maszynie <em>server1</em>, utwórz użytkownika
+        <em>user4300</em>, następnie zmień informacje o nim tak, aby stał sie
+        użytkownikiem nieinterkatywnym. Ustaw mu hasło i spróbuj się zalogować
+        na niego. Jaki komunikat został wyświetlony? Wyświetl wpis użytkownika
+        w pliku <em>/etc/passwd</em>. Co spowodowało, że użytkownik nie może
+        się zalgować?
+      </p>
+      <h2 id="ch5summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale dowiedzieliśmy się w jaki sposób możemy sprawdzić
+        próby logowania się do systemu, kto jest zalgowany i co robi. 
+        Poznaliśmy zestaw plików odpowidzialnych za autentykacje, a także
+        nauczyliśmy w podstawowym stopniu zarządzać użytkownikami. W następnym
+        rozdziale skupimy się na zasadach haseł i przełączaniu użytkowników.
+      </p>
+      <h1 id="6.advancedusermanagement">6. Zaawansowane zarządzanie użytkownikami</h1>
+      <p>
+        W poprzednim rozdziale nauczyliśmy się tworzyć, usuwać użytkowników oraz
+        edytować informacje o nich. Poznaliśmy plik uwierzytelniania, którym
+        między innymi jest plik <em>/etc/shadow</em>, w nim przechowywane są
+        przesłonione hasła, zasady ważności haseł oraz kont i tym
+        zajmiemy sie na początku.
+      </p>
+      <h2 id="6.1.passwordaging">6.1. Zasady ważności hasła</h2>
+      <p>
+        Każdy administrator w systemie, który wykorzystuje intensywnie 
+        użytkowników, powinien
+        wdrożyć zasady bezpieczeństwa z nimi związane. Może wymusić na osobach 
+        korzystających z kont ich zabezpieczenie po przez regularną zmianę hasła, 
+        zablokować nieużywane konta czy utworzyć dla użytkowników tylko konta
+        tymczasowe, które po upływie określonego czasu zostaną automatycznie
+        zablokowane. Te zasady mieszczą w się 
+        w dziedzinie ustawień ważności hasła i są realizowane w dystrybucjach
+        Linuksa za pomocą dwóch poleceń: <strong>chage</strong> oraz
+        <strong>passwd</strong>. Poniżej w tabeli skumulowałem opcje 
+        tych dwóch poleceń odpowiadające za konkrentą czynność.
+      </p>
+      <table>
+        <thead>
+          <tr>
+            <th></th>
+            <th>chage</th>
+            <th>passwd</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td><strong>Data ostatniej modyfikacji hasła</strong></td>
+            <td style="text-align: center"><em>-d</em></td>
+            <td style="text-align: center"><em>X</em></td>
+          </tr>
+          <tr>
+            <td><strong>Data wygaśnięcia konta</strong></td>
+            <td style="text-align: center"><em>-E</em></td>
+            <td style="text-align: center"><em>X</em>
+          </tr>
+          <tr>
+            <td><strong>Czas nieaktywności hasła</strong></td>
+            <td style="text-align: center"><em>-I</em></td>
+            <td style="text-align: center"><em>-i</em></td>
+          </tr>
+          <tr>
+            <td><strong>Informacje o zasadach użytkownika</strong></th>
+            <td style="text-align: center"><em>-l</em></td>
+            <td style="text-align: center"><em>-S</em></td>
+          </tr>
+          <tr>
+            <td><strong>Minimalna ważność hasła</strong></td>
+            <td style="text-align: center"><em>-m</em></td>
+            <td style="text-align: center"><em>-n</em></td>
+          </tr>
+          <tr>
+            <td><strong>Maksymalna ważność hasła</strong></th>
+            <td style="text-align: center"><em>-M</em></td>
+            <td style="text-align: center"><em>-x</em></td>
+          </tr>
+          <tr>
+            <td><strong>Okres ostrzegania</strong></th>
+            <td style="text-align: center"><em>-W</em></td>
+            <td style="text-align: center"><em>-w</em></td>
+          </tr>
+        </tbody>
+      </table>
+      <p>
+        Po za tymi wspólnymi cechami, polecenie <em>passwd</em>, jest wstanie:
+      </p>
+      <ul>
+        <li><strong>usunąć hasło</strong> - <em>-d</em>, takie konto, wówczas
+          staje się kontem bez hasła.</li>
+        <li><strong>wymusić utratę ważności hasła</strong> - <em>-e</em>, po
+          zalogowaniu na takie konto, wymagana będzie zmiana hasła. Ustawienie
+          opcji <em>-d</em> polecenia <em>chage</em>, daje ten sam efekt.</li>
+        <li><strong>zablokować konto</strong> - <em>-l</em>, użytkownik nie
+          będzie mieć możliwości zalogowania się do systemu.</li>
+        <li><strong>odblokować konto</strong> - <em>-u</em>, przywraca
+          możliwość logowania się zablokowanemu kontu.</li>
+      </ul>
+      <p>
+        Stosując <em>chage</em> lub <em>passwd</em> nazwę użytkownika podajemy
+        po opcjach i ich wartościach. Na poniższym przykładzie za prezentowałem
+        w jaki sposób możemy ustawić wszystkie pozostałe pola we wpisie w pliku
+        <em>/etc/shadow</em> za pomocą powyższych poleceń.
+      </p>
+<pre class="code-block">
+#chage:
+[root@server1 ~]# chage -m 7 -M 28 -W 5 -I 7 -E 2022-12-31 user3000
+[root@server1 ~]# chage -l user3000
+Last password change                                   : Jun 28, 2022
+Password expires                                       : Jul 26, 2022
+Password inactive                                      : Aug 02, 2022
+Account expires                                                : Dec 31, 2022
+Minimum number of days between password change         : 7
+Maximum number of days between password change         : 28
+Number of days of warning before password expires      : 5
+[root@server1 ~]# grep 'user3000' /etc/shadow
+user3000:$6$AjNe9ajpYrZ1Sjld$NN36zAMKPlnJElCvuUX1UM0fc6Ymc5pLY4medoHRMCWJhnsoiuKSpjbo7uwTZVkVlv.swqQJ5Dxoa2QZyjsXO.:19171:7:28:5:7:19357:
+
+#passwd:
+[root@server1 ~]# passwd -n 5 -x 28 -w 5 -i 7 user4000
+Adjusting aging data for user user4000.
+passwd: Success
+[root@server1 ~]# passwd -S user4000 
+user4000 PS 2022-06-28 5 28 5 7 (Password set, SHA512 crypt.)
+[root@server1 ~]# grep 'user4000' /etc/shadow
+user4000:$6$29yZ7yqj2lWdSoQE$AMp2ZXAqxa.wWMA88dINDdogjych/Yshnip1whwaqymLTS4ALW9UGx9406tZmsghOTXptBIFrq4UvDF/.sl2f0:19171:5:28:5:7::
+</pre>
+      <p>
+        Za pomocą polecenia <em>passwd</em>, nie możemy dodać daty wygaśnięcia
+        konta. Jednak to polecenie wraz z poleceniem, które znamy z
+        poprzednie rozdziału <em>usermod</em>, może blokować i odblokowywać
+        konta. Zablokujemy i odblokumjemy oba wcześniej wykorzystwane konta.
+      </p>
+      <p>
+        Blokowanie kont za pomocą polecenia <em>passwd</em>:
+      </p>
+<pre class="code-block">
+[root@server1 ~]# passwd -l user3000
+Locking password for user user3000.
+passwd: Success
+[root@server1 ~]# grep 'user3000' /etc/shadow
+user3000:!!$6$AjNe9ajpYrZ1Sjld$NN36zAMKPlnJElCvuUX1UM0fc6Ymc5pLY4medoHRMCWJhnsoiuKSpjbo7uwTZVkVlv.swqQJ5Dxoa2QZyjsXO.:19171:7:28:5:7:19357:
+[root@server1 ~]# passwd -u user3000
+Unlocking password for user user3000.
+passwd: Success
+[root@server1 ~]# grep 'user3000' /etc/shadow
+user3000:$6$AjNe9ajpYrZ1Sjld$NN36zAMKPlnJElCvuUX1UM0fc6Ymc5pLY4medoHRMCWJhnsoiuKSpjbo7uwTZVkVlv.swqQJ5Dxoa2QZyjsXO.:19171:7:28:5:7:19357:
+</pre>
+      <p>
+        Jak możemy zauważyć po zablokowaniu konta przed przesłonionym hasłem
+        zostały umieszczone dwa wykrzykniki, które po odblokowaniu konta
+        zostały usunięte. Poniżej znajdują się te same czynności wykonane
+        przy użyciu polecenia <em>usermod</em>.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# usermod -L user4000
+[root@server1 ~]# grep 'user4000' /etc/shadow
+user4000:!$6$29yZ7yqj2lWdSoQE$AMp2ZXAqxa.wWMA88dINDdogjych/Yshnip1whwaqymLTS4ALW9UGx9406tZmsghOTXptBIFrq4UvDF/.sl2f0:19171:5:28:5:7::
+[root@server1 ~]# usermod -U user4000
+[root@server1 ~]# grep 'user4000' /etc/shadow
+user4000:$6$29yZ7yqj2lWdSoQE$AMp2ZXAqxa.wWMA88dINDdogjych/Yshnip1whwaqymLTS4ALW9UGx9406tZmsghOTXptBIFrq4UvDF/.sl2f0:19171:5:28:5:7::
+</pre>
+      <p>
+        W przypadku polecenia <em>usermod</em>, umieszczony został tylko jeden
+        wykrzyknik przed hasłem, jednak nie ważne czy został umieszczony jeden
+        czy dwa, wykrzyknik przed przesłonionym hasłem oznacza, że konto jest
+        zablokowane.
+      </p>
+      <h2 id="6.2.groupmanaging">6.2. Zarządzanie grupami</h2>
+      <p>
+        Podobnie tak jak w przypadku użytkowników, w poprzednim rozdziale 
+        tak i grupami możemy zarządać w podobny sposób. Możemy je dodawać z
+        dostosowanymi do potrzeb informacjami, zmieniać ich informacje oraz
+        usuwać. 
+      </p>
+      <h3 id="6.2.1.groupadd">6.2.1. Tworzenie nowych grup</h3>
+      <p>
+        Do tworzenia nowych grup służy polecenie <strong>groupadd</strong>,
+        które do utworzenia grupy z domyślnymi wartościami wymaga jedynie jej
+        nazwy. Poniżej znajdują się najważniejsze opcje tego polecenia:
+      </p>
+      <ul>
+        <li><strong>-g</strong>, pozwala na podanie własnego identyfikatora
+          grupy <em>GID</em>, identyfikator powinien być unikatowy, chyba że
+          podano opcję <em>-o</em>.</li>
+        <li><strong>-o</strong>, pozwala na współdzielenie identyfikatora z
+          inną grupą.</li>
+        <li><strong>-r</strong>, tworzy grupę systemową z identyfikatorem w
+          zakresie podanym w pliku <em>/etc/login.defs</em>, przeważnie 
+          między 201 a 999.</li>
+        <li><strong>-U</strong>, pozwala podać listę użytkowników, którzy będą
+          należeć do grupy, nazwy użytkowników są oddzielone od siebie
+          przecinkiem.</li>
+      </ul>
+<pre class="code-block">
+[root@server1 ~]# groupadd -g 9999 sgrp
+[root@server1 ~]# grep 'sgrp' /etc/group
+sgrp:x:9999:
+</pre>
+      <p>
+        Na powyższym przykładzie utworzyłem grupę z niestandardowym 
+        identyfikatorem, następnie wyświetliłem jej wpis w pliku 
+        <em>/etc/group</em>.
+      </p>
+      <h3 id="6.2.2.groupmod">6.2.2. Zmiana informacji grupy</h3>
+      <p>
+        Polecenie <strong>groupmod</strong>, posiada takie samo zastosowanie
+        dla grup, jak polecenie <em>usermod</em> dla użytkowników. Część opcji
+        <em>groupmod</em> odpowiada opcjom z polecenia <em>groupadd</em>.
+        Na wyszczególnienie zasługuje opcja <strong>-n</strong>, która pozwala
+        na zmianę nazwy grupy.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# groupmod -g 8888 -n sysadm sgrp
+[root@server1 ~]# grep 'sgrp' /etc/group
+[root@server1 ~]# grep 'sysadm' /etc/group
+sysadm:x:8888:
+</pre>
+      <p>
+        Jak możemy zobaczyć na przykładzie grupie 
+        <code class="code-inline">sgrp</code> został zmieniony identyfikator
+        oraz nazwa. Teraz ta grupa widnieje pod <em>GID</em>-em
+        <code class="code-inline">8888</code> oraz pod nazwą
+        <code class="code-inline">sysadm</code>.
+      </p>
+      <h3 id="6.2.3.groupdel">6.2.3. Usuwanie grup</h3>
+      <p>
+        Jeśli grupa nie jest już potrzebna w systemie możemy ją usunąć. Do
+        usuwania grup służy polecenie <strong>groupdel</strong>. Polecenie jest
+        bardzo proste w użyciu. Jedyny wymagany argument to nazwa grupy.
+      </p>
+<pre class="code-block">
+[root@server1 ~]# groupdel sysadm
+[root@server1 ~]# grep 'sysadm' /etc/group
+</pre>
+      <p>
+        Grupa została usunięta. Polecenie <code class="code-inline">grep</code>
+        nie mogło odnaleźć wzorca <code class="code-inline">sysadm</code> w
+        pliku <em>/etc/group</em>.
+      </p>
+      <h2 id="6.3.suandsudo">6.3. Przełączanie użytkowników oraz uruchamianie poleceń jako superużytkownik</h2>
+      <p>
+        Wykonywanie zadań administracyjnych najczęściej będzie wymagać
+        podniesienia uprawnień do poziomu superużytkownika - <em>root</em>.
+        Do tej pory wszystkie polecenia w tym materiale wykonywałem z poziomu
+        konta <em>root</em> (wyjątkowowo kilka poleceń zostało wykonanych jako
+        zwykły użytkownik), więc aby wykonywać zadania administracyjne
+        należy się zalogować jak superużytkownik. Logowanie bezpośrednie na to
+        konto nie jest dobrą praktyką. A do dyspozycji mamy dwa rozwiązania.
+        Pierwszym z nich jest przełączenie użytkownika. 
+      </p>
+      <h3 id="6.3.1.su">6.3.1. Przełącznie użytkownika</h3>
+      <p>
+        Pierwszą z metod jest zalogowanie się na nasze konto (konto dostępowe,
+        zwykły użytkownik), a następnie przełącznie się na konto <em>root</em>
+        za pomocą polecenia <strong>su</strong>. To polecenie pozwala na
+        przełączenie się na dowolne konto, jeśli jako pierwszy argument podamy
+        myślnik (<strong>-</strong>) przed nazwą użytkownika podczas
+        przełączania zostaną uruchomione skrypty startowe, które stworzą nam
+        środowisko jak najbardziej zbliżone do bezpośredniego logowania.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ su - root
+Password: 
+[root@server1 ~]# 
+</pre>
+      <p>
+        Za pomocą tego polecenia możemy przełączyć się na dowolne konto, jeśli
+        zwykli użytkownicy przełączają się między kontami wymagane będzie
+        podanie hasła dla docelowego konta, wyjątkiem tutaj jest
+        superużytkownik, który nie musi podawać żadnych haseł.
+      </p>
+      <p>
+        Aby korzystać z tej metody nie trzeba nawet otwierać sesji powłoki jako
+        przełączony użytkownik, możemy po prostu wykonać polecenie jako on za
+        pomocą opcji <em>-c</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ su root -c 'vgs'
+Password: 
+  VG   #PV #LV #SN Attr   VSize   VFree
+  rhel   1   2   0 wz--n- &lt;19.00g    0 
+</pre>
+      <p>
+        Korzystanie z polecenia <em>su</em>, nie jest zbyt elastycznym
+        rozwiązaniem, daje pełen dostęp do superużytkownika gdzie nie jest to
+        konieczne. Ten rodzaj podniesienia uprawnień w systemie używany jest
+        przez kilka dystrybucji w jednym celu aby pobrać i skonfigurować 
+        to drugie rozwiązanie.
+      </p>
+      <h3 id="6.3.2.sudo">6.3.2. Polecenie sudo</h3>
+      <p>
+        Użycie polecenia <strong>sudo</strong> jest znacznie lepszym
+        rozwiązaniem. Głównym argumentem jest fakt, iż możemy skonfigurować
+        to polecenie w taki sposób, aby dać użytkownikom dostęp tylko do
+        tych poleceń których naprawdę potrzebują. Jednak na początku zajmiemy 
+        się prostszą konfiguracją, czyli stworzeniem lokalnego administratora,
+        którego konto dalej będzie zwykłym użytkownikiem. 
+      </p>
+      <p>
+        Do konfiguracji tego narzędzia służy plik <em>/etc/sudoers</em> oraz
+        katalog <em>/etc/sudoers.d</em>, w którym wystarczy umieścić plik z
+        konfiguracją. Plik <em>/etc/sudoers</em>, możemy edytować dowolnym
+        edytorem, jednak pakiet <em>sudo</em> posiada specjalne polecenie
+        <strong>visudo</strong>, które stworzy kopie tymczasową pliku, na 
+        której
+        będziemy dokonywać zmian (polecenie samoczynnie uruchomi edytor), 
+        następnie polecenie nadpisze oryginalny plik i usunie plik tymczasowy. 
+        Najprostszą konfiguracją jaką możemy
+        wykonać jest nadanie zwykłemu użytkownikowi uprawnień do wszystkich
+        funkcji administracyjnych. Zmian możemy dokonać w dowolnym miejscu w 
+        pliku, jednak nalepiej
+        znaleźć odpowiednie do tego miejsce. Możemy je namierzyć wyszukując
+        linię <code class="code-inline">root ALL=(ALL)  ALL</code>, skopiować 
+        ją, wkleić pod nią i zmienić tylko nazwę użytkownika na początku linii:
+      </p>
+<pre class="code-block">
+user ALL=(ALL)  ALL
+</pre>
+      <p>
+        Ten wpis zapewni użytkownikowi <code class="code-inline">user</code>
+        dostęp do wszystkich funkcji administracyjnych w systemie. Oprócz
+        użytkownikom, dostęp do wszystkich lub określonych funkcji możemy nadać
+        grupie. Kiedy zajdzie taka potrzeba wystarczy dopisać użytkownika do
+        grupy i nie trzeba już edytować pliku. Konfiguracja grupy różni się od
+        konfiguracji użytkownika tym, że nazwę grupy poprzedza się znakiem
+        procentu (<strong>%</strong>):
+      </p>
+<pre class="code-block">
+%sysadms ALL=(ALL)  ALL
+</pre>
+      <p>
+        We wpisach konfiguracyjnych znajdują się aż trzy słowa 
+        <code class="code-block">ALL</code>, każde z nich ma oddzielne
+        znacznie. Pierwsze słowo <em>ALL</em> po nazwie użytkownika oznacza
+        nazwę komputera (lub adres IP), ponieważ plik <em>/etc/sudoers</em> 
+        może być współdzielony między innymi komputerami, jednak ten plik 
+        będzię dotyczyć tylko tego systemu dlatego też może pozostać 
+        <em>ALL</em>. Drugie słowo <em>ALL</em> w nawiasie oznacza jako kto
+        będzie wykonywać te polecenie, ta lista pozwala wybrać
+        użytkownika (po zastosowaniu opcji <em>-u</em>) do wykonania polecenia.
+        W nie których systemach możemy spotkać się z zapisem 
+        <em>(ALL:ALL)</em>, zapis <em>ALL</em> po dwukropku oznacza listę grup.
+        Grupę możemy wybrać z pomocą opcji <em>-g</em>. Ostanie <em>ALL</em>
+        jest listą programów do których użytkownik poprzedzający polecenie
+        narzędziem <em>sudo</em> będzie mieć dostęp. Poniżej przykładowe użycie
+        polecenia <em>sudo</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo vgs
+[sudo] password for user: 
+  VG   #PV #LV #SN Attr   VSize   VFree
+  rhel   1   2   0 wz--n- &lt;19.00g    0
+</pre>
+      <p>
+        Podczas uruchamia programu <code class="code-inline">vgs</code>, 
+        <em>sudo</em>, po prosiło o hasło - hasło użytkownika, który wydaje 
+        to polecenie.
+        Narzędzie <em>sudo</em> możemy skonfigurować w taki sposób aby nie
+        wymagało hasła podczas uruchamiania programu. We wcześniejszej 
+        dyrektywie, konfigurującej użytkownika przed ostatnim słowem <em>ALL</em>
+        dopisujemy <em>NOPASSWD:</em>.
+      </p>
+<pre class="code-block">
+user ALL=(ALL)  NOPASSWD:ALL
+</pre>
+      <p>
+        Najczęściej naszym zadaniem związanym z poleceniem <em>sudo</em> będzie
+        przypisanie konkretnym użytkownikom dostępu do określonych poleceń.
+        Jeśli do skonfigrowania mamy wiele takich elementów za równo poleceń
+        jak i użytkowników, to aby zrobić to jak najefektywniej należy użyć
+        aliasów. <em>Sudo</em> swojej konfiguracji wyróżnia aliasy przeznaczone
+        dla użytkowników jak i dla poleceń. Alias z listą użytkowników tworzymy
+        tak jak na przykładzie:
+      </p>
+<pre class="code-block">
+User_Alias  PKGADM = user1, user100, user200
+</pre>
+      <p>
+        Po słowie <code class="code-inline">User_Alias</code> zapisujemy nazwę
+        aliasu, w tym przypadku jest <code class="code-inline">PKG_ADM</code>
+        po znaku równości (<strong>=</strong>) podajemy listę użytkowników
+        tak jak na przykładzie powyżej. Ze zbiorem poleceń jest podobnie ale
+        zmienia się dyrektywa inicjująca alias.
+      </p>
+<pre class="code-block">
+Cmnd_Alias PKGCMD = /usr/bin/yum, /usr/bin/rpm
+</pre>
+      <p>
+        Po zdefiniowaniu obu aliasów, możemy przejść do przypisnia aliasowi
+        <code class="code-inline">PKGADM</code> (określonym użytkownikom) 
+        dostępu do poleceń zapisanych w 
+        <code class="code-inline">PKGCMD</code>.
+      </p>
+<pre class="code-block">
+PKGADM ALL = PKGCMD
+</pre>
+      <p>
+        Teraz użytkownicy zdefiniowani w aliasie 
+        <code class="code-inline">PKGADM</code> będą mogli użyć tylko i 
+        wyłącznie poleceń zdefiniowanych w <code class="code-inline">PKGCMD</code>
+      </p>
+      <p>
+        Podczas pracy będziemy zazwyczaj definiować aliasy użytkowników,
+        ponieważ jeśli rozejrzymy się po pliku <em>/etc/sudoers</em>, definicje
+        aliasów z pogrupowanymi poleceniami są już zapisane w komentarzach
+        wystarczy usunąć znak komentarza oraz przypisać ten alias określonej
+        grupie użytkowników.
+      </p>
+      <p>
+        Użycie polecenia <em>sudo</em> jest rejestrowane. Wpisy zapisywane są
+        do pliku <em>/var/log/secure</em> ich odczyt wymaga uprawnień
+        superużytkownika. We wpisach znajduje się nazwa użytkownika, który
+        wywołał to polecenie jak i samo polecenie.
+      </p>
+      <p>
+        Więcej informacji na temat tego narzędzia znajduje się na stronie
+        podręcznika samego polecenia jak i pliku <em>/etc/sudoers</em>. Jak
+        ćwiczenie, nadajmy uprawnienia do pełnych funkcji administracyjnych
+        zwykłemu użytkownikowi, którego tworzyliśmy podczas instalacji
+        systemu na maszynie. Od tego momentu na wszystkich przykładach będę
+        używać tego konta, a uprawnienia administracyjne będę wymuszać za 
+        pomocą polecenia <em>sudo</em>.
+      </p>
+      <h2 id="6.4.chownchgrp">6.4. Zmiana praw własności plików i katalogów</h2>
+      <p>
+        Polecenie <strong>chown</strong>, omówiliśmy sobie podczas omawiania
+        uprawnień plików. Polecenie to służy do zmiany właściciela oraz
+        ewentualnie grupy, do której należy element. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l file1 
+-rw-r--r--. 1 user user 0 Jun 26 15:30 file1
+[user@server1 ~]$ sudo chown user100 file1
+[sudo] password for user: 
+[user@server1 ~]$ ls -l file1
+-rw-r--r--. 1 user100 user 0 Jun 26 15:30 file1
+</pre>
+      <p>
+        Jednak w systemie istnieje inne polecenie, dzięki któremu możemy
+        zmienić grupę. Jest nim <strong>chgrp</strong>. Składania 
+        polecenia identyczna do składni <em>chown</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo chgrp user100 file1
+[sudo] password for user: 
+[user@server1 ~]$ ls -l file1 
+-rw-r--r--. 1 user100 user100 0 Jun 26 15:30 file1
+[user@server1 ~]$ 
+</pre>
+      <p>
+        Jak możemy zauważyć grupa, do której należy plik została zmieniona
+        w porównaniu do szczegółów z poprzedniego przykładu.
+      </p>
+      <p>
+        Polecenia <em>chown</em> możemy również używać rekurencyjnie, aby
+        zmieniać prawa własności całych struktur katalogowych wraz z plikami.
+        Tej czynności służy opcja <em>-R</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo chown -R root:root /tmp/etc
+</pre>
+      <p>
+        Na powyższym przykładzie zmieniłem właściciela oraz grupę do wszystkim 
+        elementom w katalogu <code class="code-inline">/tmp/etc</code>.
+      </p>
+      <h3 id="exec6.1">Ćwiczenie 1: Utwórz użytkowników oraz skonfiguruj zasady haseł</h3>
+      <p>
+        Na maszynie <em>server1</em> utwórz grupę <em>lnxgrp</em> o numerze
+        <em>GID</em> 6000. Utwórz użytkownika <em>user5000</em> o numerze
+        <em>UID</em> 5000 oraz numerze <em>GID</em> 6000. Przypisz mu hasło, a
+        następnie ustaw minimum 4 dni do następnej zmiany hasła, ważność hasła
+        na 30 dni oraz okres ostrzegania na 10 dni. Konto tego użytkownika
+        powinno wygasnąć 20 grudnia 2022 roku.
+      </p>
+      <h3 id="exec6.2">Ćwiczenie 2: Zablokuj i odblokuj użytkownika</h3>
+      <p>
+        Na maszynie <em>server1</em> zablokuj użytkownika <em>user5000</em> za
+        pomocą polecenia <em>passwd</em>. Sprawdź jak zmienił się jego wpis w 
+        pliku <em>/etc/shadow</em>. Spróbuj się zalogować na użytkownika.
+        Odblokuj go za pomocą polecenia
+        <em>usermod</em> zweryfikuj jego odblokowanie na podstawie wpisu z 
+        pliku powyżej.
+      </p>
+      <h3 id="exec6.3">Ćwiczenie 3: Zmień dane grupy</h3>
+      <p>
+        Na maszynie <em>server1</em> zmień <em>GID</em> grupy <em>lnxgrp</em> 
+        z 6000 na 7000, dodaj do niej użytkowników <em>user1000</em> oraz 
+        <em>user2000</em>
+        (jeśli nie istnieją utwórz ich), na koniec zmień nazwę grupy na 
+        <em>dbagrp</em> i zweryfikuj zmiany.
+      </p>
+      <h3 id="exec6.4">Ćwiczenie 4: Konfiguracja dostępu do sudo</h3>
+      <p>
+        Na maszynie <em>server1</em>, skonfiguruj polecenie <em>sudo</em> dla
+        użytkownika <em>user5000</em>, tak aby miał dostęp do wszystkich
+        funkcji administracyjnych bez podawania hasła. W celu sprawdzenia
+        wydaj polecenie <em>sudo vgs</em>.
+      </p>
+      <h3 id="exec6.5">Ćwiczenie 5: Zmiana praw własności do plików i katalogów</h3>
+      <p>
+        Na maszynie <em>server1</em>, utwórz w katalogu <em>/tmp</em> plik
+        <em>f6</em> oraz katalog <em>d6</em>. Utwórz użytkownika <em>user90</em>.
+        Za pomocą polecenia <em>chown</em> ustaw właściciela pliku <em>f6</em>
+        na <em>user90</em>. Za pomocą polecenia <em>chgrp</em> ustaw grupę na 
+        <em>dbagrp</em>. Utwórz grupę <em>g1</em>,
+        następnie ustaw rekrencyjnie prawa własności dla katalogu <em>d6</em>,
+        na <em>user90</em>:<em>g1</em>.
+      </p>
+      <h2 id="ch6summary">Podsumowanie</h2>
+      <p>
+        Tym rodziałem zakończyliśmy zarządzanie użytkownikami. Zapoznaliśmy
+        się z narzędziami do ustalania zasad haseł w praktyce, poznaliśmy
+        narzędzia do zarządzania grupami oraz efektywne sposoby na bezpieczne
+        podnoszenie uprawnień za pomocą polecenia <em>sudo</em>. Na koniec 
+        odświerzyliśmy informacje na temat praw własności plików i katalogów.
+        W następnym rozdziale poznamy podstawy powłoki BASH.
+      </p>
+      <h1 id="7.bashshell">7. Powłoka BASH</h1>
+      <p>
+        Powłoka jest to program odpowiedzialny za możliwość wprowadzania 
+        poleceń
+        do systemu i ich interpretowanie. Powłoka jest domyślnym interfejsem
+        użytkownika w różnych wariantach systemów uniksopodobnych. To właśnie 
+        proces połoki jest uruchamiany po uruchomieniu okna terminala. 
+      </p>
+      <p>
+        Na przestrzeni lat wraz z kolenymi odłamami oryginalnego Uniksa
+        powstawało wiele powłok, każda z nich miała swoje wady i zalety.
+        Obecnie najpowszechniejszą wersją z nich jest <strong>BASH</strong>,
+        jej główną zaletą jest zebranie większości funkcjonalność różnych
+        powłok, poprawienie ich działa oraz dostosowanie do obecnych czasów.
+        Ten rodzaj powłoki również domyślnie jest instalowany w wielu
+        dystrybucjach Linuksa i Red Hat nie jest w tym temacie wyjątkiem.
+        W tym rodziale chciałbym omówić najważnejsze funkcje tej powłoki oraz
+        jej skrypty startowe, dzięki którym będziemy mogli dostować ją do
+        swoich potrzeb.
+      </p>
+      <h2 id="7.1.bashfeatures">7.1. Funkcje powłoki BASH</h2>
+      <p>
+        <em>BASH</em> w swojej kolekcji posiada masę funkcjonalności, których
+        próżno szukać w innych powłokach. Dla przykładu w nowszych
+        dystrybucjach, skrypt powłoki zastępują podstawowe narzędzia systemowe,
+        będące kiedyś pełnoprawnymi programami.
+      </p>
+      <h3 id="7.1.1.variables">7.1.1. Zmienne</h3>
+      <p>
+        Korzystając z powłoki możemy używać zmiennych, czyli opisanych miejsc
+        alokowanych w pamięci do przechowywania dowolnych wartości. Do
+        dyspozycji mamy dwa rodzaje zmiennych - zmienne <strong>lokalne</strong>
+        oraz zmienne <strong>środowiskowe</strong>.
+      </p>
+      <p>
+        Zmienne lokalne są dostępne tylko w obecnej sesji powłoki.
+        Tego typu zmienne nie będą widoczne dla
+        uruchomionych w tej sesji skryptów czy programów, gdyż są
+        przechowywane tylko i wyłącznie w obszarze pamięci należącym do tego
+        procesu powłoki. Taka zmienną możemy zdefiniować podając w wierszu
+        polecenia jej nazwę, następnie znak równości oraz wartość. Warto dodać
+        aby nie było między tymi elementami żadnej spacji. Poniższy przykład 
+        na pewno to rozświetli.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ zmienna=2137
+</pre>
+      <p>
+        Po wykonaniu takiego polecenia, powłoka utworzy zmienną i nada jej
+        podaną wartość, po czym zwróci znak zachęty.
+      </p>
+      <p>
+        Do takiej zmiennej możemy odwołać się podczas pisania polecenia
+        wystarczy poprzedzić nazwę znakiem dolara (<strong>$</strong>).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ echo $zmienna
+2137
+</pre>
+      <p>
+        Polecenie <code class="code-inline">echo</code> wypisuje wszystko co
+        do zostanie mu podane jako argument na standardowe wyjście (o tym
+        będzie w dalszej częsci materiału). Jak widzimy polecenie wypisało
+        zawartość zmiennej.
+      </p>
+      <p>
+        Innymi zmiennymi są zmienne środowiskowe przechowują one
+        różnego rodzaju wartość, które mogą wpływać na działanie programów.
+        Każdy program uruchomiony na Linuksie dostaje od procesu nadrzędnego 
+        obszar
+        pamięci zmiennych środowiskowych, które może wykorzystywać do sobie
+        tylko znanych celów. Definicja
+        takich zmiennych, różni się tym, że poprzedza się ją
+        poleceniem <strong>export</strong>, którego zadaniem jest przeniesienie
+        zmiennej lokalnej do pamięci zmiennych środowiskowych.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ export ZMIENNA=2137
+</pre>
+      <p>
+        Nazwy zmiennych środowiskowych zapisujemy za pomocą wielkich liter aby
+        odróżnić je od zmiennych lokalnych. Dostęp do takiej zmiennej możemy
+        uzyskać, kiedy uruchomimy jakiś program w tej powłoce, aby otrzymał
+        on od powłoki, w której został uruchomiony (procesu nadrzędnego) obszar 
+        zmiennych środowiskowych. Najlepiej by było aby takim programem była 
+        kolejna powłoka (podpowłoka).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ bash
+[user@server1 ~]$ echo $ZMIENNA
+2137
+</pre>
+      <p>
+        Po uruchomieniu podpowłoki wydałem polecenie, które wyświetliło mi
+        zawartość zmiennej, którą zdefiniowałem jako zmienną środowiskową w
+        poprzednim przykładzie.
+      </p>
+      <p>
+        Wszystkie zmienne środowiskowe w systemie możemy wypisać za pomocą
+        polecenia <strong>env</strong> lub polecenia <strong>printenv</strong>.
+        Oto fragment listingu zmiennych środowiskowych z mojego systemu:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ env
+...
+TERM=xterm-256color
+LESSOPEN=||/usr/bin/lesspipe.sh %s
+USER=user
+SELINUX_USE_CURRENT_RANGE=
+ZMIENNA=2137
+SHLVL=2
+XDG_SESSION_ID=7
+XDG_RUNTIME_DIR=/run/user/1000
+SSH_CLIENT=192.168.122.1 34956 22
+which_declare=declare -f
+...
+</pre>
+      <p>
+        Natomiast za pomocą polecenia <strong>set</strong> możemy wypisać
+        wszystkie zmienne dostępne w systemie, łącznie z lokalnymi zmiennymi
+        powłoki.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ set
+...
+SHLVL=1
+SSH_TTY=/dev/pts/0
+TERM=xterm-256color
+UID=1000
+USER=user
+XDG_DATA_DIRS=/home/user/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
+XDG_RUNTIME_DIR=/run/user/1000
+XDG_SESSION_CLASS=user
+XDG_SESSION_ID=7
+XDG_SESSION_TYPE=tty
+ZMIENNA=2137
+_=set
+_backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))'
+colors=/home/user/.dircolors
+new_dirs=/home/user/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share
+which_opt=-f
+which_shell=bash
+zmienna=2137
+zmienna1=2137
+...
+</pre>
+      <p>
+        Zmienne, które nie są już potrzebne możemy usunąć za pomocą polecenia
+        <strong>unset</strong>. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ set | grep 'zmienna1'
+zmienna1=2137
+[user@server1 ~]$ unset zmienna1
+[user@server1 ~]$ echo $zmienna1
+
+</pre>
+      <p>
+        Przy odwołaniu się do zmiennej, polecenie <em>echo</em> zwróciło
+        pusty wiersz.
+      </p>
+      <p>
+        Manipulując zmiennymi w powłoce może zmienić znak zachęty, ponieważ 
+        jego definicja jest przechowywana w zmiennej <strong>PS1</strong>:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ echo $PS1
+[\u@\h \W]\$
+</pre>
+      <p>
+        Te poprzedzone lewym ukośnikiem <strong>\</strong> litery są kolejnymi
+        elementami znaku zachęty. Opis tych elementów znajduje się na 
+        stronie podręcznika polecenia/powłoki <em>BASH</em> w rozdziale
+        <em>PROMPTING</em>.
+      </p>
+      <h3 id="7.1.2.commandsubstitution">7.1.2. Podstawienie polecenia</h3>
+      <p>
+        Często wykorzystywaną funkcją wraz z zmiennymi jest
+        <strong>podstawienie polecenia</strong>. Polega ono na uruchomieniu,
+        przez podpowłokę polecenia ujętego albo w okrągły nawias poprzedzony
+        znakiem dolara (<strong>$()</strong>) albo w ukośny cudzysłów
+        (<strong>``</strong>). Informacja zwracana przez polecenie trafia albo
+        do zmiennej albo bezpośrednio jako argument polecenia.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ export KERNEL_VERSION=$(uname -r)
+[user@server1 ~]$ echo $KERNEL_VERSION 
+5.14.0-70.13.1.el9_0.x86_64
+</pre>
+      <p>
+        Poniżej znajduje się przykład użycia podstawienia polecenia w innym
+        poleceniu:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo find / -name *`uname -r` -print 2&gt; /dev/null
+/boot/vmlinuz-5.14.0-70.13.1.el9_0.x86_64
+/boot/System.map-5.14.0-70.13.1.el9_0.x86_64
+/boot/config-5.14.0-70.13.1.el9_0.x86_64
+/usr/lib/firmware/5.14.0-70.13.1.el9_0.x86_64
+/usr/lib/modules/5.14.0-70.13.1.el9_0.x86_64
+/usr/share/doc/kernel-keys/5.14.0-70.13.1.el9_0.x86_64
+</pre>
+      <p>
+        Gwiazdka (<strong>*</strong>) w tym przypadku oraz 
+        <code class="code-inline">2&gt;</code>, również są elementami połoki, 
+        które sobie omówimy.
+      </p>
+      <h3 id="7.1.3.streamredirections">7.1.3. Przekierowanie strumieni</h3>
+      <p>
+        Na Uniksach mamy doczynienia z trzema rodzajami strumieni danych,
+        owe strumienie łączą ze sobą np. urządzenia z programami, dlatego
+        pisząc na klawiaturze możemy wprowadzać tekst do programu, albo 
+        programy
+        mogą wypisać wynik swojego działnia do okna terminala. Pierszy strumień
+        to strumień standardowegp wejścia źródłem jego danych jest najczęściej 
+        klawiatura.
+        Jego identyfikatorem jest <strong>0</strong> (programy używają
+        identyfikatorów do korzystania ze strumieni, my też będziemy podłaczając
+        jeden strumień do drugiego). Drugi strumień danych, to strumień
+        standarowego wyjścia źródłem jego danych jest najczęściej program 
+        (jądro podczas
+        uruchamiania programu przekazuje mu kopie strumieni), jego
+        identyfikatorem jest <strong>1</strong>, a podłączony jest on do
+        terminala. Ostatnim strumieniem jest strumień błędów jego źródłem 
+        danych są komunikaty diagnostyczne programów, jest on najczęciej
+        podłączony razem ze strumieniem wyjścia do terminala. Identyfikatorem 
+        strumienia błędów jest <strong>2</strong>.
+      </p>
+      <p>
+        Przekierowania strumienia standardowego wyjścia dokonujemy w wierszu 
+        polecenia poprzez 
+        podanie znaku większości (<strong>&gt;</strong>) a następnie podajemy
+        miejse docelowe na dane. Na przykład wynik listowania katalogu
+        <em>/etc</em> możemy umieścić w pliku.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /etc &gt; ls.out
+[user@server1 ~]$ head -5 ls.out 
+total 1320
+drwxr-xr-x.  3 root root        28 Jun 26 13:50 accountsservice
+-rw-r--r--.  1 root root        16 Jun 26 14:01 adjtime
+-rw-r--r--.  1 root root      1529 Jun 23  2020 aliases
+drwxr-xr-x.  3 root root        65 Jun 26 13:54 alsa
+</pre>
+      <p>
+        Użycie pojedynczego znaku większości przekieruje strumień w tym
+        przypadku do pliku oraz nadpisze informacje zawarte w nim. Jeśli plik
+        nie istnieje to zostanie on utworzony.
+      </p>
+      <p>
+        Nadpisywanie danych za pomocą przekierowania strumieni nazywane jest
+        <em>clobberingiem</em>. Możemy zablokować tę funkcję za pomocą
+        polecenia <code class="code-inline">set -o noclobber</code>, wówczas
+        gdy plik będzie istnieć pokaże nam się taki komunikat jak na poniższym
+        przykładzie.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /etc &gt; ls.out
+-bash: ls.out: cannot overwrite existing file
+</pre>
+      <p>
+        Funkcję można włączyć z powrotem za pomocą polecenia
+        <code class="code-inline">set +o noclobber</code>.
+      </p>
+      <p>
+        Chcąc dopisać do zawartości pliku, zawartość strumienia możemy użyć
+        podwójnego znaku większości (<strong>>></strong>). Na przykład:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /var &gt;&gt; ls.out
+[user@server1 ~]$ cat ls.out
+total 4
+drwxr-xr-x. 2 user4000 g1         6 Jun 26 16:06 d6
+srwxrwxrwx. 1 gdm      gdm        0 Jun 30 13:59 dbus-aIxoyUxXnM
+srwxrwxrwx. 1 gdm      gdm        0 Jun 30 09:38 dbus-JRmt27fCi0
+drwxr-xr-x. 2 user200  dba        6 Jun 26 15:33 dir10
+-rw-r--r--. 1 user4000 dba        0 Jun 26 16:06 f6
+-rw-r--r--. 1 user200  user100    0 Jun 26 15:33 file10
+-rw-r--r--. 1 user     user    2400 Jun 30 14:57 ioerror
+...
+total 16
+drwxr-xr-x.  2 root root   19 Jun 26 13:54 account
+drwxr-xr-x.  2 root root    6 Aug 10  2021 adm
+drwxr-xr-x. 18 root root 4096 Jun 26 14:12 cache
+drwxr-xr-x.  2 root root    6 Mar  7 04:37 crash
+drwxr-xr-x.  3 root root   18 Jun 26 13:50 db
+drwxr-xr-x.  2 root root    6 Aug 10  2021 empty
+...
+</pre>
+      <p>
+        Z racji tego, iż znak większości służy do przekierowania jedynie 
+        wyjścia
+        to aby przekierować strumień błedów, należy podać przez znakiem jego
+        identyfikator. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /dvd 2&gt; err.out
+[user@server1 ~]$ cat err.out 
+ls: cannot access '/dvd': No such file or directory
+</pre>
+      <p>
+        Czasami może się zdarzyć, iż będzie potrzeba przekierowania obu tych
+        strumieni, wówczas trzeba skorzystać z podłączenia jednego strumienia
+        do drugiego.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /tmp /sdir &gt; ls2.out 2&gt;&amp;1
+[user@server1 ~]$ cat ls2.out 
+ls: cannot access '/sdir': No such file or directory
+/tmp:
+total 4
+drwxr-xr-x. 2 user4000 g1         6 Jun 26 16:06 d6
+srwxrwxrwx. 1 gdm      gdm        0 Jun 30 13:59 dbus-aIxoyUxXnM
+srwxrwxrwx. 1 gdm      gdm        0 Jun 30 09:38 dbus-JRmt27fCi0
+drwxr-xr-x. 2 user200  dba        6 Jun 26 15:33 dir10
+-rw-r--r--. 1 user4000 dba        0 Jun 26 16:06 f6
+-rw-r--r--. 1 user200  user100    0 Jun 26 15:33 file10
+-rw-r--r--. 1 user     user    2400 Jun 30 14:57 ioerror
+...
+</pre>
+      <p>
+        To polecenie można zapisać również w inny sposób. Na przykład:
+        <code class="code-inline">ls -l /tmp /sdir &amp;&gt; ls2.out</code>.
+        Obie formy są poprawne i obie robią to samo, która będzie dla nas
+        lepsza musimy zdecydować sami.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Jednym z zadań egzaminacyjnych może być wykonanie polecenia z 
+        przekierowaniem wyjścia lub/i strumienia błędów do pliku.
+      </p>
+      <p>
+        Kolejnym rodzajem przekierowania jest przekierowanie wejścia, jednak 
+        jest ono dość rzadko stosowane. Do tego rodzaju przekierowania 
+        stosuje się znak mniejszości (<strong>&lt;</strong>). Jednym z
+        przykładów jest polecenie użycie polecenia <em>tar</em>, jednak nie ma
+        ono sensu, ponieważ istnieje opcja <em>-f</em>, która pozwala na
+        podanie ścieżki do pliku.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ tar -x -C /tmp &lt; etc.tar 
+[user@server1 ~]$ ls -l /tmp
+total 16
+drwxr-xr-x.   2 user4000 g1         6 Jun 26 16:06 d6
+srwxrwxrwx.   1 gdm      gdm        0 Jun 30 13:59 dbus-aIxoyUxXnM
+srwxrwxrwx.   1 gdm      gdm        0 Jun 30 09:38 dbus-JRmt27fCi0
+drwxr-xr-x.   2 user200  dba        6 Jun 26 15:33 dir10
+drwxr-xr-x. 132 user     user    8192 Jun 30 09:38 etc
+...
+</pre>
+      <p>
+        Ostatni rodzaj przekierowania, to <strong>potok</strong>, o potoku
+        jeszcze będzie w tym rozdziale.
+      </p>
+      <h3 id="7.1.4.history">7.1.4. Historia poleceń</h3>
+      <p>
+        Dość istotną funkcją powłoki <em>BASH</em> jest historia poleceń.
+        Pozwala ona zaoszczędzić pisania w szczególności długich poleceń czy
+        poleceń potokowych (ang. <em>pipelines</em>). Posiada ona funkcję
+        wyszukiwania oraz swobodny dostęp do poleceń umieszczonych w historii.
+      </p>
+      <p>
+        Aby wyświetlić polecenia z historii, należy użyć polecenia
+        <strong>history</strong>, wyświetli ono listę poleceń z numerami na
+        początku, każde polecenie to jedna linia. Numer porządkowy pomoże nam
+        się odwołać do polecenia podczas jego wywoływania, ponieważ nie
+        potrzeba szukać polecenia czy przebierać ich wszystkich za pomocą
+        niżej opisanych klawiszy. Wystarczy znać jego numer. Poniżej znajduje
+        się fragment listy historii poleceń z mojego systemu:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ history
+    1  id
+    2  groups 
+    3  su
+    4  su -
+    5  cat /etc/sudoers
+    6  su - root
+    7  sudo cat /etc/sudoers
+    8  su - root
+    9  sudo cat /etc/sudoers
+   10  su - root
+   11  sudo yum update
+   12  su - root
+   13  touch file1
+...
+</pre>
+      <p>
+        Wyświetlenie listy poleceń w historii możemy ograniczyć podajac w
+        jako argument ilość wyświetlanych linii. Polecenie wyświetli wówczas
+        polecenia od końca listy (ostatnio dodane).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ history 10
+  266  rm etc.tar 
+  267  sudo tar -cvf etc.tar /etc
+  268  tar -x -C /tmp &lt; etc.tar 
+  269  ls -al /tmp
+  270  ls -l /tmp
+  271  history
+  272  touch file1
+  273  sudo poweroff
+  274  touch file1
+  275  history 10
+</pre>
+      <p>
+        Za pomocą opcji <em>-d</em> możemy usunać wybrane polecenie z historii.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ history 10
+  266  rm etc.tar 
+  267  sudo tar -cvf etc.tar /etc
+  268  tar -x -C /tmp &lt; etc.tar 
+  269  ls -al /tmp
+  270  ls -l /tmp
+  271  history
+  272  touch file1
+  273  sudo poweroff
+  274  touch file1
+  275  history 10
+[user@server1 ~]$ history -d 271
+[user@server1 ~]$ history 10
+  267  sudo tar -cvf etc.tar /etc
+  268  tar -x -C /tmp &lt; etc.tar 
+  269  ls -al /tmp
+  270  ls -l /tmp
+  271  touch file1
+  272  sudo poweroff
+  273  touch file1
+  274  history 10
+  275  history -d 271
+  276  history 10
+</pre>
+      <p>
+        Na informacji zwracanej przez wcześniejsze wywołanie polecenia
+        <code class="code-inline">history 10</code> w linii 
+        <code class="code-inline">271</code> widnieje polecenie
+        <code class="code-inline">history</code>, natomiast na drugim wywołaniu
+        po usunięciu tego polecenia pod tym numerem widnieje już inne.
+      </p>
+      <p>
+        Wśród poleceń w historii możemy poruszać się za pomocą strzełek w górę 
+        oraz w dół lub kombinacji klawiszy (co jest bardziej zalecene)
+        <em>Ctrl+p</em> (poprzednie polecenie) oraz <em>Ctrl+n</em> (następne
+         polecenie). Możemy je również wyszukiwać po
+        przez wciśnięcie kombinacji klawiszy <em>Ctrl+r</em> i podanie 
+        fragmentu polecenia. Czasmi wyszukiwanie może nie przynieść skutku,
+        wówczas należy nacisnać <em>Ctrl+c</em> i spróbować ponownie.
+      </p>
+      <p>
+        Do poleceń w historii odnosimy się wprowadzając w wierszu polecenia
+        wykrzyknik (<strong>!</strong>) następnie możemy podać numer z listy.
+        Dla przykładu użyje polecenia numer <code class="code-inline">13</code>
+        z fragmentu listy z pierwszego przykładu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ !13
+touch file1
+touch: cannot touch 'file1': Permission denied
+</pre>
+      <p>
+        Możemy również podać litery rozpoczynające polecenie na przykład:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ !tou
+touch file1
+touch: cannot touch 'file1': Permission denied
+</pre>
+      <p>
+       Ta instrukcja podstawi najczęstsze wystąpienie polecenia 
+       rozpoczynającego się o tych liter. Podobną metodą jest podanie fragmentu
+       polecenia zawierającego jakiś ciąg znaków, na przykład:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ !?file?
+touch file1
+touch: cannot touch 'file1': Permission denied
+</pre>
+      <p>
+        To polecenie podstawi najczęściej występujące polecenie z historii
+        zawierające ciąg znaków <code class="code-inline">file</code>.
+      </p>
+      <p>
+        Za pomocą polecenia wykrzyknika możemy odwołać się do ostatniego
+        polecenia podając drugi wykrzyknik. Tą metodę możemy zastosować
+        w przypadku gdy zapomnimy o <em>sudo</em> przy wydawaniu poleceń
+        administracyjnych.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ cat /var/log/secure
+cat: /var/log/secure: Permission denied
+[user@server1 ~]$ sudo !!
+sudo cat /var/log/secure
+[sudo] password for user: 
+Jun 26 14:12:08 server1 polkitd[725]: Loading rules from directory /etc/polkit-1/rules.d
+Jun 26 14:12:08 server1 polkitd[725]: Loading rules from directory /usr/share/polkit-1/rules.d
+Jun 26 14:12:08 server1 polkitd[725]: Finished loading, compiling and executing 12 rules
+Jun 26 14:12:08 server1 polkitd[725]: Acquired the name org.freedesktop.PolicyKit1 on the system bus
+...
+</pre>
+      <p>
+        Historię możemy wyłączyć używając polecenia
+        <code class="code-inline">set -o history</code>. Włączenie historii
+        wymaga polecenia <code class="code-inline">set +o history</code>.
+        Historia kontrolowana jest za pomocą trzech zmiennych
+        <em>HISTSIZE</em>, której wartość jest równoznaczna z ze zmienną
+        <em>HISTFILESIZE</em> oraz <em>HISTCONTROL</em>.  Ich opisy znajdują
+        się na stronie podręcznika polecenia <em>bash</em>. Natomiast ścieżka
+        do pliku zawierającego historie z poprzednich sesji znajduje się w
+        zmiennej <em>HISTFILE</em>.
+      </p>
+      <h3 id="7.1.5.editingcli">7.1.5. Edycja wiersza polecenia</h3>
+      <p>
+        Za pomocą strzałek w lewo oraz w prawo, możemy przesuwać kursor w 
+        wierszu polecenia, jednak istnieją znacznie bardziej efektywne
+        sposoby na edycje wpisanego polecenia.
+      </p> 
+      <ul>
+        <li><em>Ctrl+a</em> - przenosi kursor na początek wiersza.</li>
+        <li><em>Ctrl+e</em> - przenosi kursor na koniec wiersza.</li>
+        <li><em>Ctrl+f</em> - przenosi kursor o jeden znak w prawo.</li>
+        <li><em>Ctrl+b</em> - przenosi kursor o jeden znak w lewo.</li>
+        <li><em>Alt+f</em> - przenosi kursor o jedno słowo w prawo.</li>
+        <li><em>Alt+b</em> - przenosi kursor o jedno słowo w lewo.</li>
+        <li><em>Ctrl+u</em> - usuwa wszystko z linii polecenia.</li>
+      </ul>
+      <p>
+        Te skróty pozwalają na sprawniejsze poruszenie się w wierszu
+        polecenia.
+      </p>
+      <h3 id="7.1.6.commandcompletion">7.1.6. Uzupełnianie poleceń</h3>
+      <p>
+        Chcąc przyspieszyć pisanie poleceń możemy wykorzystać uzupełnianie
+        poleceń. W wierszu polecenia zapisujemy fragment polecenia lub ścieżki
+        następnie naciskamy klawisz <strong>Tab</strong>. Powłoka uzupełni
+        nasz zapis do wspólnej części z na przykład nazwami plików, katalogów
+        czy poleceń. Po następnym naciśnięciu tego klawisza, powłoka zwróci 
+        możliwe warianty pasujące do tego co zapisaliśmy.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ deb
+
+#Pierwsze naciśnięcie klawisza Tab
+[user@server1 ~]$ debug
+
+#Drugie naciśnięcie klawisza Tab
+[user@server1 ~]$ debug
+debugfs          debuginfod-find  
+[user@server1 ~]$ debug
+</pre>
+      <p>
+        Kiedy dopiszemy kilka liter z jednego z wariantów, polecenie dopełni
+        je pozostałymi lub zwróci zawężoną ilość możliwych do wyboru elementów.
+      </p>
+      <h3 id="7.1.7.tilde">7.1.7. Podstawienie tyldy</h3>
+      <p>
+        Tylda w powłoce oznacza jedno - katalog domowy użytkownika. Za jej
+        pomocą możemy w prosty sposób odwoływać się do elementów w katalogu
+        domowym użytkownika ale i nie tylko. Poniżej przedstawiłem trzy
+        zastosowania podstawienia tyldy.
+      </p>
+      <ul>
+        <li><strong>~/Dokumenty</strong> - odwołanie się do elementu 
+          znajdującego się w katalogu domowym użytkownika.</li>
+        <li><strong>~+</strong> - odwołanie się do obecnego katalogu roboczego
+          (wyświetla ścieżkę bezwzględną obecnego katalogu roboczego),
+          równoznaczne z podstawiemiem polecenia <em>pwd</em>.</li>
+        <li><strong>~-</strong> - odwołanie się do poprzedniego katalogu
+          roboczego, podstawienie również zwraca ścieżkę bezwzględną do 
+          katalogu,
+          w którym się znajdowaliśmy przed przejściem do obecnego.</li>
+      </ul>
+      <p>
+        Podstawienie tyldy może zaoszczędzić nam czas oraz zmieniejszyć ilość
+        pisania. Poniżej znajduje się kilka przykładów prezentujących powyższe
+        podstawienia.
+      </p>
+<pre class="code-block">
+[user@server1 logs]$ echo ~+
+/home/user/logs
+[user@server1 logs]$ echo ~
+/home/user
+[user@server1 logs]$ cd /etc
+[user@server1 etc]$ echo ~-
+/home/user/logs
+</pre>
+      <h3 id="7.1.8.alias">7.1.8. Aliasy</h3>
+      <p>
+        Alias to nazwa zastępcza, dzięki której możemy zastąpić długie
+        polecenia za pomocą pojedynczego wyrazu. Aliasy definiowane są
+        pomocą polecenia <strong>alias</strong>, jako argument przyjmuje on
+        definicję aliasów, czyli nazwę zastępnczą, znak równości oraz
+        polecenie w podwójnych apostrofach. Między tym elementami nie
+        powinno być spacji. Poniżej znajduje się definicja aliasów, który
+        szuka w katalogu domowym plików powyżej 1 GB a następnie zwraca ich
+        atrybutu. 
+      </p>
+<pre class="code-block">
+alias bigfiles="find ~ -size +1G -exec ls -lh {} \;"
+[user@server1 ~]$ bigfiles 
+-rw-r--r--. 1 user user 1.5G Jul  1 12:55 /home/user/test.img
+</pre>
+      <p>
+        Ważną rzeczą związna z aliasami jest fakt iż kiedy powłoka otrzymuje
+        polecenie do interpretacji to sprawdza na początku czy nie jest ono
+        aliasem i jeśli tak jest to wykonuje to co znajduje się pod nim. Aliasy
+        mogą mieć takie same nazwy jak programy czy inne polecenia w systemie,
+        dlatego też mogą je przesłaniać. Tak jest w przypadku superużytkownika
+        z poleceniami <em>cp</em>, <em>mv</em> czy <em>rm</em>. Poniższy
+        przykład dobrze to obrazuje.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ alias rm="rm -i"
+[user@server1 ~]$ rm test.img
+rm: remove regular file 'test.img'? n
+</pre>
+      <p>
+        Aby powłoka nie brała nazwy polecenia przy poszukiwaniu aliasów, należy
+        poprzedzić ją znakiem lewego ukośnika czy <em>backslashu</em>
+        (<strong>\</strong>).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rm logs
+rm: remove symbolic link 'logs'? n
+[user@server1 ~]$ \rm logs
+</pre>
+      <p>
+        Usuwaniu aliasów służy polecenie <strong>unalias</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ unalias bigfiles
+[user@server1 ~]$ bigfiles
+bash: bigfiles: command not found...
+</pre>
+      <h3 id="7.1.9.metacharacters">7.1.9. Metaznaki oraz nazwy wieloznaczne</h3>
+      <p>
+        Chcąc odwołać się do wielu elementów posiadających wspólne fragmenty
+        nazw możemy użyć tzw. <strong>metaznaków</strong> lub
+        <em>nazw wieloznacznych</em>, służą one podstawianiu znaków pod używane
+        wraz z nim nazwy. Załóżmy że mamy dwa rodzaje archiwów w katalogu jedne
+        rozpoczynają się od nazwy <em>backup</em> a drugie od nazwy <em>d</em>
+        kazde archiwum zawiera w nazwie po podanej części myślnik oraz datę.
+        Chcemy wyświetlić atrybuty archiwów z nazwą zaczynającą się od <em>d</em>
+        w tym celu możemy użyć nazwy wieloznacznej. Podstawiając za nazwą
+        gwiazdkę.
+      </p>
+<pre class="code-block">
+[js@fujitsu windows]$ ls -l D*
+-rwxr--r-- 1 windows windows 11718211581 05-01 21:09 D-2022-05-01.7z
+-rwxr--r-- 1 windows windows 11718211581 05-02 21:08 D-2022-05-02.7z
+-rwxr--r-- 1 windows windows 11718211581 05-03 21:08 D-2022-05-03.7z
+-rwxr--r-- 1 windows windows 11718269229 05-04 21:15 D-2022-05-04.7z
+-rwxr--r-- 1 windows windows 11718658739 05-05 21:14 D-2022-05-05.7z
+-rwxr--r-- 1 windows windows 11718634289 05-06 21:14 D-2022-05-06.7z
+-rwxr--r-- 1 windows windows 11718634289 05-07 21:08 D-2022-05-07.7z
+-rwxr--r-- 1 windows windows 11718634289 05-08 21:08 D-2022-05-08.7z
+-rwxr--r-- 1 windows windows 11718633900 05-09 21:15 D-2022-05-09.7z
+...
+</pre>
+      <p>
+        Do stosowania nazw wieloznacznych, możemy stosować wiele znaków ich
+        opis znajduje się na liście poniżej.
+      </p>
+      <ul>
+        <li><strong>*</strong> - gwiazdka, ten symbol podstawia dowolną ilość
+          dowolnych znaków. Mogą one w ogóle nie występować.
+<pre class="code-block">
+[user@server1 ~]$ ls -l D*
+-rw-r--r--. 1 user user 0 Jul  1 13:39 D
+</pre>
+        </li>
+        <li><strong>?</strong> - znak zapytania, pojedynczy dowolny znak.
+<pre class="code-block">
+[user@server1 ~]$ ls -l ??.*
+-rw-r--r--. 1 user user 2732 Jun 30 19:14 ls.out
+</pre>
+        </li>
+        <li><strong>[]</strong> - nawias kwadratowy, zakresy lub lista znaków.
+          Lista znaków:
+<pre class="code-block">
+[user@server1 ~]$ ls -l /dev/*[ty]
+crw-------. 1 root root 10, 126 Jul  1 11:00 /dev/cpu_dma_latency
+crw-------. 1 root root 10, 228 Jul  1 11:00 /dev/hpet
+crw-r-----. 1 root kmem  1,   4 Jul  1 11:00 /dev/port
+crw-------. 1 root root 10, 231 Jul  1 11:00 /dev/snapshot
+lrwxrwxrwx. 1 root root      15 Jul  1 11:00 /dev/stdout -&gt; /proc/self/fd/1
+crw-rw-rw-. 1 root tty   5,   0 Jul  1 13:03 /dev/tty
+</pre>
+          Zakres:
+<pre class="code-block">
+[user@server1 ~]$ sudo ls -ld /etc/systemd/system/[m-o]*
+drwxr-xr-x. 2 root root 4096 Jun 26 13:54 /etc/systemd/system/multi-user.target.wants
+drwxr-xr-x. 2 root root   48 Jun 26 13:50 /etc/systemd/system/network-online.target.wants
+</pre>
+          Zakresy oraz listy znaków mogą zostać zanegowane za pomocą
+          wykrzyknika.
+<pre class="code-block">
+[user@server1 ~]$ sudo ls -ld /etc/systemd/system/[!m-o]*
+[sudo] password for user: 
+drwxr-xr-x. 2 root root   65 Jun 26 13:54  /etc/systemd/system/basic.target.wants
+drwxr-xr-x. 2 root root   31 Jun 26 13:50  /etc/systemd/system/bluetooth.target.wants
+...
+</pre>
+          Powyższe przypasowane elementy nie zawierają liter od m-o na początku
+          swoich nazw.
+        </li> 
+      </ul>
+      <p>
+        Stosując nazwy wieloznaczne możemy automatycznie wykonywać te same
+        polecenia na elementach posiadających wspólne nazwy.
+      </p>
+      <h3 id="7.1.10.pipes">7.1.10. Potoki i polecenia potokowe</h3>
+      <p>
+        Omawiając przkierowania strumieni wspomniałem o potokach. Potok to 
+        przekierowanie wyjścia jednego polecenia na wyjście drugiego za pomocą
+        znaku pionowej kreski (<strong>|</strong>).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /etc | head
+total 1320
+drwxr-xr-x.  3 root root        28 Jun 26 13:50 accountsservice
+-rw-r--r--.  1 root root        16 Jun 26 14:01 adjtime
+-rw-r--r--.  1 root root      1529 Jun 23  2020 aliases
+drwxr-xr-x.  3 root root        65 Jun 26 13:54 alsa
+drwxr-xr-x.  2 root root      4096 Jun 26 13:58 alternatives
+-rw-r--r--.  1 root root       541 Aug  9  2021 anacrontab
+-rw-r--r--.  1 root root       769 Aug 28  2021 appstream.conf
+-rw-r--r--.  1 root root        55 Feb 11 10:53 asound.conf
+-rw-r--r--.  1 root root         1 Aug  9  2021 at.deny
+</pre>
+      <p>
+        Za pomocą potoków możemy łączyć polecenia w długie łańcuchy
+        przekazując strumień wyjściowy wychodzący z innych poleceń na wejście
+        kolejnych. Polecenia tego typu nazwyane są 
+        <strong>poleceniami potokowymi</strong>. Poniżej znajduej się jedno
+        z nich.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /etc | sed -n '15p' | awk '{printf $1}'
+</pre>
+      <p>
+        Powyższe polecenie wyświetli pierwszą kolumnę atrybutów pliku z
+        15 lini zawartości katalogu <em>/etc</em>. Polecenia 
+        <code class="code-inline">sed</code> oraz 
+        <code class="code-inline">awk</code> znajdują się poza zakresem
+        merytorycznym tego materiału.
+      </p>
+      <h3 id="7.1.11.quoting">7.1.11. Cytowanie</h3>
+      <p>
+        Za tą enigmatyczną nazwą stoją mechanizmy, których możemy użyć, aby
+        znaki specjalne w powłoce, by traktowane jako zwykłe znaki bez
+        żadnego specjalnego znaczenia. Pierwszym z nich jest użycie 
+        lewego ukośnika (<strong>\</strong>). Jeśli na przykład stworzyślimy
+        plik on nazwie <em>*</em>. To jeśli spróbujemy go usunąć bez żadnego
+        cytowania usuniemy wszystko co znajduje się w katalogu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rm \*
+rm: remove regular empty file '*'? y
+[user@server1 ~]$ ls
+D  err.out  etc.tar  file1  ls2.out  ls.out  test.img
+</pre>
+      <p>
+        Jak widać na załączonym przykładzie moim plikom nic się nie stało.
+        Używanie lewego ukośnika może być uciążliwe jeśli do zacytowania mamy
+        więcej niż jeden znak. Wówczas możemy się posłużyć pojedynczym
+        apostrofem (<strong>''</strong>). Wszystko co zostanie umieszczone
+        miedzy nimi, będzie traktowane dosłownie. Najprostszym przykładem
+        użycia jest odwołanie się do zmiennej.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ zmienna='abc'
+[user@server1 ~]$ echo $zmienna
+abc
+[user@server1 ~]$ echo '$zmienna'
+$zmienna
+</pre>
+      <p>
+        Gdy odwołaliśmy się do zmiennej w pojedynczych cudzysłowach, znak
+        dolara został potraktowany dosłownie, więc polecenie
+        <code class="code-inline">echo</code> wypisało ciąg znaków
+        <code class="code-inline">$zmienna</code>. Ostatnim rodzajem cytowania
+        podobnym do pojedynczego apostrofu jest podwójny apostrof. Zauważalną
+        różnicą jest to, iż podwójny apostrof pozwala na użycie specjalnego
+        znaczenia takich znaków jak: lewy ukośnik (<strong>\</strong>),
+        znak dolara (<strong>$</strong>) oraz pojedynczy apostrof
+        (<strong>''</strong>), dzięki czemu wewnątrz literałów prezentowanych
+        za pomocą podwójnych apostrofów możemy uzyskać wartości zmiennych. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ echo "Pierwszym literami alfabetu są litery $zmienna"
+Pierwszym literami alfabetu są litery abc
+</pre>
+      <h3 id="7.1.12.regex">7.1.12. Wyrażenia regularne</h3>
+      <p>
+        Wyrażenia regularne służą wyszukiwaniu wzorców w tekście. Wzorce
+        składają się z ze znaków specjalnych oraz innych zwykłych znaków 
+        mających przybliżyć odnalezienie wzorca. Wyrażenia regularne w powłoce
+        możemy obsługiwać za pomocą polecenia <strong>grep</strong>. W tym
+        materiale również używaliśmy wyrażeń regularnych przy wyświetlaniu
+        zawartości pliku <em>/etc/login.defs</em>
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep -v -e '^#' -e '^$' /etc/login.defs 
+MAIL_DIR       /var/spool/mail
+UMASK          022
+HOME_MODE      0700
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_WARN_AGE  7
+...
+</pre>
+      <p>
+        Na powyższym przykładzie widzimy składnie polecenia, źródłem danych
+        nie musi być wyłącznie plik, równie dobrze mogą one pochodzić z
+        przekierowania. Na przykład z potoku.
+        Najpierw jednak zajmiemy się czymś prostszym, a do tego poziomu 
+        dojdziemy pod koniec. Najprostszym wyrażeniem może być zwykły
+        ciąg znaków.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep 'pass' /etc/login.defs
+# passwd command) should therefore be configured elsewhere. Refer to
+#      PASS_MAX_DAYS   Maximum number of days a password may be used.
+#      PASS_MIN_DAYS   Minimum number of days allowed between password changes.
+#      PASS_MIN_LEN    Minimum acceptable password length.
+#      PASS_WARN_AGE   Number of days warning given before a password expires.
+</pre>
+      <p>
+        Jak możemy zauważyć polecenie zwróciło wszystkie linie zawierające
+        wyrażenie jakie podaliśmy przed ścieżką do pliku. Podane wyrażenie
+        zapisaliśmy za pomocą małych liter i takie też zostało przypasowane
+        jeśli chcemy, aby nie była rozrózniana wielkość liter należy użyć
+        opcji <em>-i</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep -i 'pass' /etc/login.defs
+# passwd command) should therefore be configured elsewhere. Refer to
+# Password aging controls:
+#      PASS_MAX_DAYS   Maximum number of days a password may be used.
+#      PASS_MIN_DAYS   Minimum number of days allowed between password changes.
+#      PASS_MIN_LEN    Minimum acceptable password length.
+#      PASS_WARN_AGE   Number of days warning given before a password expires.
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_WARN_AGE  7
+</pre>
+      <p>
+        Poniżej umieściłem listę znaków wykorzystywanych do tworzenie wyrażeń
+        regularnych wraz z opisem. 
+      </p>
+      <ul>
+        <li><strong>.</strong> - pojedynczy dowolny znak,</li>
+        <li><strong>*</strong> - przypasowanie wzorca min. 0 razy lub więcej 
+          razy.</li>
+        <li><strong>+</strong> - przypasowanie wzorca min. 1 raz lub więcej 
+          razy.</li>
+        <li><strong>^</strong> - metaznak oznaczający początek wiersza. 
+          Wzorzec rozpoczynający się od tego znaku znajduje się na początku 
+          wiersza.</li>
+        <li><strong>$</strong> - metaznak oznaczający koniec wiersza. Wzorzec
+          zakończony tym znakiem znajduje się na końcu wiersza.</li>
+        <li><strong>[]</strong> - metaznak ozanaczający zbiory oraz zakresu. 
+          Zakresy mogą być różne: litery <em>[a-z]</em>, wielkie litery 
+          <em>[A-Z]</em> czy cyfry <em>[0-9]</em>. Zakresy nie muszą być pełne,
+          mogą być np. od a do o - <em>[a-o]</em>.
+        <li><strong>[^...]</strong> - negacja zbioru, zamiast trzech kropek
+          wstawiamy znaki. Przypasowanie następuje wówczas, kiedy we wzorcu
+          nie znajdują się podane znaki.</li>
+      </ul>
+      <p>
+        Wiecęj znaków oraz informacji znajduje się na stronie podręcznika
+        polecenia <em>grep</em> <code class="code-inline">man grep</code> oraz
+        na stronie podręcznika poświęconej wyrażeniom regularnym: 
+        <code class="code-inline">man 7 regex</code>. Teraz przedstawie kilka
+        dodatkowych opcji polecenia <em>grep</em>.
+      </p>
+      <ul>
+        <li><strong>-E</strong> - opcja umożliwia użycie rozszerzonych
+          wyrażeń regularnych, jedną z ciekawych opcji tego trybu jest użycie
+          <strong>alternatyw</strong>, czyli dodatkowych wzorców. Kiedy
+          nie będzie przypasowań do pierwszego wzorca <em>grep</em> sprawdzi
+          pozostałe. Alternatywy zapisuje się po <em>znaku potoku</em>, po
+          kresce pionowej <strong>|</strong>.
+<pre class="code-block">
+[user@server1 ~]$ cat colors 
+blue
+yellow
+green
+orange
+white
+black
+[user@server1 ~]$ grep -E 'red|white' colors 
+white
+</pre>
+        </li>
+        <li><strong>-v</strong> - odwraca przypasowanie wzorca, polecenie
+          wówczas wypisze wszystkie linie nie pasujące do wzorca.</li>
+        <li><strong>-o</strong> - zamiast całych wierszy, polecenie zwróci
+          tylko pasujący do wzorca fragment danych.</li>
+      </ul>
+      <p>
+        Wiecej opcji znajduje się na stronie podręcznika polecenia 
+        <em>grep</em>. Myślę, że teraz bez problemu jesteśmy w stanie 
+        zrozumieć przykład z początku tego podrozdziału.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Polecenie <em>grep</em> jest poręcznym narzędziem stosowany do 
+        wyłuskiwania informacji z pliku lub wyjścia polecenia. Wybrane
+        informacje mogą zostać przekierowane do pliku, pozostawiając dane
+        wejściowe nienaruszone.
+      </p>
+      <h3 id="7.1.13.jobmanaging">7.1.13. Zarządzanie zadaniami</h3>
+      <p>
+        Uruchamiając jakiś program w terminalu, możemy go odłączyć od niego i
+        przekazać jego wykonanie do tła. Wówczas taki program staje się
+        <strong>zadaniem</strong>. Program kontynuje swoje wykonanie w tle, 
+        ale jest kontrolowany przez terminal, w którym został uruchomiony.
+        W podpowłoce uruchomiłem plik <em>test</em>, który jest mały skryptem, 
+        który tak naprawdę nic nie robi.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ bash test
+
+</pre>
+      <p>
+        Użyłem kombinacji klawiszy <strong>Ctrl+z</strong>, aby zatrzymać 
+        wykonanie.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ bash test
+^Z
+[1]+  Stopped                 bash test
+</pre>
+      <p>
+        W ostatniej linii, na początku w nawiasie kwadratowym znajduje się
+        numer zadania. Za pomocą tego numeru możemy odwoływać się do zadania.
+        Teraz uruchomimy je w tle.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ bg %1
+[1]+ bash test &amp;
+</pre>
+      <p>
+        Do uruchomienia zadania w tle służy polecenie <strong>bg</strong>,
+        Do odwołania się do niego służą numery zadań poprzedzone
+        znakiem procentu (<strong>%</strong>). Możemy przywrócić działanie 
+        zadania na pierwszy plan przywołując je za pomocą polecenia
+        <strong>fg</strong>, metoda odwołania się do zadania jest taka sama 
+        jak w przypadku polecenia <em>bg</em>. Zanim przełaczym zadanie na
+        pierwszy plan, sprawdźmy jego status za pomocą polecenia
+        <strong>jobs</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ jobs
+[1]+  Running                 bash test &amp;
+</pre>
+      <p>
+        Teraz możemy przełączyć polecenie, aby finalnie je zamknąć za pomocą
+        klawiszy <strong>Ctrl + c</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ fg %1
+bash test
+^C
+</pre>
+      <p>
+        W ten sposób zarządza się zadaniami za pomocą mechanizmów powłoki.
+        Zadań przekazanych do tła systemu, może być wiele. Zadania nie zostaną
+        zakończone w momencie wylogowania się z systemu. Dlatego jeśli
+        wykonanie jakiego zadania, będzie wymagać czasu mozemy przenieść je
+        do tła. Przy planach użycia tła systemu warto wziąć po uwagę to, aby
+        przekierować wyjście programów/poleceń do jakiegoś pliku lub 
+        do urządzenia <em>/dev/null</em>, które ma jedno zadanie. Ignorować
+        wszelkie napływające do niego dane.
+      </p>
+      <p>
+        Chcąc uruchomić jakieś zadanie w tle odrazu, możemy pominąć tą całą
+        zabawę w jego zatrzymywanie i przekazywanie do tła. Możemy uruchomić je
+        od razu kończąc polecenie znakiem ampersendu (<strong>&amp;</strong>).
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ bash test &amp;
+[1] 14048
+[user@server1 ~]$ jobs
+[1]+  Running                 bash test &amp;
+</pre>
+      <h2 id="7.2.startupscripts">7.2. Pliki startowe powłoki</h2>
+      <p>
+        Plik startowe powłoki mają za zadanie wykonać kilka czynności 
+        konfiguracjynych,
+        aby użytkownik po jej uruchomieniu nie musiał tracić czasu
+        na ustawienie na przykład ścieżki wszukiwania poleceń, czyli zmiennej
+        <em>PATH</em>. Pliki te definiują również aliasy, które jak do tej
+        pory mogły się wydawać zwykłymi poleceniami. Pliki startowe powłoki
+        możemy podzielić na pliki globalne (mające zastosowanie dla całego
+        systemu) oraz pliki lokalne (mające zastosowanie tylko dla jednego
+        użytkownika).
+      </p>
+      <h3 id="7.2.1.systemwidefiles">7.2.1. Globalne pliki startowe powłoki</h3>
+      <p>
+        Do globalnych plików startowych możemy zaliczyć takie pliki jak
+        <em>/etc/bashrc</em>, <em>/etc/profile</em> oraz katalog
+        <em>/etc/profile.d</em>. Zmiany w tych plikach wpływają na konfigurację
+        powłoki wszystkich użytkowników w systemie. Poniżej znajduje się lista
+        ze skróconym opisem co dane pliki zawierają.
+      </p>
+      <ul>
+        <li><strong>/etc/bashrc</strong> - plik zawiera ustawienia właściwości
+          <em>PROMPT_COMMAND</em>, ustawienia historii, definicje znaku zachęty,
+          maski użytkownika oraz definicje zmiennej środowiskowej <em>SHELL</em>.
+        </li>
+        <li><strong>/etc/profile</strong> - plik zawiera definicje części
+          zmiennych środowiskowych, dopisuje pewne katalogi do zmiennej
+          <em>PATH</em>.</li>
+        <li><strong>/etc/profile.d</strong> - katalog zawiera skrypt
+          rozszerzające konfiguracje zawarte w powyższych plikach, te skrypt
+          są uruchamiane przez oba z nich.</li>
+      </ul>
+      <p>
+        Jeśli musimy umieścić dodatkowe konfiguracje w tych plikach najlepiej
+        umieścić je w skrypcie w katalogu <em>/etc/profile.d</em>.
+      </p>
+      <h3 id="7.2.2.usersfiles">7.2.2. Pliki startowe powłoki użytkownika</h3>
+      <p>
+        Każdy użytkownik posiada swoje pliki startowe powłoki
+        <strong>~/.bash_profile</strong> - odpowiadający globalnemu
+        <em>/etc/profile</em> oraz <strong>~/.bashrc</strong> - odpowiadający
+        globalnemu <em>/etc/bashrc</em>. Te pliki kopiowane są z katalogu 
+        szkieletowego - <em>/etc/skel</em> podczas tworzenia katalogu domowego
+        przy zakładaniu nowego użytkownika. Jeśli zajrzymy do zawartości tych
+        katalogów, to dowiemy się że:
+      </p>
+      <ul>
+        <li>W pliku <strong>~/.bash_profile</strong> umieszczamy dodatkowe
+          zmienne środowiskowe oraz dodatkowe programy lub skrypty startowe.
+        </li>
+        <li>W pliku <strong>~/.bashrc</strong> umieszczamy dodatkowe aliasy
+          oraz funkcje powłoki (funkcje powłoki wykraczają poza ten materiał).
+        </li>
+      </ul>
+      <p>
+        Pliki startowe powłoki są uruchamione określonej kolejności. W ramach
+        eksperymentu umieściłem, krótką informacje na końcu każdego z nich
+        a następnie wylogowałem się i zalogowałem ponownie. W poniższym bloku
+        kodu, znajduje się wynik tego eksperymentu:
+      </p>
+<pre class="code-block">
+xf0r3m@inspiron-3542:~$ ssh user@rhel9-vm1 
+user@rhel9-vm1's password: 
+Register this system with Red Hat Insights: insights-client --register
+Create an account or view all your systems at https://red.ht/insights-dashboard
+Last login: Sat Jul  2 15:29:33 2022 from 192.168.122.1
+Globalny /etc/bashrc
+Globalny /etc/profile
+Lokalny ~/.bashrc
+Lokalny ~/.bash_profile
+</pre>
+      <p>
+        Jak mogliśmy się domyślić na początku uruchiamiane są pliki globalne
+        a następnie lokalne.
+      </p>
+      <p>
+        Dodatkowym plikiem użytkownika o nieco innym znaczeniu jest
+        <em>~/.bash_logout</em>. Czynności zapisane w tym pliku są
+        wykonywane podczas wylogowywania użytkownika.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Jeśli jedno z zadań będzie dotyczyć dodania aliasu lub zmiennej
+        środowiskowej, to należy wiedzieć w jakich plikach je umieścić.
+      </p>
+      <h3 id="exec7.1">Ćwiczenie 1: Zmiana symbolu zachęty</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie <em>server1</em> dostosuj znak
+        zachęty aby wyglądał jak ten ujęty w podwójne apostrofy
+        "&lt;user@server1 in /etc &gt;:". <em>/etc</em> w tym przypadku jest
+        ścieżką do obecnego katalogu roboczego. Zapisz nową definicję znaku
+        zachęty do odpowiedniego pliku, wyloguje się i zaloguj ponownie 
+        następnie usuń tę definicję.
+      </p>
+      <h3 id="exec7.2">Ćwiczenie 2: Przkierowanie strumieni</h3>
+      <p>
+        Jako zwykły użytkownik na maszynie <em>server1</em> wyświetl zawartość
+        katalogów <em>/etc</em>, <em>/dvd</em> oraz <em>/var</em> przekieruj
+        standardowe wyjście oraz strumień błędów do pliku <em>/tmp/ioerror</em>
+        Sprawdź zawartość pliku.
+      </p>
+      <h2 id="ch7summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale zapoznaliśmy się z powłoką BASH. Nauczyliśmy się
+        korzystać z jej mechanizów, poznaliśmy również podstawy wyrażeń
+        regularnych. Na koniec dowiedzieliśmy się jak używać plików startowych
+        powłoki, aby dostosować ją do własnych potrzeb. W następnym rodziale
+        zajmiemy się procesami.
+      </p>
+      <h1 id="8.processandschedule">8. Zarządzanie procesami oraz harmonogram zadań</h1>
+      <p>
+        Zarządzanie procesami oraz obsługa harmonogramu zadań jest kolejnym z
+        zadań, które będziemy wykonywać jako administrator systemu Linuks.
+      </p>
+      <h2 id="8.1.procesmgmt">8.1. Zarządzanie procesami</h2>
+      <p>
+        <strong>Procesy</strong> są to odniesienia w pamięci do uruchomionych 
+        w systemie programów. Procesy są
+        sposobem organizacji przydzielania zasobów komputera. Struktura
+        procesów w systemie ma charakter hierarchiczny, każdy proces może mieć
+        swoje podprocesy, tzw. procesy potomne. Każdy z procesów posiada swój 
+        unikalny identyfikator <strong>PID</strong>, identyfikator służy
+        jądru do komunikacji z procesami. W systemie istnieje masa procesów,
+        wśród nich możemy wyróżnić takie jak <strong>demony</strong>, które 
+        świadczą usługi użytkownikom oraz innym procesom. Zwykle działają one 
+        w tle, oraz pozostają w stanie bezczynności oczekując na żądania od
+        użytkownika lub od innego procesu.
+      </p>
+      <p>
+        Procesy podczas wykonywania swoich czynności mogą znajdować się w 5
+        różnych stanach. Stan procesu zależy od tego co robi w danym
+        momencie. Procesy mogą przyjmować następujące stany: 
+      </p>
+      <ul>
+        <li><strong>Running</strong> - (pol. <em>uruchomiony</em>), proces jest
+          obecnie wykonywany przez CPU.</li>
+        <li><strong>Sleeping</strong> - (pol. <em>spanie</em>), proces oczekuje
+          na dane.</li>
+        <li><strong>Waiting</strong> - (pol. <em>czekanie</em>), proces czeka
+          na swoją kolej do wykonania przez procesor.</li>
+        <li><strong>Stopped</strong> - (pol. <em>zatrzymany</em>), proces
+          otrzymał sygnał zatrzymania wykonania i nie wznowii go do momentu
+          otrzymiania odpowiedniego sygnału.</li>
+        <li><strong>Zombie</strong> - (pol. <em>zombie</em>), proces jest
+          martwy, nie posiada już żadnych zasobów. Widnieje wśród innych
+          procesów gdyż czeka na zakończenie przez inny proces.</li>
+      </ul>
+      <p>
+        Procesy podczas swoje cyklu <em>życia</em> w systemie, zmieniają te
+        stany w zależności od tego jaką czynność wykonują. Najczęściej będzie
+        to lawirowanie między trzema pierwszymi. Teraz kiedy znamy
+        charakterystykę procesów możemy przejść do praktyki, a na początku
+        zajmiemy się wyświetlaniem informacji o procesach.
+      </p>
+      <h3 id="8.1.1.pscommand">8.1.1. Polecenie ps</h3>
+      <p>
+        Polecenie <strong>ps</strong>, służy do wyświetlania procesesów w 
+        tabeli.
+        Domyślnie to polecenie bez żadnych opcji wyświetli procesy uruchomione
+        w tym oknie terminala.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ps
+    PID TTY          TIME CMD
+   1452 pts/1    00:00:00 bash
+   1891 pts/1    00:00:00 ps
+</pre>
+      <p>
+        Wynik polecenia podzielony jest na 4 kolumny. Kolumna
+        <code class="code-inline">PID</code> zwraca identyfikator procesu,
+        następnie kolumna <code class="code-inline">TTY</code> wyświetla
+        powiązaną z procesem nazwę terminala, na którym został uruchomiony,
+        później w kolumnie <code class="code-inline">TIME</code> znajduje się
+        łączny czas procesora w wyrażony w sekundach poświęcony na wykonanie
+        tego procesu. Na końcu w kolumnie <em>CMD</em>, znajduje się polecenie
+        odpowiedzialne za ten proces. To polecenie nie zwraca zbyt wielu
+        informacji, które mogły by nam pomóc w zarządzaniu procesami. Warto
+        dodać do tego polecenia kilka opcji.
+      </p>
+      <p>
+        Jedną z nich może być opcja <em>-e</em>, która zwraca każdy występujący 
+        w systemie proces, następną jak warto dodać jest opcja <em>-f</em>,
+        zwracająca wiecej szczegółów nt. procesu, jednak ta opcja nie jest dla
+        nas wystarczająca, ponieważ do zarządzania procesami potrzebujemy
+        jeszcze kilku informacji, które jest w stanie zwrócić nam opcja
+        <em>-l</em>. Te wymienione trzy opcje, tworzą najbardziej powszechne
+        użycie polecenia <em>ps</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ps -efl 
+F S UID          PID    PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
+...
+4 S root        1443     849  0  80   0 -  4884 -      10:34 ?        00:00:00 sshd: user [priv]
+5 S user        1448    1443  0  80   0 -  4884 -      10:34 ?        00:00:00 sshd: user@pts/1
+0 S user        1452    1448  0  80   0 - 56082 do_wai 10:34 pts/1    00:00:00 -bash
+1 I root        1828       2  0  80   0 -     0 -      13:15 ?        00:00:00 [kworker/u2:2-events_unbound]
+1 I root        1838       2  0  80   0 -     0 -      13:58 ?        00:00:00 [kworker/0:1-events]
+1 I root        1851       2  0  80   0 -     0 -      14:02 ?        00:00:00 [kworker/u2:1-events_unbound]
+1 I root        1910       2  0  80   0 -     0 -      15:28 ?        00:00:00 [kworker/0:0-kdmflush/253:0]
+1 I root        1931       2  0  80   0 -     0 -      15:37 ?        00:00:00 [kworker/0:2-kdmflush/253:0]
+0 R user        1932    1452  0  80   0 - 56375 -      15:38 pts/1    00:00:00 ps -efl
+</pre>
+      <p>
+        Polecenie to zwraca bardzo dużo informacji o procesach. Najważniejsze
+        dla nas są kolumny: <code class="code-inline">S</code>,
+        <code class="code-inline">UID</code>, <code class="code-inline">PID</code>,
+        <code class="code-inline">PPID</code>, <code class="code-inline">PRI</code>,
+        <code class="code-inline">NI</code> oraz <code class="code-inline">CMD</code>,
+        w których znajdują się takie informacje jak:
+      </p>
+      <ul>
+        <li><code class="code-inline">S</code> - Stan procesu.</li>
+        <li><code class="code-inline">UID</code> - Identyfikator użytkownika,
+          w tym przypadku jest to nazwa użytkownika.</li>
+        <li><code class="code-inline">PID</code> - Identyfikator procesu.</li>
+        <li><code class="code-inline">PPID</code> - Identyfikator procesu
+          nadrzędnego (procesu, który uruchomiło ten proces).</li>
+        <li><code class="code-inline">PRI</code> - Priorytet procesu.</li>
+        <li><code class="code-inline">NI</code> - Wartość <em>nice</em>.</li>
+        <li><code class="code-inline">CMD</code> - Polecenie, które uruchomiło
+          proces.</li>
+      </ul>
+      <p>
+        Jako ciekawostkę podam, iż procesy, które w kolumnie 
+        <code class="code-inline">TTY</code> posiadają znak zapytania
+        (<strong>?</strong>) pochodzą prawdopodbnie od któregoś z demonów.
+      </p>
+      <p>
+        Polecenie <em>ps</em> daje możliwość wyświetlenia
+        tylko tych informacji, które potrzebujemy dzięki opcji <em>-o</em>.
+        Możemy użyć polecenia poniżej:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ps -eo user,s,pid,command
+USER     S     PID COMMAND
+root     S       1 /usr/lib/systemd/systemd rhgb --switched-root --system --deserialize 31
+root     S       2 [kthreadd]
+root     I       3 [rcu_gp]
+root     I       4 [rcu_par_gp]
+root     I       6 [kworker/0:0H-events_highpri]
+root     I       9 [mm_percpu_wq]
+root     S      10 [rcu_tasks_kthre]
+root     S      11 [rcu_tasks_rude_]
+root     S      12 [rcu_tasks_trace]
+root     S      13 [ksoftirqd/0]
+root     I      14 [rcu_preempt]
+</pre>
+      <p>
+        Za pomocą <em>ps</em>, możemy wyszukać proces na podstawie polecenia.
+        Do tego wykorzystamy opcje <em>-C</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ps -o user,s,pid,command -C sshd
+USER     S     PID COMMAND
+root     S     849 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
+root     S    1974 sshd: user [priv]
+user     S    1979 sshd: user@pts/0
+root     S    2098 sshd: user [priv]
+user     S    2103 sshd: user@pts/1
+</pre>
+      <p>
+        Polecenie <em>ps</em> zawiera ogromną ilość opcji. Ich opisy znajdują
+        się na stronie podręcznika polecenia.
+      </p>
+      <h3 id="8.1.2.polecenietop">8.1.2. Polecenie top</h3>
+      <p>
+        Polecenie z poprzednie podrozdziału służyło do wyświetlania procesów.
+        Za pomocą tego przedstawionego tutaj możemy je monitorować 
+        w czasie rzeczywistym. Polecenie <strong>top</strong>, może posłużyć
+        do sprawdzenia czy system nie jest przeciążony.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ top
+top - 16:31:38 up  6:00,  1 user,  load average: 0.00, 0.00, 0.00
+Tasks: 174 total,   1 running, 173 sleeping,   0 stopped,   0 zombie
+%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
+MiB Mem :    960.5 total,    123.2 free,    464.1 used,    373.2 buff/cache
+MiB Swap:   2048.0 total,   2048.0 free,      0.0 used.    335.9 avail Mem 
+
+    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND 
+      1 root      20   0  106212  15976  10328 S   0.0   1.6   0:01.96 systemd  
+      2 root      20   0       0      0      0 S   0.0   0.0   0:00.00 kthreadd 
+      3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp 
+      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp 
+      6 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/0:0H-events_highpri 
+      9 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 mm_percpu_wq 
+     10 root      20   0       0      0      0 S   0.0   0.0   0:00.00 rcu_tasks_kthre 
+     11 root      20   0       0      0      0 S   0.0   0.0   0:00.00 rcu_tasks_rude_ 
+     12 root      20   0       0      0      0 S   0.0   0.0   0:00.00 rcu_tasks_trace 
+     13 root      20   0       0      0      0 S   0.0   0.0   0:00.36 ksoftirqd/0 
+     14 root      20   0       0      0      0 I   0.0   0.0   0:00.26 rcu_preempt 
+     15 root      rt   0       0      0      0 S   0.0   0.0   0:00.05 migration/0
+     16 root      20   0       0      0      0 S   0.0   0.0   0:00.00 cpuhp/0 
+     18 root      20   0       0      0      0 S   0.0   0.0   0:00.00 kdevtmpfs
+     19 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 netns 
+     20 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 inet_frag_wq 
+</pre>
+      <p>
+        Informacje zwracane przez to polecenie możemy podzielić na dwie części
+        jedną z nich jest część, w której znajduje się podsumowanie. W pierszej
+        linii znajduje się linia identyczna z informacją zwracaną przez
+        polecenie <em>uptime</em>, następne linie to: ilość liczbowa procesów w
+        systemie, informacje o zużyciu procentowym procesora, zużyciu
+        pamięci operacyjnej oraz przestrzeni wymiany. Ostatnia kolumna z
+        ostatniego rzędu zwraca rzeczywistą ilość dostępnej pamięci operacyjnej
+        bez wliczania przestrzeni wymiany.  
+      </p>
+      <p>
+        Drugą częścią jest tabelaryczne przedstawienie listy procesów 
+        dostępnych
+        w systemie. W tym przypadku procesy, które zużywają najwięcej zasobów
+        komputera wyświetlane są w pierwszych wierszach tabeli. Przez co można
+        stwierdzić, że tabela jest posortowana względem wartości procentowej
+        zużycia procesora. Polecenie <em>top</em> jest bardzo elastyczne,
+        posiadamy możliwość dostosowania kolumn wyświetlanych w tabeli oraz
+        części z podsumowaniem, informacje na ten temat znajdują się na stronie
+        podręcznika.
+      </p>
+      <h3 id="8.1.3.niceandrenice">8.1.3. Priorytet procesu</h3>
+      <p>
+        Podczas wykonywania procesów, każdy z procesów dostaje dostęp do
+        procesora na ułamek sekundy, wówczas proces zmienia swój stan na
+        <em>Running</em>, po upływie tego czasu proces w zależności od czynności
+        przechodzi albo w <em>Waiting</em> albo w <em>Sleeping</em>. Kiedy
+        proces przebywa w tych stanach wykonywane są inne procesy, później
+        proces znów zostaje wznowiony i tak w kółko. Tego typu działanie
+        nazywane jest wielozadaniowością (a przynajmniej się takie wydaje).
+        Każdy z procesów otrzymuje określoną ilość czasu, jednak są procesy,
+        które mogą otrzymać go więcej lub mniej. Czasami zmiana tych wartość
+        jest to niezbędna do funkcjonowania
+        systemu. Czynnikiem który wpływa na tę decyzje jest 
+        <strong>priorytet</strong> - kolumna <em>PRI</em> przy poleceniu
+        <em>ps</em>. Priorytety są już z góry określone podczas uruchamiania
+        procesu. Najwyszym priorytetem (proces otrzyma najwięcej czasu
+        procesora) jest 0, a najniższym (proces otrzyma najmniej czasu
+        procesora) jest 39. Administratorzy mają wpływ na priorytet procesu
+        za pomocą wartości <strong>nice</strong>. Kiedy administrator chce
+        zmienić wartość priorytetu, ustala wartość <em>nice</em> dla procesu
+        a ona jest do niego dodawana. Wartość <em>nice</em>, może być w zakresie
+        od -20 do 19. Jeśli chcemy aby proces posiadał w momencie uruchomienia
+        inny priorytet uruchamiamy go za pomocą polecenia 
+        <strong>nice</strong>. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ps -efl | grep $(pidof top)
+0 S user        2152    1980  0  80   0 - 56480 do_sel 17:24 pts/0    00:00:00 top
+[user@server1 ~]$ nice -n 19 top
+[user@server1 ~]$ ps -efl | grep $(pidof top)
+0 S user        2137    1980  0  99  19 - 56480 do_sel 17:20 pts/0    00:00:00 top
+</pre>
+      <p>
+        Kolumna numer 7 zawiera wartość priorytetu, a 8 kolumna zawiera wartość
+        <em>nice</em>. Zwróćmy uwagę na rozbierzności w wyświetlaniu 
+        priorytetów procesów między poleceniami <em>top</em> oraz <em>ps</em>.
+        Nie mniej jednak wartość <em>nice</em> sprawiła zmianę priorytetu
+        procesu <em>top</em>. 
+      </p>
+      <p>
+        Jeśli proces jest już uruchomiony to również możemy zmienić jego
+        priorytet, za pomocą polecenie <strong>renice</strong>, jednak
+        najpierw poznamy dwa polecenia, które ułatwią nam pracę z poleceniem
+        <em>renice</em> oraz każdym innym, które potrzebuje identyfikatora
+        procesu. Tymi poleceniami są polecenia <strong>pidof</strong> oraz
+        <strong>pgrep</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ pidof top
+2170
+[user@server1 ~]$ pgrep top
+2170
+</pre>
+      <p>
+        Polecenia bez żadnych opcji zwracają to samo - identyfikator
+        procesu i tymi poleceniami będziemy się wspomagać. Oczywiście więcej
+        informacji na ich temat znajduje się na stronach podręcznika. Wracajac
+        do wartości <em>nice</em>, zmienie teraz priorytet działającego
+        procesu za pomocą polecenia <em>renice</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo renice -n -10 $(pidof top)
+[sudo] password for user: 
+2170 (process ID) old priority 0, new priority -10
+[user@server1 ~]$ ps -efl | grep $(pidof top)
+0 S user        2170    1980  0  70 -10 - 56480 do_sel 17:43 pts/0    00:00:00 top
+</pre>
+      <p>
+        Priorytet procesu zmienił się. Zwróćmy uwagę na to, iż polecenie
+        <em>renice</em> wymaga uprawnień superużytkownika do działania.
+      </p>
+      <h3 id="8.1.4.signals">8.1.4. Zarządzanie procesami za pomocą syganałów</h3>
+      <p>
+        Działanie procesów, może być kontrolowane za pomocą sygnałów, które
+        są do nich wysyłane przez jądro systemu. Te sygnały mogą zatrzymać
+        wykonanie procesu, przenieść proces na do tła, poprosić go o zakończenie
+        działania lub gdy jest dość oporny na poprzedni sygnał poprostu
+        unicestwić. Każdy z sygnałów posiada swoją nazwę oraz numer. My możemy
+        używać dowolnej formy. Poniżej znajduje się lista najczęściej
+        wykorzystywanych sygnałów wraz z numerami.
+      </p>
+      <ul>
+        <li><strong>SIGHUP - 1</strong> - sygnał zawieszenia, powoduje
+          odłącznieni się od terminala, którym proces wystartował. W przypadku
+          demonów, ten sygnał spowoduje ponowne odczytanie konfiguracji bez
+          restartu demona.</li>
+        <li><strong>SIGINT - 2</strong> - sygnał przerwania, wysyłany jest do
+          procesu w momencie naciśnięcia klawiszy <em>Ctrl+c</em>.</li>
+        <li><strong>SIGKILL - 9</strong> - sygnał zabicia, powoduje
+          unicestwienie procesu, a sprzątaniem po nim zajmuj się jądro.</li>
+        <li><strong>SIGTERM - 15</strong> - sygnał zakończnia, prośba o
+          zakończenie swojego działania. W przypadku tego sygnału proces ma
+          możliwość posprzątania po sobie oraz polubownego zakończenia
+          wszystkich czynności. Ten sygnał jest domyślnym sygnałem wysyłanym
+          do procesów.</li>
+        <li><strong>SIGCONT - 18</strong> - sygnał kontynuacji pracy w tle,
+          równoznaczny z poleceniem <em>bg</em>.</li>
+        <li><strong>SIGSTOP - 19</strong> - sygnał zatrzymania, równoznaczny
+          z naciśnięciem kombinacji klawiszy <em>Ctrl+z</em>.</li>
+        <li><strong>SIGTSTP - 20</strong> - sygnał kontynuacji pracy na
+          pierwszym planie, równoznaczny z poleceniem <em>fg</em>.</li>
+      </ul>
+      <p>
+        Do wysyłania sygnałów do procesów służy polecenie <strong>kill</strong>
+        lub <strong>pkill</strong>. Różnią się one tym, iż poleceniu 
+        <em>kill</em> podaje się <em>PID</em>, natomiast <em>pkill</em> nazwę
+        procesu lub polecenie. Numery sygnałów podjemy po myślniku przed
+        <em>PID</em>-em lub nazwą. Jeśli chcemy użyć nazw sygnałów należy
+        podać je po opcji <em>-s</em> (w przypadku polecenia <em>kill</em>) lub
+        <em>--signal</em> (w przypadku polecenia <em>pkill</em>). Listę
+        dostępnych sygnałów możemy wyświetlić za pomocą poniższego polecenia:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ kill -l
+ 1) SIGHUP      2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
+ 6) SIGABRT     7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
+11) SIGSEGV    12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
+16) SIGSTKFLT  17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
+21) SIGTTIN    22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
+26) SIGVTALRM  27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
+31) SIGSYS     34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
+38) SIGRTMIN+4 39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
+43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
+48) SIGRTMIN+14        49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
+53) SIGRTMAX-11        54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
+58) SIGRTMAX-6 59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
+63) SIGRTMAX-1 64) SIGRTMAX    
+</pre>
+      <p>
+        W ramach przykładu zakończymy działania procesu <em>top</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ pkill top
+[user@server1 ~]$ kill $(pidof top)
+</pre>
+      <p>
+        Do kończenia pracy procesów możemy użyć również polecenia
+        <strong>killall</strong>, które kończy pracę wszystkich procesów,
+        które pasują do określonych kryteriów.
+      </p>
+      <h2 id="8.2.taskschedule">8.2. Harmonogram zadań</h2>
+      <p>
+        Harmonogram zadań służy do planowania wykonania poleceń czy
+        uruchomienia programów w przyszłości. Na Linuksie możemy to zrobić na
+        dwa sposóby, w zależności od potrzeby powtórzenia danego zadania. Na
+        Linuksie zadania z harmonogramu moga być uruchomione raz w określonym
+        czasie lub wykonywane cyklicznie co jakiś okres czasu. Narzędziami
+        odpowiedzialnymi za obsługę funkcji harmonogramu zadań na Linuksie 
+        są <strong>at</strong> oraz <strong>cron</strong>. W <em>RHEL</em> 
+        możemy
+        również spotkać się z mechanizmem kontroli dostępu do tych programów.
+      </p>
+      <h3 id="8.2.1.scheduleaccesscontrol">8.2.1. Kontrola dostępu do harmongramu</h3>
+      <p>
+        W <em>RHEL</em> stosowany jest mechanizm kontroli dostępu do 
+        harmonogramu
+        zdań zarówno dla obu narzędzi. Ten mechanizm składa się z dwóch
+        plików, jeden z rozszerzeniem <em>*.allow</em> oraz jeden z
+        rozszerzeniem <em>*.deny</em>. W tych plikach umieszczamy
+        wpis z nazwą użytkownika w zależności od tego czy użytkownik ma mieć
+        lub nie mieć dostępu do tych narzędzi. Sama obecność tych plików w
+        systemie ma wpływ na to czy użytkownicy będą mogli korzystać z
+        harmonogramu zadań. Każdy program posiada swoją parę plików. W 
+        poniższej tabeli znajdują się rozpisane zależności, które obrazują
+        w jaki sposób obecność tych plików wpływa na dostęp do narzędzi
+        harmonogramu zadań.
+      </p>
+      <table>
+        <thead>
+          <tr>
+            <th>Obecność pliku <em>*.allow</em></th>
+            <th>Obecność pliku <em>*.deny</em></th>
+            <th>Wpływ na dostęp do <em>at</em> oraz <em>cron</em></th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td>Istnieje, posiada wpisy użytkowników.</td>
+            <td>Nie musi istnieć.</td>
+            <td><strong>Wszyscy użytkownicy w pliku posiadają dostęp.</strong></td>
+          </tr>
+          <tr>
+            <td>Istnieje, ale jest pusty.</td>
+            <td>Nie musi istnieć.</td>
+            <td><strong>Nikt nie ma dostępu.</strong></td>
+          </tr>
+          <tr>
+            <td>Nie istnieje.</td>
+            <td>Istnieje, posiada wpisy użytkowników.</td>
+            <td><strong>Wszyscy użytkownicy, poza tymi zapisanym w pliku
+              <em>*.deny</em> mają dostęp.</strong></td>
+          </tr>
+          <tr>
+            <td>Nie istnieje.</td>
+            <td>Istnieje, ale jest pusty.</td>
+            <td><strong>Wszyscy użytkownicy posiadają dostęp.</strong></td>
+          </tr>
+          <tr>
+            <td>Nie istnieje.</td>
+            <td>Nie istnieje.</td>
+            <td><strong>Nikt nie ma dostępu.</strong></td>
+          </tr>
+        </tbody> 
+      </table>
+      <p>
+        Powyższe zasady nie obowiązują oczywiście superużytkownika, nawet mimo
+        umieszczenia jego nazwy w plik <em>*.deny</em>. Domyślnie w 
+        <em>RHEL</em>
+        plik <em>*.allow</em> nie istnieje, natomiast plik <em>*.deny</em>
+        istnieje, ale jest pusty.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Definiując wpisy w tych plikach, należy pamiętać o tym aby jedna linia
+        zwierała jednego użytkownika. To jedyna poprawna metoda.
+      </p>
+      <p>
+        Po wpisaniu nazwy użytkownika do pliku, jeśli będzie on chciał
+        skorzystać z <em>at</em> lub <em>cron</em> zobaczy poniższe komunikaty.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ at
+You do not have permission to use at. 
+[user@server1 ~]$ crontab -e
+You (user) are not allowed to use this program (crontab)
+See crontab(1) for more information
+</pre>
+      <p>
+        Oczywiście dla przykładu zablokowałem dostęp do obu narzędzi.
+      </p>
+      <h3 id="8.2.2.at">8.2.2. Wykonanie zadań w przyszłości - polecenie at</h3>
+      <p>
+        Polecenie <strong>at</strong> służy do planowania pojedynczego 
+        wykonania
+        zadania w przyszłości. Podczas wydawania polecenia podajemy czas oraz
+        ewentualnie datę kiedy zadanie ma zostać wykonane. Czas możemy podać
+        na kilka różnych sposobów:
+      </p>
+      <ul>
+        <li><strong>at 1:15am</strong> - polecenie zostanie uruchomione o 01:15
+          następnego dnia,</li>
+        <li><strong>at noon</strong> - polecenie zostanie uruchomione w
+          południe tego lub nastęnego dnia,</li>
+        <li><strong>at 23:45</strong> - polecenie zostanie uruchomione o 23:45,</li>
+        <li><strong>at midnight</strong> - polecenie zostanie uruchomione o
+          północy,</li>
+        <li><strong>at 17:05 tommorow</strong> - polecenie zostanie uruchomione
+          w dniu jutrzejszym o 17:05,</li>
+        <li><strong>at now + 5 hours</strong> - polecenie zostanie uruchonione
+          za 5 godzin,</li>
+        <li><strong>at 3:00 10/12/2022</strong> - polecenie zostanie
+          uruchomione o 3 w nocy 12 października 2022 roku (w amerykańskim
+          zapisie daty na początku podaje się miesiąc następnie dzień
+          miesiąca).</li>
+      </ul>
+      <p>
+        Po wydaniu polecenia z datą, polecenie uruchomi tryb interaktywyny,
+        gdzie w każdej linii będziemy mogli zapisać polecenie, które wykona
+        się o podanym czasie. Po zakończeniu zapisywania poleceń naciskamy
+        kombinację <em>Ctrl+d</em>, aby zakończyć działanie programu i zapisać
+        polecenia, wówczas po znaku zachęty pojawi się znak <em>&lt;EOT&gt;</em>
+        oznaczający zakończenie wprowadzania poleceń.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ at midnight
+warning: commands will be executed using /bin/sh
+at&gt; date 
+at&gt; pwd
+at&gt; whoami
+at&gt; who
+at&gt; w
+at&gt; &lt;EOT&gt;
+job 2 at Wed Jul  6 00:00:00 2022
+</pre>
+      <p>
+        Polecenia zapisywane są w odpowiednich pliku w katalogu
+        <em>/var/spool/at</em>. Dostęp do katalogu wymaga uprawnień 
+        administratora.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo ls -l /var/spool/at
+[sudo] password for user: 
+total 4
+-rwx------. 1 user user 3365 Jul  5 09:28 a0000201a56968
+</pre>
+      <p>
+        Programem odpowiedzialnym za wykonanie poleceń jest demon <em>atd</em>.
+        Za pomocą opcji polecenia <em>at</em> możemy na przykład wyświetlić
+        listę zdefiniowanych zadań (<em>-l</em>):
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ at -l 
+2      Wed Jul  6 00:00:00 2022 a user
+</pre>
+      <p>
+        W pierwszej kolumnie znajduje się numer zadania. Jest on istotny jeśli
+        chcemy na przykład wyświetlić jego plik za pomocą opcji <em>-c</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ at -c 2
+#!/bin/sh
+# atrun uid=1000 gid=1000
+# mail user 0
+umask 22
+SHELL=/bin/bash; export SHELL
+HISTCONTROL=ignoredups; export HISTCONTROL
+HISTSIZE=1000; export HISTSIZE
+HOSTNAME=server1.example.com; export HOSTNAME
+PWD=/home/user; export PWD
+LOGNAME=user; export LOGNAME
+XDG_SESSION_TYPE=tty; export XDG_SESSION_TYPE
+MOTD_SHOWN=pam; export MOTD_SHOWN
+HOME=/home/user; export HOME
+LANG=en_US.UTF-8; export LANG
+...
+${SHELL:-/bin/sh} &lt;&lt; 'marcinDELIMITER29478f5e'
+date
+pwd
+whoami
+who
+w
+marcinDELIMITER29478f5e
+</pre>
+      <p>
+        Zadanie możemy też usunąć za pomocą opcji <em>-r</em> lub <em>-d</em>,
+        plik z katalogu <em>/var/spool/at</em> również zostanie usunięty.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ at -d 2
+[user@server1 ~]$ at -l
+</pre>
+      <p>
+        Do usunięcia potrzebny jest numer zadania, który znajduje się
+        pierwszej kolumnie listy zadań wyświetlonej za pomocą polecenia
+        <code class="code-inline">at -l</code>. Obie przestawione powyżej
+        opcje są aliasami do poleceń <em>atq</em> oraz <em>atrm</em>.
+      </p>
+      <p>
+        Działanie narzędzi harmonogramu zadań jest rejestrowane, a ich
+        komunikaty diagnostyczne są zapisywane w <em>/var/log/cron</em>. Mimo
+        iż nazwa pliku wskazuje iż dotyczy on głównie <em>crond</em> to
+        komunikaty <em>atd</em> również są tam zapisywane. Aby
+        wyświetlić jego zawartość potrzebne są uprawnienia administratora:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tail /var/log/cron
+[sudo] password for user: 
+Jul  5 09:01:01 server1 anacron[1651]: Jobs will be executed sequentially
+Jul  5 09:01:01 server1 run-parts[1640]: (/etc/cron.hourly) finished 0anacron
+Jul  5 09:01:01 server1 CROND[1639]: (root) CMDEND (run-parts /etc/cron.hourly)
+Jul  5 09:21:01 server1 anacron[1651]: Job `cron.daily' started
+Jul  5 09:21:01 server1 anacron[1651]: Job `cron.daily' terminated
+Jul  5 09:21:01 server1 anacron[1651]: Normal exit (1 job run)
+Jul  5 10:01:01 server1 CROND[1941]: (root) CMD (run-parts /etc/cron.hourly)
+Jul  5 10:01:01 server1 run-parts[1941]: (/etc/cron.hourly) starting 0anacron
+Jul  5 10:01:01 server1 run-parts[1941]: (/etc/cron.hourly) finished 0anacron
+Jul  5 10:01:01 server1 CROND[1940]: (root) CMDEND (run-parts /etc/cron.hourly)
+</pre>
+      <h3 id="8.2.3.cron">8.2.3. Definiowanie powtarzalnych zadań - program cron</h3>
+      <p>
+        Na Uniksach, bo nie tylko na Linuksie, istnieje program służący do
+        definiowania powtarzalnych zadań uruchamianych co jakiś czas. Takim
+        programem, a raczej demonem jest <strong>cron</strong>. Działanie
+        tego programu opiera się o pliki zwane <em>tablicami cron</em> lub
+        <em>crontabami</em>. Każdy użytkownik może korzystać z tego narzędzia,
+        chyba, że występuje on w pliku <em>/etc/cron.deny</em>.
+        Użytkownicy do kontroli harmonogramu zadań, używają polecenia
+        <strong>crontab</strong>. Każdy z nich zapisuje zadania w swojej
+        tablicy znajdującej się w katalogu <em>/var/spool/cron</em>. Zapis
+        zadań w tablicy wymaga ściśle określonej składni. Wpis składa się z
+        5 pól czasu, ewentualnego pola zawierającego nazwę użytkownika
+        (pole to występuje tylko w systemowej tablicy cron 
+        <em>/etc/crontab</em>), z którego uprawnieniami ma zostać wykonane to
+        zadanie, oraz reszty linii zawierającej polecenie do wykonania.
+        Poniżej znajduje się przykład wpis, który sobie przeanalizujemy.
+      </p>
+<pre class="code-block">
+15 13 4 7 * echo "Hello World" &gt; /dev/pts/1
+</pre>
+      <p>
+        Każdy wpis zadania w tablicy <em>cron</em> rozpoczyna się od 5 pól
+        określających kiedy owe zadanie ma zostać wykonane. Pola od lewej
+        definiują kolejno:
+      </p>
+      <ul>
+        <li><code class="code-inline">15</code> - pole 1, minuta w godzinie.
+          W tym polu określamy konkretną minutę godziny w której zadanie
+          ma zostać uruchomione, jeśli jest to jedyne skonfigurowane pole
+          wówczas zadanie bedzie uruchamiać się co godzinę. To 
+          pole przyjmuje wartości od 0 do 59.</li>
+        <li><code class="code-inline">13</code> - pole 2, godzina w dniu. To
+          pole wskazuje na godzinę, w której zadanie ma zostać uruchomione.
+          Jeśli to jedyne skonfigurowane pole, wówczas zadanie będzie
+          uruchamiać się o pełnej godzinie kazdego dnia. To pole może
+          przyjmować wartości od 0 do 23.</li>
+        <li><code class="code-inline">4</code> - pole 3, dzień miesiąca. Pole
+          wskazuje dzień miesiąca w którym ma zostać uruchomione zadanie. Jeśli
+          jest to jedyne zdefiniowane pole, to zadanie będzie się uruchamiać
+          tego dnia każdego miesiąca. Pole to może przyjmować wartości od
+          1 do 31.</li>
+        <li><code class="code-inline">7</code> - pole 4, miesiąc, pole wskazuje
+          na miesiąc w roku. Pole może przyjmować zarówno wartości liczbowe
+          jak alfabetyczne, nazwy miesięcy składają się trzech pierwszych
+          małych liter angielskiej nazwy miesiąca.</li>
+        <li><code class="code-inline">*</code> - pole 5, dzień tygodnia, pole
+          wskazuje na dzień tygodnia podobnie jak miesiąc może zawierać
+          wartości liczbowe oraz alfabetyczne zawierające trzy pierwsze 
+          małe litery angielskiej nazwy dnia. Wartość 0 oraz 7 oznaczają 
+          niedzielę.</li> 
+      </ul>
+      <p>
+        Pola czasu przyjmują takie wartości jak listy (określajace konkretne
+        godziny, dni itd. Na przykład <em>15,16</em>), zakresy (określające,
+        którego do którego polecenia ma zostać wykonane np. <em>10-20</em>) 
+        oraz wartości skokowe, które definiują co ile minut, godzin lub dni
+        wykonać to zadanie. Listy oraz zakresy można łączyć ze sobą zazwyczaj
+        <em>10-15,21</em> może to oznacząć uruchomienie zadania od 10-15 oraz
+        21 dnia miesiąca. Więcej informacji na temat można znaleźć na stronie
+        podręcznika pliku <em>/etc/crontab</em>. 
+      </p>
+      <p>
+        Ostatnie pole, jest miejscem do umieszaczania poleceń. Jeśli polecenie
+        zwraca istotne dane wyjściowe to najlepiej jest je przekierować.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzamin:</strong><br />
+        Wykonując zadania administracyjne, powinniśmy mieć opanowaną składnie
+        wpisów zadań oraz rozumienie jej poszczególnych części.
+      </p>
+      <p>
+        Do edycji tablicy <em>cron</em> służy polecenie <strong>crontab</strong>
+        z opcją <em>-e</em>. Polecenie to uruchomi edytor, w którym to
+        zapiszemy wpisy harmonogramu, po zakończeniu edycji i zapisaniu zmian
+        polecenie utworzy plik w <em>/var/spool/cron</em> o nazwie użytkownika.
+        Ten plik staje się teraz jego tablicą <em>cron</em>. Po zapisaniu pliku
+        tablica zostaje <em>zainstalowana</em> w pamięci demona. W ten sposób
+        definiuje się wpisy harmonogramu zadań <em>cron</em>.
+      </p>
+      <p>
+        Za pomocą opcji <em>-l</em> możemy wyświetlić obecną tablicę 
+        <em>cron</em>.
+      </p>
+<pre class="code-block">
+[user@server1 log]$ crontab -l
+15 13 4 7 * echo "Hello World" &gt; /dev/pts/1
+</pre>
+      <p>
+        Za pomocą opcji <em>-r</em> możemy usunąć obecną tablicę <em>cron</em>:
+      </p>
+<pre class="code-block">
+[user@server1 log]$ crontab -r
+[user@server1 log]$ crontab -l
+no crontab for user
+</pre>
+      <h3 id="8.2.4.anacron">8.2.4. Wykonanie pominiętych zadań - program Anacron</h3>
+      <p>
+        Nie które komputery z zainstalownym Linuksem, nie są właczone 24/7.
+        Za tem cześć zadań zdefiniowana w systemowym harmonogramie w plikach
+        <em>/etc/cron.*</em> nie jest wykonywana. Pliki te dotyczą czynność 
+        systemowych zdefiniowanych co godzinę, dzień, tydzień czy miesiąc.
+        Ta przypadłość najczęściej dotyczy komputerów osobistych.
+        Dlatego też, aby uruchomić te zdania używa się demona
+        <strong>anacron</strong>. Aby demon rozpoczął uruchmianie niewykonanych
+        zadań muszą zostać w systemie spełnione trzy czynniki. Pliki tablicy
+        <em>anacron</em> muszą istnieć w katalogu <em>/var/spool/anacron</em>,
+        musi upłynąć odpowiednia ilość czasu (zdefiowana w pliku
+        systemowej tablicy <em>/etc/anacrontab</em>) oraz komputer musi być
+        podłączony do stałego źródła zasilania. Poniżej znajduje sie plik
+        konfiguracyjny <em>anacron</em>.
+      </p>
+<pre class="code-block">
+SHELL=/bin/sh
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+MAILTO=root
+RANDOM_DELAY=45
+START_HOURS_RANGE=3-22
+1              5       cron.daily                nice run-parts /etc/cron.daily
+7             25       cron.weekly               nice run-parts /etc/cron.weekly
+@monthly 45    cron.monthly            nice run-parts /etc/cron.monthly
+</pre>
+      <p>
+        W pierwszej kolumnie znajduje się okres (w dniach) jaki musi upłynąć 
+        od ostatniego uruchomienia tych zdań. W drugiej znajduje się opóźnienie
+        które musi minąć od uruchomienia systemu, to opóźnienie jest zazwyczaj
+        powiększone o wartość zdefiniowaną w zmiennej 
+        <code class="code-inline">RANDOM_DELAY</code>.
+        W następnej kolumnie znajduje się identyfikator zdania, a ostatnia
+        kolumna to już pole polecenia. Dość istotną rolę gra tutaj wartość
+        zmiennej <code class="code-inline">START_HOURS_RANGE</code>. Określa
+        ona w jakich godzinach <em>anacron</em> może działać. 
+      </p>
+      <p>
+        Działanie demona możemy wymusić poprzez wydanie polecenia
+        <strong>anacron</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo anacron
+[sudo] password for user: 
+[user@server1 ~]$ 
+</pre>
+      <h3 id="exec8.1">Ćwiczenie 1: Wartość nice procesu</h3>
+      <p>
+        Na maszynie <em>server1</em>, uruchomy dwa termiale (mogą być to dwa
+        połączenia SSH z tą maszyną) następnie w jednym z terminali uruchom
+        program <em>top</em>, na drugim terminalu za pomocą polecenia <em>ps</em>
+        lub <em>pgrep</em> ustal <em>PID</em> oraz wartość <em>nice</em> dla
+        wcześniej uruchomionego polecenia <em>top</em>. Zakończ działanie
+        programu <em>top</em>, następnie uruchom je ponownie z priorytetem
+        zmniejszonym o 8 (+8). Potwierdź zmianę priorytet na drugim terminalu.
+        Następnie zwiększ priorytet o 10 (-10) nie zamykając programu <em>top</em>
+        i potwierdź to w drugim terminalu.
+      </p>
+      <h3 id="exec8.2">Ćwiczenie 2: Konfiguracja tablicy cron użytkownika</h3>
+      <p>
+        Na maszynie <em>server1</em> jako superużytkownik zapewnij dostęp
+        do <em>cron</em> dla zwykłego użytkownika, na którego się logujesz.
+        Jako zwykły użytkownik sprawdź nazwę aktualnego terminala
+        (polecenie <em>tty</em>) oraz obecną datę i godzinę (polecenie 
+        <em>date</em>). Za pomocą harmonogramu zadań <em>cron</em> ustaw
+        wykonanie polecenia 
+        <code class="code-inline">echo "Hello World" &gt; nazwa_terminala</code>
+        (za <em>nazwa_terminala</em> podstawiamy nazwę uzyskaną z polecenia
+        <em>tty</em>) za 3 minuty od bierzącego czasu. Zaczekaj na wykonanie
+        zadania.
+      </p>
+      <h2 id="ch8summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale zapoznaliśmy się z procesami, wyświetaliśmy ich listę
+        korzystaliśmy z polecenia <em>top</em>, zmienialiśmy ich priorytet
+        oraz zarządzaliśmy nimi za pomocą sygnałów. W drugiej części zajęliśmy
+        się narzędziami harmonogramu zadań. Nauczyliśmy się korzystać z takich
+        programów jak <em>at</em> czy <em>cron</em>. Na koniec poznaliśmy
+        specyficzny dla dystrybucji klasy <em>enterprise</em> demon 
+        <em>Anacron</em>. W następnym
+        rozdziale zapoznamy się podstawami zarządzania pakietami oprogramowania
+        na <em>RHEL</em>.
+      </p>
+      <h1 id="9.rpmbasics">9. Podstawy zarządzania pakietami oprogramowania</h1>
+      <p>
+        Pakiety inaczej zwane paczkami czy ogólnie oprogramowanie dystrybucji,
+        to archiwa przechowywujące zazwyczaj skompilowane oprogramowanie
+        przeznaczone dla systemu, który używamy. Wewnątrz pakietów znajduje się
+        cała strukturktura katalogowa z plikami pakietu, tak by podczas
+        instalacji wystarczyło je tylko rozpakować. Wewnątrz znajdują się 
+        również metadane zawierające informacje o pakiecie. 
+      </p>
+      <p>
+        Większość pakietów posiada długie nazwy, które nie są dokońca
+        rozumiałe. Weźmy na przykład taką nazwę jak:
+<pre class="code-block">
+openssl-1.1.1-8.el8.x86_64.rpm
+</pre>
+        Zawiera ona takie elementy jak:
+      </p>
+      <ul>
+        <li>Jednoznaczną nazwę oprogramowania pozwalającą, zidentyfikować
+          co to za program (<code class="code-inline">openssl</code>).</li>
+        <li>Numer wersji oprogramowania
+          (<code class="code-inline">1.1.1</code>).</li>
+        <li>Numer wydania (<code class="code-inline">8</code>).</li>
+        <li>Nazwę dystrybucji, rodziny dystrybucji itp. Ten element nie jest
+          obligatoryjny. Nie które dystrybucje włączają go do numeru wydania
+          (<code class="code-inline">el8</code>).
+        </li>
+        <li>Nazwa architektury dla jakiej zostało skompilowane oprogramowanie
+          (<code class="code-inline">x86-64</code>).</li> 
+        <li>Rozszerzenie (<code class="code-inline">.rpm</code>).</li>
+      </ul>
+      <p>
+        Kompilacja programów ze źródeł wymaga odpowiedniego środowiska (w ten
+        sposób tworzy się binarne wersje programów udostępnionych w pakietach).
+        Aby oprogramowanie z pakietu mogło działać tak samo, jak na w systemie,
+        w którym zostało skompilowane wymaga identycznego środowiska. To
+        środowisko jest przedstawiane za pomocą 
+        <strong>zależności pakietu</strong>, czyli wszystkich innych pakietów,
+        wymaganych do działania tego programu, który chcemy
+        zainstalować. Informacje o zależnościach znajdują się w metadanych
+        pakietu.
+      </p>
+      <p>
+        Systemy, w których dystrybucja oprogramowania jest oparta o pakiety 
+        musi
+        posiadać bazę danych pakietów. W przypadku <em>RHEL</em> znajduje się
+        ona w katalogu <em>/var/lib/rpm</em>. Na podstawie danych umieszczonych
+        w tym katalogu oprogramowanie do zarządzania pakietami pobiera
+        informacje o zainstalowanych w systemie pakietach. 
+      </p>
+      <p>
+        Aby móc zarządzać pakietami potrzebne są do tego odpowiednie
+        programy. <em>Red Hat</em> posiada takie polecenie jak 
+        <strong>rpm</strong> (ang. <em>Red Hat Packet Manager</em>) i jest to
+        podstawowe narzędzie do instalacji, aktualizacji, wyszukiwania
+        informacji czy usuwania oprogramowania z systemu. <em>Rpm</em> jest
+        bardzo prostym narzędziem jednak posiada jedną wadę, otóż
+        nie rozwiązuje samodzielnie zależności. Dlatego też pojawił
+        się taki program jak <strong>yum</strong>, który pełni takie same
+        role jak <em>rpm</em> jednak nie posiada wspomnianej wady. Od wersji
+        8 <em>RHEL</em>, <em>yum</em> został zastąpiony przez
+        <strong>dnf</strong>, który rozszerza funkcjonalność <em>yum</em>.
+        W tym rodziale zajmiemy się wyłącznie <em>rpm</em>. W następnym
+        zaś skupimy się na <em>dnf</em>.
+      </p>
+      <h2 id="9.1.rpm">9.1. Red Hat Packet Manager - RPM</h2>
+      <h3 id="9.1.1.gettinginfo">9.1.1. Pobieranie danych z pakietu</h3>
+      <p>
+        Jedną z podstawowych czynności jakie możemy wykonać przy użyciu tego 
+        narzędzia
+        jest pobieranie informacji o pakietach, za pomocą opcji <em>-q</em>
+        podając jako argument nazwę programu możemy dowiedzić się czy takowy
+        jest zainstalowany w systemie.
+      </p> 
+<pre class="code-inline">
+[user@server1 ~]$ rpm -q zsh
+package zsh is not installed
+[user@server1 ~]$ rpm -q bash
+bash-5.1.8-4.el9.x86_64
+</pre>
+      <p>
+        Pakiet <code class="code-inline">zsh</code> nie jest zainstalowany
+        w moim systemie. Natomiast drugie wywołanie potwierdza, że systemie
+        zainstalowano powłokę <em>BASH</em>. 
+      </p>
+      <p>
+        Z racji tego, iż <em>rpm</em> to nie tylko narzędzie ale i format
+        danych za pomocą tego polecenia, możemy wyświetlić pliki konfiguracyjne
+        programu (<em>-qc</em>), który zawiera pakiet czy pliki dokumentacji 
+        (<em>-qd</em>).
+      </p> 
+<pre class="code-inline">
+#Plik dokumentacji:
+[user@server1 ~]$ rpm -qd bash
+/usr/share/doc/bash/FAQ
+/usr/share/doc/bash/INTRO
+/usr/share/doc/bash/RBASH
+/usr/share/doc/bash/README
+/usr/share/doc/bash/bash.html
+/usr/share/doc/bash/bashref.html
+...
+
+#Pliki konfiguracji:
+[user@server1 ~]$ rpm -qc bash
+/etc/skel/.bash_logout
+/etc/skel/.bash_profile
+/etc/skel/.bashrc
+</pre>
+      <p>
+        Wszystkie pliki pakietu możemy wyświetlić za pomocą opcji <em>-ql</em>.
+        Generalnie opcja <em>-q</em>, jest modyfikatorem odpowiedzialnym za
+        pobieranie danych z bazy lub z samego pliku pakietu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -ql bash
+/etc/skel/.bash_logout
+/etc/skel/.bash_profile
+/etc/skel/.bashrc
+/usr/bin/alias
+/usr/bin/bash
+/usr/bin/bashbug
+/usr/bin/bashbug-64
+/usr/bin/bg
+/usr/bin/cd
+...
+</pre>
+      <p>
+        Za pomocą opcji <em>-qf</em> możemy wyszukać pakietu, z którego
+        pochodzi podany plik.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -qf /etc/bashrc
+setup-2.13.7-6.el9.noarch
+</pre>
+      <p>
+        Polecenie zwróci nazwę pakietu. Zwróćmy uwagę na to, że nazwy
+        zainstalowanych pakietów w <em>RHEL</em> różnią się od nazw plików
+        tym, że nie posidają rozszerzenia. Jeśli nie wiemy czym jest ten pakiet
+        przedstawiowny na poprzednim przykładzie za pomocą opcji <em>-qi</em>
+        możemy sprawdzić do czego służy. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -qi setup-2.13.7-6.el9.noarch
+Name        : setup
+Version     : 2.13.7
+Release     : 6.el9
+Architecture: noarch
+Install Date: Sun 26 Jun 2022 01:48:46 PM CEST
+Group       : System Environment/Base
+Size        : 726478
+License     : Public Domain
+Signature   : RSA/SHA256, Sat 20 Nov 2021 04:26:39 PM CET, Key ID 199e2f91fd431d51
+Source RPM  : setup-2.13.7-6.el9.src.rpm
+Build Date  : Tue 10 Aug 2021 06:16:15 PM CEST
+Build Host  : ppc64le-03.build.eng.rdu2.redhat.com
+Packager    : Red Hat, Inc. &lt;http://bugzilla.redhat.com/bugzilla&gt;
+Vendor      : Red Hat, Inc.
+URL         : https://pagure.io/setup/
+Summary     : A set of system configuration and setup files
+Description :
+The setup package contains a set of important system configuration and
+setup files, such as passwd, group, and profile.
+</pre>
+      <p>
+        Przed przejściem do kolejnego zaganienia musimy umieścić płytę
+        instalacjyną z <em>RHEL</em> w napędzie maszyny. Z niej będziemy
+        pobierać pakiety do dalszych ćwiczeń, gdyż nasze maszyny nie są
+        podłączone do sieci <em>Red Hat</em>. Po włożeniu płyty do napędu 
+        dodajmy poniższy wpis do
+        pliku <em>/etc/fstab</em>, aby płyta posiadała prosty i stały punkt
+        montowania. Na płycie znajdują się dwa katalogi <em>BaseOS/Packages</em>
+        oraz <em>AppStream/Packages</em>, gdzie znajdują się pakiety.
+      </p>
+<pre class="code-block">
+/dev/sr0  /mnt  iso9660 ro  0 0
+</pre>
+      <p>
+        Po zapisaniu zmian w pliku wywołujemy polecenie
+        <code class="code-inline">sudo mount -a</code>, aby zamontować płytę
+        w podkatalogu <em>/mnt</em>. Kiedy płyta jest już zamontowana w
+        systemie, możemy wyświetlić informacje z metadanych pliku pakietu za 
+        pomocą opcji <em>-qip</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -qip /mnt/BaseOS/Packages/bash-completion-2.11-4.el9.noarch.rpm 
+Name        : bash-completion
+Epoch       : 1
+Version     : 2.11
+Release     : 4.el9
+Architecture: noarch
+Install Date: (not installed)
+Group       : Unspecified
+Size        : 1057184
+License     : GPLv2+
+Signature   : RSA/SHA256, Sat 20 Nov 2021 11:52:53 AM CET, Key ID 199e2f91fd431d51
+Source RPM  : bash-completion-2.11-4.el9.src.rpm
+Build Date  : Mon 09 Aug 2021 09:47:13 PM CEST
+Build Host  : s390-070.build.eng.bos.redhat.com
+Packager    : Red Hat, Inc. &lt;http://bugzilla.redhat.com/bugzilla&gt;
+Vendor      : Red Hat, Inc.
+URL         : https://github.com/scop/bash-completion
+Summary     : Programmable completion for Bash
+Description :
+bash-completion is a collection of shell functions that take advantage
+of the programmable completion feature of bash.
+</pre>
+      <p>
+        Polecenie zwraca taką samą ilość informacji jak polecenie <em>rpm</em>
+        wraz z opcją <em>-qi</em>.
+      </p>
+      <h3 id="9.1.2.checkingpkgs">9.1.2. Sprawdzanie pakietów</h3>
+      <p>
+        Za pomocą jednego z programów związanych z <em>rpm</em> oraz za pomocą 
+        samego polecenia <em>rpm</em> możemy sprawdzić poprawność oraz
+        wiarygodność pakietów, które zamierzamy zainstalować, jak i sprawdzić
+        co zostało zmienione przez nas w plikach programów, które są już 
+        zainstalowane w systemie względem oryginalnego pakietu.
+      </p>
+      <p>
+        Walidację pakietu, który mamy zainstalować możemy przeprowadzić
+        względem dwóch kryteriów, jednym z nich jest poprawność plików
+        znajdujących się w pakiecie. Ta metoda polega na sprawdzeniu sumy
+        kontrolnej <em>MD5</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpmkeys -K /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm --nosignature
+/mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm: digests OK
+</pre>
+      <p>
+        Drugim kryterium jest wiarygodność. Każdy pakiet zawiera podpis
+        twórcy/dostawcy, w naszym przypadku jest to dostawca którym jest firma
+        <em>Red Hat</em>, ten podpis dokonywany jest za pomoca klucza 
+        kryptograficznego.
+        Część tego klucza odpowiedzialna za szyfrowanie danych jest instalowana
+        w naszym systemie i pozostaje do naszej dyspozycji. Poza omówią funkcją
+        ta część klucza może również pomoć nam sprawdzić czy pakiet który
+        pobraliśmy z internetu rzeczywiście został stworzony przez firmę
+        <em>Red Hat</em>, za nim zaczniemy używać klucza musimy go na początku
+        zaimportować, importu dokonujemy za pomocą polecenia poniżej, ścieżka
+        do klucza również znajduje się na przykładzie.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release 
+</pre>
+      <p>
+        Import klucza, jak i sprawdzenie
+        wiargodności pakietów wymaga uprawnień administratora.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpmkeys -K /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm
+/mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm: digests signatures OK
+</pre>
+      <p>
+        Teraz polecenie sprawdziło nie tylko poprawność plików 
+        (<code class="code-inline">digests</code>), ale także ich wiarygodność
+        (<code class="code-inline">signatures</code>).
+      </p>
+      <p>
+        Za pomocą polecenia <em>rpm</em> możemy sprawdzić
+        zainstalowane już pakiety
+        pod kątem zmian względem plików znajdujących w oryginalnym pakiecie.
+        Służy temu opcja <em>-V</em>, jeśli nie ma żadnych zmian to polecenie
+        nic nie zwróci. Możemy oczywiście zwiększyć ilość komunikatów
+        generowanych podczas pracy programu z pomocą opcji <em>-v</em>, wówczas
+        polecenie zwróci informacje na temat każdego sprawdzonego pliku pakietu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -V at
+[sudo] password for user: 
+.......T.  c /etc/at.deny
+</pre>
+      <p>
+        Informacja zwracana przez to polecenie składa się z trzech kolumn, w
+        pierwszej kolumnie znajdują się flagi, które mowią nam co uległo 
+        zmianie, każda z 9-ciu kropek to jedna flaga, w drugiej kolumnie 
+        znajdują się rodzaj pliku w tym przypadku 
+        <code class="code-inline">c</code>. Ostatnia kolumna zawiera ścieżkę
+        bezwzględną do pliku. Poniżej znajdują się listy z flagami oraz typami
+        plików. Kolejność na liście z flagami oznacza konkretną kropkę.
+      </p> 
+      <ol>
+        <li><strong>S</strong> - różnica w wielkości pliku,</li>
+        <li><strong>M</strong> - różnica w uprawnieniach,</li>
+        <li><strong>5</strong> - różnica w sumie kontrolnej pliku,</li>
+        <li><strong>D</strong> - różnica w numerze głównym i pobocznym 
+          urządzenia, urządzenie zostało zmienione,</li>
+        <li><strong>L</strong> - zmieniona ścieżka dowiązania symbolicznego,</li>
+        <li><strong>U</strong> - zmieniony właściciel pliku,</li>
+        <li><strong>G</strong> - zmieniona grupa pliku,</li>
+        <li><strong>T</strong> - różnica w czasie modyfikacji,</li>
+        <li><strong>P</strong> - różnica w <em>POSIX Capabilities</em></li>
+      </ol>
+      <p>
+        Kropka (<strong>.</strong>) oznacza brak zmian. Poniżej znajduje się
+        lista zawierająca typy plików. 
+      </p>
+      <ul>
+        <li><strong>c</strong> - <em>%config</em> - pliki konfiguracyjne,</li>
+        <li><strong>d</strong> - <em>%docs</em> - pliki dokumentacji,</li>
+        <li><strong>g</strong> - <em>%ghost</em> - pliki, których zawartość
+          nie znajduje się wewnątrz pakietu,</li> 
+        <li><strong>l</strong> - <em>%license</em> - pliki licencji,</li>
+        <li><strong>r</strong> - <em>%readme</em> - plik README.</li>
+      </ul>
+      <h3 id="9.1.3.installation">9.1.3. Instalacja i reinstalacja</h3>
+      <p>
+        Aby jak najlepiej wykorzystać polecenie <em>rpm</em> do instalacji
+        pakietów wykorzystuje się trzy opcje: <em>-i</em> - oznaczającą samą
+        instalacje pakietu, <em>-v</em> - zwiększającą ilość generowanych przez
+        polecenie komunikatów, <em>-h</em> - wyświetlająca pasek postępu w
+        postaci serii krzyżyków (<strong>#</strong>), po zapisaniu tych opcji
+        podajemy ścieżkę do pliku pakietu. Uwaga, tutaj pojawia się omawiana
+        wcześniej wada: brak rozwiązywania zależność, jeśli spróbujemy 
+        zainstalować jakiś pakiet, które zależności nie są rozwiązane
+        (spełnione), <em>rpm</em> nie podejmie w ogóle instalacji, zwraca
+        błąd o niespełnionych zależnościach. Na przykładzie poniżej znajduje
+        się instalacja powłoki <em>zsh</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -ivh /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm 
+[sudo] password for user: 
+Verifying...                          ################################# [100%]
+Preparing...                          ################################# [100%]
+Updating / installing...
+   1:zsh-5.8-9.el9                    ################################# [100%]
+</pre>
+      <p>
+        Teraz powłoka <em>zsh</em> jest zainstalowana w systemie. Pakiety
+        możemy również reinstalować podając po <em>-i</em> długą opcję
+        <em>--reinstall</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -i --reinstall -vh /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm 
+Verifying...                          ################################# [100%]
+Preparing...                          ################################# [100%]
+Updating / installing...
+   1:zsh-5.8-9.el9                    ################################# [ 50%]
+Cleaning up / removing...
+   2:zsh-5.8-9.el9                    ################################# [100%]
+</pre>
+      <h3 id="9.1.4.updates">9.1.4. Aktualizacje pakietów</h3>
+      <p>
+        Aktualizacji pakietu możemy dokonać na dwa sposoby, pierwszym z nich
+        jest aktualizacja przy użyciu opcji <em>-U</em>,
+        jeśli podany pakiet nie istnieje w systemie to zostanie on
+        automatycznie zainstalowany. Opcji <em>-U</em> używa się wraz innymi
+        opcjami instalacji <em>-v</em> oraz <em>-h</em>. Spróbujemy
+        zaktualizować naszą powłokę <em>zsh</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -Uvh /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm 
+[sudo] password for user: 
+Verifying...                          ################################# [100%]
+Preparing...                          ################################# [100%]
+       package zsh-5.8-9.el9.x86_64 is already installed
+</pre>
+      <p>
+        W tym przykładzie użyłem tej samego pakietu do aktualizacji, co 
+        wygerowało monit o tym, że taki pakiet jest już zainstalowany w
+        systemie.
+      </p>
+      <p>
+        Inną opcją aktualizacji jest odświerzenie (ang. <em>freshening</em>),
+        ta metoda wymaga aby pakiet w starszej wersji był już zainstalowany
+        w systemie. Odświerzenie wymaga opcji <em>-F</em> i używa się jej
+        wraz z pozostałymi opcjami wymienionymi podczas instalacji oraz 
+        aktualizacji.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -Fvh /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm 
+[sudo] password for user: 
+</pre>
+      <p>
+        Polecenie nie zrobiło nic poniważ podałem ten sam pakiet, które jest
+        już zainstalowany.
+      </p>
+      <h3 id="9.1.5.erasing">9.1.5. Usuwanie pakietów</h3>
+      <p>
+        Do usuwania pakietów z systemu służy opcja <em>-e</em>, używa się jej
+        wraz z opcją <em>-v</em>, aby polecenie zróciło chociaż jakiś komunikat, 
+        po usunięciu pakietu. Poniżej znajdują się polecenia pokazujące 
+        usunięcie pakietu z systemu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -q zsh
+zsh-5.8-9.el9.x86_64
+[user@server1 ~]$ sudo rpm -ev zsh
+Preparing packages...
+zsh-5.8-9.el9.x86_64
+[user@server1 ~]$ rpm -q zsh
+package zsh is not installed
+</pre>
+      <p>
+        Na podstawie informacji zwracanej przez ostatnie polecenie możemy
+        wywnioskować, iż pakiet został usunięty.
+      </p>
+      <h3 id="9.1.6.miscs">9.1.6. Pozostałe czynności wykonywane na pakietach.</h3>
+      <p>
+        Do pozostałych czynności jakie możemy wykonać zaliczamy
+        <strong>nadpisanie pakietu</strong>. Jeśli podejrzewany, że mogły
+        wystąpić błędy podczas instalacji możemy nadpisać pakiety dodając do 
+        opcji instalacji długą opcję <em>--replacepkgs</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo rpm -ivh --replacepkgs /mnt/BaseOS/Packages/zsh-5.8-9.el9.x86_64.rpm 
+[sudo] password for user: 
+Verifying...                          ################################# [100%]
+Preparing...                          ################################# [100%]
+Updating / installing...
+   1:zsh-5.8-9.el9                    ################################# [100%]
+</pre>
+      <p>
+        Wynik działania nadpisania jest identyczny jak w przypadku instalacji.
+      </p>
+      <p>
+        Czasami może się zdarzyć taka potrzeba, aby wyodrębnić jeden z plików
+        znajdujących wewnątrz pakietu, możemy wówczas taki pakiet rozpakować
+        do katalogu, a następnie przekopiować interesujące nas pliki.
+        Załóżmy że potrzebujemy pliku <em>/etc/bashrc</em>. Za pomocą opcji
+        <em>-qf</em> możemy ustalić z jakiego pakietu pochodzi.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ rpm -qf /etc/bashrc
+setup-2.13.7-6.el9.noarch
+</pre>
+      <p>
+        Pobieramy plik z internetu lub możemy załadować go z płyty. Do 
+        polecenia
+        <strong>rpm2cpio</strong> podajemy ścieżkę do pliku, następnie wyjście 
+        polecenia przekierowujemy
+        za pomocą potoku do polecenia <strong>cpio</strong> z następującymi
+        opcjami <em>-i</em> (wypakuj), <em>-m</em> (zachowaj oryginalny
+        czas modyfikacji plików), <em>-d</em> (utwórz katalogi poprzedzające
+        pliki). Takie wypakowanie nalepiej jest zrobić w odrębnym katalogu
+        na przykład w <em>/tmp</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ mkdir /tmp/setup.rpm
+[user@server1 ~]$ cd /tmp/setup.rpm/
+[user@server1 setup.rpm]$ rpm2cpio /mnt/BaseOS/Packages/setup-2.13.7-6.el9.noarch.rpm | cpio -imd
+1430 blocks
+[user@server1 setup.rpm]$ ls
+etc  run  usr
+[user@server1 setup.rpm]$ ls -l etc/bashrc 
+-rw-r--r--. 1 user user 3019 Jun 23  2020 etc/bashrc
+</pre>
+      <p>
+        Teraz możemy przekopować potrzebny nam pliki.
+      </p>
+      <h3 id="exec9.1">Ćwiczenie 1: Instalacja pakietu zsh</h3>
+      <p>
+        Na maszynie <em>server1</em>, jak użytkownik z mozliwością podniesienia
+        uprawnień zamontuj płytę/obraz płyty w systemie. Za pomocą polecenia
+        <em>rpm</em> wyświetl informacje (podstawowe) o pakiecie <em>zsh</em>,
+        sprawdź jego poprawność oraz wiarygodność, a następnie zainstaluj go
+        w systemie. Na koniec sprawdź czy występują jakieś róznice między 
+        plikami zainstalowanymi, a plikami oryginalnymi występującymi w
+        pakiecie.
+      </p>
+      <h3 id="exec9.2">Ćwiczenie 2: Pobieranie informacji oraz usunięcie pakietu</h3>
+      <p>
+        Na maszynie <em>server1</em>, jak użytkownik z mozliwością podniesienia
+        uprawnień zamontuj płytę/obraz płyty w systemie. Za pomocą polecenia
+        <em>rpm</em> sprawdzić czy zainstalowany jest pakiet <em>setup</em> i
+        wyświetl jego pliki konfiguracyjne. Wyświetl informacje na temat
+        pakietu <em>zlib-devel</em> znajdującego się na obrazie płyty.
+        Zainstaluj ponownie pakiet <em>zsh</em> a następnie go usuń.
+      </p>
+      <h2 id="ch9summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale zapoznaliśmy się z pojęciem pakietu oprogramowania oraz
+        z podstawowymi metodami na zarządzanie nim w <em>RHEL</em> w praktyce.
+        Dowiedzieliśmy się jak instalować, usuwać oraz wydobywać informacje o
+        i z pakietów. W następnym rodziale zajmiemy się bardziej zaawansowanym
+        zarządzeniem pakietami przy użyciu polecenia <strong>dnf</strong>.
+      </p>
+      <h1 id="10.advancedpackagemanagement">10. Zaawansowane zarządzanie pakietami.</h1>
+      <p>
+        W poprzednim rozdziale zapoznaliśmy się z podstawą zarządania pakietami
+        jaka nie wątpliwie jest program <em>rpm</em>. Jego główną wadą jest to,
+        iż nie rozwiązuje on zależności instalowanych pakietów. Z tego powodu
+        potrzebne było lepsze narzędzie do obsługi oprogramowania w systemie,
+        dlatego też twórcy <em>RHEL</em> wdrożyli program <em>yum</em>, który 
+        przez
+        lata sprawdzał się postaci menedżera pakietów, a od wersji 8 
+        <em>Red Hat Enterprise Linux</em> został on zastąpiony programem 
+        <strong>dnf</strong>,
+        który ma nieco większe możliwości. Zanim przejdziemy do zarządzania
+        pakietami, trochę teorii.
+      </p>
+      <p>
+        <em>Dnf</em> wprowadza do zarządzania pakietami takie pojęcia jak
+        <strong>grupy pakietów</strong> - są tematyczne grupy aplikacji,
+        którymi możemy wzbogacić nasz system. Powiedzmy, że potrzebujemy w
+        systemie obsługi kart inteligentnych to zamiast szukać odpowiednich
+        pakietów, możemy zainstalować wszystkie niezbędne programy podając
+        poleceniu <em>dnf</em> nazwę grupy.
+      </p>
+      <p>
+        Wraz z <em>dnf</em> pojawiają się takie pojęcia jak
+        <strong>moduł aplikacji</strong> oraz <strong>strumień aplikacji</strong>.
+        Moduł aplikacji, to podobnie do grupy jest zbiór pakietów, ale
+        odpowiedzialnych za jedną aplikację. W module zawarte są wszystkie
+        pakiety odpowiedzialne za działanie aplikacji, poza zależnościami mogą
+        znajdować się tam także biblioteki, generalnie całe środowisko. Moduły
+        posiadają swoje strumienie, czyli konkretne wersje pakietów aplikacji, 
+        które dostarczają. W systemie może być zainstalowany tylko jeden
+        strumień danej aplikacji. Między strumieniami można się przełączać.
+        będziemy to omawiać pod koniec tego rozdziału. Moduły w
+        strumieniach posiadają jeszcze <strong>profile</strong>. Profile są
+        to zbiory pakietów, programów określanych przez moduł zbudowane z 
+        myślą o przeznaczeniu aplikacji. Na przykład systemy bazodanowe mogą
+        posiadać pakiety przeznaczone dla serwera oraz dla klienta. Jeśli baza
+        danych znajduje się na innym serwerze niż aplikacja, która z niej
+        korzysta, to w systemie aplikacji nie ma sensu instalować wszystkich
+        pakietów związanych z cała bazą wystarczą pakiety, które będą
+        udostępniać tylko i wyłącznie możliwość połączenia się z bazą.
+      </p>
+      <p>
+        RHEL w wersji 8 dzieli również repozytorium (bazę pakietów) na dwie
+        części. Piewsza część <strong>BaseOS</strong>, zawiera jak sama nazwa
+        wskazuje pakiety bazowe, które zawierają większość pakietów 
+        niezbędnych do działania systemu operacyjnego. Druga część
+        <strong>AppStream</strong> zawiera wszystkie dodatkowe aplikacje. Tego
+        rodzaju podział został wprowadzony z względu na to, że w momencie 
+        przezprowadzania aktualizacji systemu, aktualizowane było również
+        zainstalowane na nim oprogramowanie co mogło nie być porządane i
+        wprowadzać nie potrzebne zamieszanie lub destabilizować cały systemu.
+      </p>
+      <p>
+        Kolejną rzeczą wartą wspomnienia są repozytoria. Nasze systemy, których
+        używamy do wypróbowywania przykładów oraz do rozwiązywania ćwiczeń, nie
+        są zarejestrowane na naszych kontach <em>Red Hat</em>. Rejestracja 
+        systemu daje
+        możliwość aktualizacji pakietów zawartych na płytach oraz instalowania
+        ich bezpośrednio z sieci. Oprócz repozytoriów firmy Red Hat mamy
+        rownież inne repozytoria dostępne w sieci. Takie jak na przykład
+        <em>RPM Fusion</em>. Bez tych repozytoriów korzystanie z 
+        <em>RHEL</em> 9 w
+        codziennym użyciu na desktopie nie miało by sensu. Przynajmniej w moim
+        wypadku ;). Konfigurację repozytoriów przeprowadza się zapisując je
+        w pliku w katalogu <em>/etc/yum.repos.d</em>, w jednym pliku może
+        znajdować się kilka repozytoriów, sposób organizacji zależy od nas.
+      </p>
+      <p>
+        Na koniec, kilka spraw organizacyjnych. W <em>RHEL</em> 9 poki co 
+        brakuje
+        modułów. W tym odnośniku znajduje się dowód, że na moduły przyjdzie na
+        poczekać do wersji 9.1. <a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/managing_software_with_the_dnf_tool/index#con_modules_assembly_distribution-of-content-in-rhel-9">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/managing_software_with_the_dnf_tool/index#con_modules_assembly_distribution-of-content-in-rhel-9</a>
+        Tak więc wszystkie przykłady jakie będę wykonywać w tym rodziale będą
+        realizowane za pomocą <em>Red Hat Enterprise Linux</em> w wersji 8.6. Po
+        zarejestrowaniu się możemy pobrać <em>RHEL</em> aż do wersji 8.0. Także możemy
+        stworzyć środowisko maszyny <em>server1</em> na podstawie 
+        <em>RHEL</em> 8.
+      </p>
+      <h2 id="10.1.repoconfig">10.1. Konfiguracja repozytorium dnf</h2>
+      <p>
+        Jak już wspomniałem repozytorium konfigurujemy za pomocą plików
+        złożonych w katalogu <em>/etc/yum.repos.d</em>. Na początku jednak
+        musimy dodać płytę do pliku <em>/etc/fstab</em>. Opisywałem ten proces
+        na początku 9 rozdziału o <a href="#9.1.1.gettinginfo">tutaj</a>.
+        Dlatego też w przykładach przyjmę iż płyta jest montowana w podkatalogu
+        <em>/mnt</em>. Jak pamiętamy z poprzedniego rozdziału na płycie
+        znajdują się dwa katalogi z pakietami: <em>BaseOS/Packages</em> oraz
+        <em>AppStream/Packages</em>. W konfiguracji podajemy tylko te pierwsze
+        człony tych ścieżek, ponieważ w niej wskazujemy katalog bazowy.
+        Konfiguracja każdego z repozytorium wymaga minimum 4 wierszy. Poniższy
+        przykład przedstawia zawartość pliku konfiguracjynego repozytoriów z
+        płyty instalacjynej <em>RHEL</em> 8.
+      </p>
+<pre class="code-block">
+[BaseOS]
+name=BaseOS
+baseurl=file:///mnt/BaseOS
+gpgcheck=0
+
+[AppStream]
+name=AppStream
+baseurl=file:///mnt/AppStream
+gpgcheck=0
+</pre>
+      <p>
+        W nawiasach kwadratowych znajdują się unikatowe identyfikatory 
+        repozytoriów (<code class="code-inline">[BaseOS]</code>), następnie
+        dyrektywa <code class="code-inline">name</code> zawiera ich opisy
+        w przypadku środowisk testowych nie musimy się wysilać z opisami czy
+        sprawdzać autentyczności pakietów przy użyciu <em>GPG</em>
+        (<code class="code-inline">gpgcheck=0</code>). Wyłączenie sprawdzania
+        pakietów usprawni proces ich instalacji, w przeciwym razie za
+        każdą czynnością opartą o repozytorium otrzymywalibyśmy monit. Istotną
+        funkcję pełni tym
+        przypadku dyrektywa <code class="code-inline">baseurl</code>, która
+        wskazuje na miejsce przechowywania pakietów, tym przypadku jest katalog
+        zatem protokołem poprzedzającym ścieżkę będzie
+        <code class="code-inline">file</code>, jak w każdym adresie <em>URL</em>
+        następuje <code class="code-inline">://</code>, a następnie
+        (w tym przypadku) bezwzględna ścieżka do katalogu.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Umiejętnośc konfigurowania repozytoriów <em>yum</em>/<em>dnf</em> z
+        wykorzystaniem <em>URL</em> może być istotna do wykonania pewnych
+        zadań egzaminacyjnych. Konstruując <em>URL</em> możemy użyć takich
+        protokołów jak FTP, HTTP czy HTTPS (zapis w <em>URL</em> zawsze małymi 
+        literami) po czym następuje dwukropek z dwoma slashami <em>://</em>
+        a następnie adres repozytorium. 
+      </p>
+      <p>
+        Po zdefiniowaniu repozytoriów zapisujemy zmiany w pliku. Aby
+        zweryfikować poprawność konfiguracji wydajemy polecenie, które
+        odświerza pamięć podręczną pakietów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf makecache
+[sudo] password for user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+This system is not registered with an entitlement server. You can use 
+subscription-manager to register.
+BaseOS                                              1.6 MB/s | 2.7 kB     00:00    
+AppStream                                           2.3 MB/s | 2.8 kB     00:00 
+Metadata cache created.
+</pre>
+      <p>
+        Metadane zostały załadowane do pamięci podręcznej. Za pomocą poniższego
+        polecenia możemy wyświetlić informacje na temat zdefiniowanych w naszym
+        systemie repozytoriów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 mnt]$ sudo dnf repoinfo -v
+...
+DNF version: 4.7.0
+cachedir: /var/cache/dnf
+Ostatnio sprawdzono ważność metadanych: 0:00:20 temu w dniu nie, 10 lip 2022, 22:51:36.
+Identyfikator repozytorium        : AppStream
+Nazwa repozytorium                : AppStream
+Wersja repozytorium               : 1650471026
+Aktualizacje repozytorium         : śro, 20 kwi 2022, 18:10:27
+Pakiety repozytorium              : 6 609
+Dostępne pakiety repozytorium     : 5 345
+Rozmiar repozytorium              : 8.6 G
+Podstawowy adres URL repozytorium : file:///mnt/AppStream
+Wygaszenie repozytorium           : 172 800 s (ostatnio: nie, 10 lip 2022, 22:51:36)
+Nazwa pliku repozytorium          : /etc/yum.repos.d/local.repo
+
+Identyfikator repozytorium        : BaseOS
+Nazwa repozytorium                : BaseOS
+Wersja repozytorium               : 1650471057
+Aktualizacje repozytorium         : śro, 20 kwi 2022, 18:10:59
+Pakiety repozytorium              : 1 714
+Dostępne pakiety repozytorium     : 1 712
+Rozmiar repozytorium              : 1.3 G
+Podstawowy adres URL repozytorium : file:///mnt/BaseOS
+Wygaszenie repozytorium           : 172 800 s (ostatnio: nie, 10 lip 2022, 22:51:34)
+Nazwa pliku repozytorium          : /etc/yum.repos.d/local.repo
+Razem pakietów: 8 323
+</pre>
+      <p>
+        Tak zdefiniowanych repozytoriów będziemy używać w przykładach oraz
+        do rozwiązywania zadań w ćwiczeniach.
+      </p>
+      <h2 id="10.2.individualpackagemgmnt">10.2. Zarządzanie pojedynczymi pakietami</h2>
+      <p>
+        Program <em>dnf</em> jest stanie wykonywać identyczne czynności jak
+        polecenie <em>rpm</em>. Z racji tego, iż skonfigurowaliśmy wcześniej
+        repozytorium nie musimy podawać żadnych ścieżek wystarczy nazwa
+        pakietu, a ją możemy poznać wyświetlając listy pakietów.
+      </p>
+      <h3 id="10.2.1.listofpackages">10.2.1. Listy pakietów</h3>
+      <p>
+        Z pomocą
+        poniższego polecenia możemy wyświetlić listę wszystkich pakietów.
+        Domyślnie lista pakietów jest podzielona na dwie części: zainstalowane
+        oraz dostępne pakiety.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf list
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. 
+You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 9:22:00 temu w dniu nie, 10 lip 2022, 22:51:36.
+Zainstalowane pakiety
+GConf2.x86_64                  3.2.6-22.el8                           @AppStream
+ModemManager.x86_64            1.18.2-1.el8                           @anaconda 
+ModemManager-glib.x86_64       1.18.2-1.el8                           @anaconda 
+NetworkManager.x86_64          1:1.36.0-4.el8                         @anaconda 
+NetworkManager-adsl.x86_64     1:1.36.0-4.el8                         @anaconda 
+NetworkManager-bluetooth.x86_64
+                               1:1.36.0-4.el8                         @anaconda 
+NetworkManager-config-server.noarch
+                               1:1.36.0-4.el8                         @anaconda 
+NetworkManager-libnm.x86_64    1:1.36.0-4.el8                         @anaconda 
+NetworkManager-team.x86_64     1:1.36.0-4.el8                         @anaconda 
+NetworkManager-tui.x86_64      1:1.36.0-4.el8                         @anaconda 
+NetworkManager-wifi.x86_64     1:1.36.0-4.el8                         @anaconda 
+NetworkManager-wwan.x86_64     1:1.36.0-4.el8                         @anaconda
+...
+Dostępne pakiety
+CUnit.i686                     2.1.3-17.el8                           AppStream 
+CUnit.x86_64                   2.1.3-17.el8                           AppStream 
+GConf2.i686                    3.2.6-22.el8                           AppStream 
+HdrHistogram.noarch            2.1.11-3.module+el8.5.0+12798+cbad756b AppStream 
+HdrHistogram-javadoc.noarch    2.1.11-3.module+el8.5.0+12798+cbad756b AppStream 
+HdrHistogram_c.i686            0.9.13-2.el8                           AppStream 
+HdrHistogram_c.x86_64          0.9.13-2.el8                           AppStream 
+Judy.x86_64                    1.0.5-18.module+el8+2765+cfa4f87b      AppStream 
+LibRaw.i686                    0.19.5-3.el8                           AppStream 
+LibRaw.x86_64                  0.19.5-3.el8                           AppStream 
+ModemManager-glib.i686         1.18.2-1.el8                           BaseOS    
+NetworkManager-cloud-setup.x86_64
+                               1:1.36.0-4.el8                         AppStream 
+NetworkManager-config-connectivity-redhat.noarch
+                               1:1.36.0-4.el8                         BaseOS    
+NetworkManager-dispatcher-routing-rules.noarch
+</pre>
+      <p>
+        Ilość wyświetlonych pakietów możemy zmniejszyć za pomocą odpowiednich
+        opcji, wyświetlając tylko listę pakietów zainstalowanych
+        (<em>--installed</em>) lub listę pakietów dostępnych
+        (<em>--available</em>).
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf list --installed
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. 
+You can use subscription-manager to register.
+
+Zainstalowane pakiety
+GConf2.x86_64                              3.2.6-22.el8               @AppStream
+ModemManager.x86_64                        1.18.2-1.el8               @anaconda 
+ModemManager-glib.x86_64                   1.18.2-1.el8               @anaconda 
+NetworkManager.x86_64                      1:1.36.0-4.el8             @anaconda 
+NetworkManager-adsl.x86_64                 1:1.36.0-4.el8             @anaconda 
+NetworkManager-bluetooth.x86_64            1:1.36.0-4.el8             @anaconda 
+NetworkManager-config-server.noarch        1:1.36.0-4.el8             @anaconda 
+NetworkManager-libnm.x86_64                1:1.36.0-4.el8             @anaconda 
+
+[user@rhel8-vm1 ~]$ sudo dnf list --available
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. 
+You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 9:33:18 temu w dniu nie, 10 lip 2022, 22:51:36.
+Dostępne pakiety
+CUnit.i686                     2.1.3-17.el8                            AppStream
+CUnit.x86_64                   2.1.3-17.el8                            AppStream
+GConf2.i686                    3.2.6-22.el8                            AppStream
+HdrHistogram.noarch            2.1.11-3.module+el8.5.0+12798+cbad756b  AppStream
+HdrHistogram-javadoc.noarch    2.1.11-3.module+el8.5.0+12798+cbad756b  AppStream
+HdrHistogram_c.i686            0.9.13-2.el8                            AppStream
+HdrHistogram_c.x86_64          0.9.13-2.el8                            AppStream
+Judy.x86_64                    1.0.5-18.module+el8+2765+cfa4f87b       AppStream
+LibRaw.i686                    0.19.5-3.el8                            AppStream
+LibRaw.x86_64                  0.19.5-3.el8                            AppStream
+ModemManager-glib.i686         1.18.2-1.el8                            BaseOS   
+</pre>
+      <p>
+        Listy są podzielone na trzy kolumny w pierwsze z nich znajduje się
+        nazwa pakietu, w drugie wersja, a w trzeciej nazwa repozytorium, które
+        zawiera ten pakiet lub z które został on zainstalowany. W przypadku
+        wartości <code class="code-inline">@anaconda</code>, są to pakiety
+        zainstalowane podczas instalacji systemu, w przypadku pakietów 
+        instalowanych
+        za pomocą polecenia <em>rpm</em> w trzeciej kolumnie będzie widnieć
+        napis <em>@System</em>.
+      </p> 
+      <p>
+        Przydatną opcją jeśli korzystamy z repozytoriów sieciowych może być
+        <em>updates</em> wydawane po podpoleceniu <em>list</em>. W <em>dnf</em>
+        opcje często posiadają formę podpoleceń, natomiast to co my możemy
+        uważać za opcję jest modyfikatorem. Podpolecenie <em>updates</em>
+        wyświetla pakiety możliwe do zaktualizowania.
+      </p>
+      <h3 id="10.2.2.repoqueries">10.2.2. Zapytania do repozytorium</h3>
+      <p>
+        <em>Dnf</em> w przeciwieństwie do <em>rpm</em> pozwala nam przeszukiwać
+        repozytorium pod względem występowania na przykład pakietu lub możemy
+        podać ścieżkę do pliku znajdującego się w systemie a program zwrócić
+        nam informacje z jakiego pakietu pochodzi. 
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf repoquery zsh
+[sudo] hasło użytkownika user: 
+
+Ostatnio sprawdzono ważność metadanych: 0:03:42 temu w dniu pon, 11 lip 2022, 08:36:18.
+zsh-0:5.5.1-9.el8.x86_64
+
+[user@rhel8-vm1 ~]$ sudo dnf repoquery /etc/bashrc
+Ostatnio sprawdzono ważność metadanych: 0:04:02 temu w dniu pon, 11 lip 2022, 08:36:18.
+setup-0:2.12.2-6.el8.noarch
+</pre>
+      <p>
+        Podpolecenie <em>repoquery</em> pozwala na sprecyzowanie repozytorium,
+        do którego będą kierowane zapytania, za pomocą opcji <em>--repo</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf repoquery --repo BaseOS zsh
+Ostatnio sprawdzono ważność metadanych: 0:16:51 temu w dniu pon, 11 lip 2022, 08:36:18.
+zsh-0:5.5.1-9.el8.x86_64
+</pre>
+      <p>
+        Podpolecenie <em>repoquery</em> posiada całą masę modyfikatorów dzięki
+        nim możemy na przykład sprawdzić zależności pakietów. Aby ujawnić 
+        listę modyfikatorów możemy użyć podpolecenia <em>repoquery</em> wraz z
+        <em>--help</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf repoquery --help
+Repoquery command-specific options:
+  -a, --all             Odpytuje wszystkie pakiety (skrót do „repoquery '*'”
+                        lub repoquery bez parametru)
+  --show-duplicates     Odpytuje wszystkie wersje pakietów (domyślnie)
+  --arch [arch], --archlist [arch]
+                        wyświetla tylko wyniki dla tej ARCHITEKTURY
+  -f FILE [FILE ...], --file FILE [FILE ...]
+                        wyświetla tylko wyniki posiadające PLIK
+...
+</pre>
+      <h3 id="10.2.3.info">10.2.3. Pobieranie informacji o pakietach</h3>
+      <p>
+        Polecenie <em>dnf</em> pozwala uzyskać informacje na temat pakietu.
+        Za pomocą podpolecenia <em>info</em> możemy pobrać informacje o 
+        na przykład wersji, numerze wydania, rozmiarze czy repozytorium w
+        jakim jest przechowywane.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf info php
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:40:02 temu w dniu pon, 11 lip 2022, 08:36:18.
+Dostępne pakiety
+Nazwa        : php
+Wersja       : 7.2.24
+Wydanie      : 1.module+el8.2.0+4601+7c76a223
+Architektura : x86_64
+Rozmiar      : 1.5 M
+Źródło       : php-7.2.24-1.module+el8.2.0+4601+7c76a223.src.rpm
+Repozytorium : AppStream
+Podsumowanie : PHP scripting language for creating dynamic web sites
+Adres URL    : http://www.php.net/
+Licencja     : PHP and Zend and BSD and MIT and ASL 1.0
+Opis         : PHP is an HTML-embedded scripting language. PHP attempts to make
+             : it easy for developers to write dynamically generated web pages.
+             : PHP also offers built-in database integration for several
+             : commercial and non-commercial database management systems, so
+             : writing a database-enabled webpage with PHP is fairly simple. The
+             : most common use of PHP coding is probably as a replacement for
+             : CGI scripts.
+             : 
+             : The php package contains the module (often referred to as
+             : mod_php) which adds support for the PHP language to Apache HTTP
+             : Server.
+</pre>
+      <p>
+        Teraz kiedy wiemy jak możemy uzyskać informacje na temat interesujących
+        nas pakietów możemy przejść do podstawowych czynności z nimi 
+        związanych, czyli: instalacji, aktualizacji oraz usuwania.
+      </p>
+      <h3 id="10.2.4.installpackage">10.2.4. Instalacja pakietów</h3>
+      <p>
+        Instalacja pakietów jest banalnie prosta w przypadku narzędzia <em>dnf</em>
+        wymaga ona użycia podpolecenia <strong>install</strong> a następnie
+        podania nazwy pakietu. 
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf install mc
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:07:02 temu w dniu pon, 11 lip 2022, 08:36:18.
+Rozwiązano zależności.
+================================================================================
+ Pakiet      Architektura    Wersja                    Repozytorium       Rozm.
+================================================================================
+Instalowanie:
+ mc          x86_64          1:4.8.19-9.el8            AppStream          1.9 M
+
+Podsumowanie transakcji
+================================================================================
+Instalacja  1 pakiet
+
+Całkowity rozmiar: 1.9 M
+Rozmiar po zainstalowaniu: 6.8 M
+W porządku? [t/N]: 
+...
+</pre> 
+      <p>
+        Program wyświetli w tabeli wszystkie instalowane pakiety, 
+        następnie całkowity rozmiar pobieranych pakietów 
+        oraz ilość miejsca na dysku zabranego na potrzeby instalacji.
+        Po zapoznaniu
+        się z tym możemy potwierdzić za pomocą <em>t</em> (w polskiej wersji
+        językowej) lub <em>y</em> lub przerwać na przykład naciskając Enter,
+        ponieważ opcja <em>N</em> (nie, <em>no</em>) jest domyślna. Po
+        zatwierdzeniu pakietów rozpocznie się ich pobieranie oraz instalacja.
+      </p>
+<pre class="code-block">
+...
+Pobieranie pakietów:
+Wykonywanie sprawdzania transakcji
+Pomyślnie ukończono sprawdzanie transakcji.
+Wykonywanie testu transakcji
+Pomyślnie ukończono test transakcji.
+Wykonywanie transakcji
+  Przygotowywanie                :                                          1/1 
+  Instalowanie                   : mc-1:4.8.19-9.el8.x86_64                 1/1 
+  Wykonywanie skryptu            : mc-1:4.8.19-9.el8.x86_64                 1/1 
+  Sprawdzanie                    : mc-1:4.8.19-9.el8.x86_64                 1/1 
+Installed products updated.
+
+Zainstalowano:
+  mc-1:4.8.19-9.el8.x86_64                                                      
+
+Ukończono.
+</pre>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf list --installed mc
+[sudo] hasło użytkownika user: 
+
+Zainstalowane pakiety
+mc.x86_64                       1:4.8.19-9.el8                        @AppStream
+</pre> 
+      <p>
+        <em>Dnf</em> daje nam możliwość przeprowadzanie lokalnej instalacji
+        podając ścieżkę do pliku <em>.rpm</em>. Ta czynność wymaga użycia
+        podpolecenia <em>localinstall</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf localinstall /mnt/AppStream/Packages/dcraw-9.27.0-9.el8.x86_64.rpm 
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:23:58 temu w dniu pon, 11 lip 2022, 08:36:18.
+Rozwiązano zależności.
+================================================================================
+ Pakiet        Architektura   Wersja                 Repozytorium         Rozm.
+================================================================================
+Instalowanie:
+ dcraw         x86_64         9.27.0-9.el8           @commandline         267 k
+
+Podsumowanie transakcji
+================================================================================
+Instalacja  1 pakiet
+
+Całkowity rozmiar: 267 k
+Rozmiar po zainstalowaniu: 548 k
+W porządku? [t/N]: t 
+Pobieranie pakietów:
+Wykonywanie sprawdzania transakcji
+Pomyślnie ukończono sprawdzanie transakcji.
+Wykonywanie testu transakcji
+Pomyślnie ukończono test transakcji.
+Wykonywanie transakcji
+  Przygotowywanie                :                                          1/1 
+  Instalowanie                   : dcraw-9.27.0-9.el8.x86_64                1/1 
+  Wykonywanie skryptu            : dcraw-9.27.0-9.el8.x86_64                1/1 
+  Sprawdzanie                    : dcraw-9.27.0-9.el8.x86_64                1/1 
+Installed products updated.
+
+Zainstalowano:
+  dcraw-9.27.0-9.el8.x86_64                                                     
+
+Ukończono.
+</pre>
+      <h3 id="10.2.5.updatepackages">10.2.5. Aktualizacje pakietów</h3>
+      <p>
+        Aktualizacja pakietów za pomocą <em>dnf</em> wymaga użycia podpolecenia
+        <em>update</em>. Aktualizacje pojedynczych pakietów przeprowadzamy 
+        podając
+        ich nazwę po podpoleceniu. Ta funkcjonalność wymaga jednak aby pakiet
+        był już zainstalowany w systemie. Jeśli wydamy to podpolecenie bez
+        żadnego argumentu polecenie sprawdzi wszystkie zainstalowane pakiety
+        w systemie, czy występują dla nich jakieś aktualizacje następnie
+        spyta czy je zainstalować.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf update autofs
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:34:19 temu w dniu pon, 11 lip 2022, 08:36:18.
+Pakiet autofs jest dostępny, ale nie jest zainstalowany.
+Brak wyników dla parametru: autofs
+Błąd: Brak pakietów oznaczonych do aktualizacji.
+
+[user@rhel8-vm1 ~]$ sudo dnf update
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:38:26 temu w dniu pon, 11 lip 2022, 08:36:18.
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+</pre>
+      <h3 id="10.2.6.removepackages">10.2.6. Usuwanie pakietów</h3>
+      <p>
+        Usuwanie pakietów w przypadku <em>dnf</em> wymaga użycia podpolecenia
+        <em>remove</em>. Polecenie usunie zainstalowany pakiet z systemu wraz
+        ze wszystkimi jego plikami.
+      </p> 
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf remove mc
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Rozwiązano zależności.
+================================================================================
+ Pakiet      Architektura    Wersja                   Repozytorium        Rozm.
+================================================================================
+Usuwanie:
+ mc          x86_64          1:4.8.19-9.el8           @AppStream          6.8 M
+
+Podsumowanie transakcji
+================================================================================
+Usunięcie  1 pakiet
+
+Zwolnione miejsce: 6.8 M
+W porządku? [t/N]: t
+Wykonywanie sprawdzania transakcji
+Pomyślnie ukończono sprawdzanie transakcji.
+Wykonywanie testu transakcji
+Pomyślnie ukończono test transakcji.
+Wykonywanie transakcji
+  Przygotowywanie                :                                          1/1 
+  Usuwanie                       : mc-1:4.8.19-9.el8.x86_64                 1/1 
+  Wykonywanie skryptu            : mc-1:4.8.19-9.el8.x86_64                 1/1 
+  Sprawdzanie                    : mc-1:4.8.19-9.el8.x86_64                 1/1 
+Installed products updated.
+
+Usunięto:
+  mc-1:4.8.19-9.el8.x86_64                                                      
+
+Ukończono.
+</pre>
+      <p>
+        W przypadku instalowania pakietu polecenie przekazywało nam informacje 
+        o użytym na potrzeby instalacji miejscu na dysku. Tak teraz informuje
+        o jego zwolnieniu.
+      </p>
+      <h3 id="10.2.7.provides">10.2.7. Więcej informacji na temat pakietów</h3>
+      <p>
+        Innym sposobem na uzyskanie informacji o tym jaki pakiet zawiera
+        określony plik jest użycie podpolecenia <em>provides</em>. Sprawdza
+        ono występowanie plików w pakietach zainstalowanych w systemie jak
+        i tych możliwych do instalacji.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf provides /etc/passwd
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:04:16 temu w dniu pon, 11 lip 2022, 08:36:18.
+setup-2.12.2-6.el8.noarch : A set of system configuration and setup files
+Repozytorium       : @System
+Dopasowano z:
+Nazwa pliku : /etc/passwd
+
+setup-2.12.2-6.el8.noarch : A set of system configuration and setup files
+Repozytorium       : BaseOS
+Dopasowano z:
+Nazwa pliku : /etc/passwd
+</pre>
+      <p>
+        Po za opisaną metodą na wyszukiwanie informacji o pakietach, do
+        dyspozycji posiadamy jeszcze podpolecenie <em>search</em>, które
+        wyszukuje słów kluczowych w podsumowaniu opisu pakietu oraz jego nazwie.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf search setup
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:20:48 temu w dniu pon, 11 lip 2022, 08:36:18.
+==================== Dopasowano Nazwa i Podsumowanie: setup ====================
+setup.noarch : A set of system configuration and setup files
+cryptsetup-libs.x86_64 : Cryptsetup shared library
+cryptsetup-libs.i686 : Cryptsetup shared library
+ibus-setup.noarch : IBus setup utility
+initial-setup-gui.x86_64 : Graphical user interface for the initial-setup
+                         : utility
+...
+=========================== Dopasowano Nazwa: setup ============================
+NetworkManager-cloud-setup.x86_64 : Automatically configure NetworkManager in
+                                  : cloud
+cryptsetup.x86_64 : A utility for setting up encrypted disks
+cryptsetup-devel.i686 : Headers and libraries for using encrypted file systems
+cryptsetup-devel.x86_64 : Headers and libraries for using encrypted file systems
+cryptsetup-reencrypt.x86_64 : A utility for offline reencryption of LUKS
+                            : encrypted disks.
+...
+======================== Dopasowano Podsumowanie: setup ========================
+rhsm-gtk.x86_64 : GTK+ widgets used by subscription-manager-gui and
+                : initial_setup
+</pre>
+      <p>
+        Jak możemy zauważyć polecenie wyświetla znalezione informacje w trzech
+        grupach.
+      </p>
+      <h2 id="10.3.packagegroup">10.3. Grupy pakietów</h2>
+      <p>
+        Pośród innych sposobów na zarządzanie pakietami możemy wymienić grupy
+        pakietów. Są to zestawy pakietów odpowiedzialne za zapewnienie
+        systemowi operacyjnemu pewnej funkcjonalności np. obsługi wirtualizacji
+        i maszyn wirtualnych. Grupy pakietów obsługuje się identycznie jak
+        pakiety indywidualne, możemy je wyświetlić, zainstalować, 
+        zaktualizować, wyświetlić informacje o nich oraz usunąć. Przjdziemy
+        sobie przez te wszystkie zagadnienia.
+      </p>
+      <h3 id="10.3.1.listsofgroups">10.3.1. Listy grup</h3>
+      <p>
+        Do obsługi grupy służy podpolecenie <em>group</em>, które posiada
+        kolejne znane nam już z obsługi pojedynczych pakietów podpolecenia
+        takie jak np <em>list</em>, którego zadaniem jest wyświetlenie grup
+        pakietów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group list
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:39:54 temu w dniu pon, 11 lip 2022, 08:36:18.
+Dostępne grupy środowisk:
+   Server
+   Minimalna instalacja
+   Workstation
+   Custom Operating System
+   Gospodarz wirtualizacji
+Zainstalowane grupy środowisk:
+   Serwer z graficznym interfejsem użytkownika
+Zainstalowane grupy:
+   Container Management
+   Headless Management
+Dostępne grupy:
+   Zgodność z przestarzałym systemem UNIX
+   Narzędzia programistyczne
+   .NET Core Development
+   Graficzne narzędzia administracyjne
+   Serwery sieciowe
+   RPM Development Tools
+   Obsługa aplikacji naukowych
+   Narzędzia bezpieczeństwa
+   Obsługa smart card
+   Narzędzia systemowe
+</pre>
+      <p>
+        Jak możemy zawuważyć grupy dzielą się dwa rodzaje pierwszym z nich są
+        <code class="code-inline">grupy środowisk</code>, drugim są 
+        zwykłe grupy. Z grupami mogliśmy się już spotkać podczas instalacji
+        systemu, wybieraliśmy rodzaj instalacji <em>Server with GUI</em>.
+        Podczas wyboru oprogramowania mogliśmy wybrać dowolną z nich do
+        zainstalowania. Teraz za pomocą <em>dnf</em> możemy doinstalować 
+        dodatkowe grupy lub usunąć nie potrzebne. Podpolecenie <em>list</em>
+        wyświetla również te obecnie zainstalowane oraz nie wyświetla 
+        wszystkich dostępnych w systemie grup. Wszystkie grupy będą wyświetlone
+        jeśli uzupełnimy nasze polecenie o modyfikator <em>--hidden</em>.
+        W ten sposób możemy wybrać znacznie węższą grupę pakietów. Możemy
+        również używać modyfikatorów takich jak <em>--installed</em> lub
+        <em>--available</em>
+      </p>
+      <p>
+        Po za taką długą listą możemy wyświetlić podsumowanie, które zwróci
+        informacje o ilości dostępnych oraz zainstalowanych grup.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group summary
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 3:08:10 temu w dniu pon, 11 lip 2022, 08:36:18.
+Zainstalowane grupy: 2
+Dostępne grupy: 10
+</pre>
+      <h3 id="10.3.2.infoaboutgroup">10.3.2. Informacje o grupie</h3>
+      <p>
+        Za wyświetlenie informacji o grupie odpowiedzialne jest podpolecenie
+        <em>info</em>, zwraca ono listę pakietów obowiązkowych, które muszą być
+        zainstalowane, aby system został rozszerzony o funkcjonalność 
+        przypisaną grupie oraz listę pakietów opcjonalnych.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group info "Platforma wirtualizacji"
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:58:21 temu w dniu pon, 11 lip 2022, 08:36:18.
+
+Grupa: Platforma wirtualizacji
+ Opis: Dostarcza interfejs do uzyskiwania dostępu i kontrolowania wirtualizowanych gości i kontenerów.
+ Pakiety obowiązkowe:
+   libvirt
+   libvirt-client
+   virt-who
+ Pakiety opcjonalne:
+   fence-virtd-libvirt
+   fence-virtd-multicast
+   fence-virtd-serial
+   perl-Sys-Virt
+</pre>
+      <h3 id="10.3.3.instalationofgroup">10.3.3. Instalacja grup</h3>
+      <p>
+        Instalacja grup odbywa się na tej samej zasadzie, z drobnym wyjątkiem.
+        Otóż jeśli w systemie będą występować jakieś składniki grupy, to
+        jeśli będzie taka możliwość zostaną one zaktualizowane. Instalacja
+        grupy odbywa się za pomocą podpolecenia <em>install</em> podpolecenia
+        <em>group</em>. Jako argument podajemy nazwę grupy.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group install "Obsługa smart card"
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 3:37:36 temu w dniu pon, 11 lip 2022, 08:36:18.
+Rozwiązano zależności.
+================================================================================
+ Pakiet               Architektura Wersja                 Repozytorium    Rozm.
+================================================================================
+Instalowanie pakietów grupy/modułu:
+ esc                  x86_64       1.1.2-22.el8_4         AppStream       180 k
+ pcsc-lite-ccid       x86_64       1.4.29-5.1.el8_4       BaseOS          316 k
+Instalowanie zależności:
+ opensc               x86_64       0.20.0-4.el8           BaseOS          1.3 M
+ pcsc-lite            x86_64       1.9.5-1.el8            BaseOS          110 k
+ pcsc-lite-libs       x86_64       1.9.5-1.el8            BaseOS           43 k
+Instalowanie grup:
+ Smart Card Support                                                            
+
+Podsumowanie transakcji
+================================================================================
+Instalacja  5 pakietów
+
+Całkowity rozmiar: 1.9 M
+Rozmiar po zainstalowaniu: 6.0 M
+W porządku? [t/N]: t
+Pobieranie pakietów:
+Wykonywanie sprawdzania transakcji
+Pomyślnie ukończono sprawdzanie transakcji.
+Wykonywanie testu transakcji
+Pomyślnie ukończono test transakcji.
+Wykonywanie transakcji
+  Przygotowywanie                :                                          1/1 
+  Instalowanie                   : pcsc-lite-libs-1.9.5-1.el8.x86_64        1/5 
+  Wykonywanie skryptu            : pcsc-lite-libs-1.9.5-1.el8.x86_64        1/5 
+  Instalowanie                   : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   2/5 
+  Wykonywanie skryptu            : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   2/5 
+  Instalowanie                   : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Wykonywanie skryptu            : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Instalowanie                   : opensc-0.20.0-4.el8.x86_64               4/5 
+  Wykonywanie skryptu            : opensc-0.20.0-4.el8.x86_64               4/5 
+  Instalowanie                   : esc-1.1.2-22.el8_4.x86_64                5/5 
+  Wykonywanie skryptu            : esc-1.1.2-22.el8_4.x86_64                5/5 
+  Sprawdzanie                    : opensc-0.20.0-4.el8.x86_64               1/5 
+  Sprawdzanie                    : pcsc-lite-1.9.5-1.el8.x86_64             2/5 
+  Sprawdzanie                    : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   3/5 
+  Sprawdzanie                    : pcsc-lite-libs-1.9.5-1.el8.x86_64        4/5 
+  Sprawdzanie                    : esc-1.1.2-22.el8_4.x86_64                5/5 
+Installed products updated.
+
+Zainstalowano:
+  esc-1.1.2-22.el8_4.x86_64            opensc-0.20.0-4.el8.x86_64               
+  pcsc-lite-1.9.5-1.el8.x86_64         pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   
+  pcsc-lite-libs-1.9.5-1.el8.x86_64   
+
+Ukończono.
+</pre>
+      <p>
+        Za pomocą <em>dnf</em> zainstalowałem w  grupę pakietów
+        odpowiedzialną za obsługę kart inteligentych.
+      </p>
+      <h3 id="10.3.4.groupupdate">10.3.4. Aktualizacja grupy</h3>
+      <p>
+        Aktualizacja grupy różni się podaniem innego podpolecenia. Zamiast
+        <em>install</em> podajemy <em>update</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group update "Obsługa smart card"
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 3:47:16 temu w dniu pon, 11 lip 2022, 08:36:18.
+Rozwiązano zależności.
+================================================================================
+ Pakiet            Architektura     Wersja              Repozytorium      Rozm.
+================================================================================
+Aktualizowanie grup:
+ Smart Card Support
+                                                                               
+
+Podsumowanie transakcji
+================================================================================
+
+W porządku? [t/N]: t
+Ukończono.
+</pre>
+      <h3 id="10.3.5.removethegroup">10.3.5. Usuwanie grupy</h3>
+      <p>
+        Tak samo jak w przypadku pojedynczych pakietów, możemy usunąć i grupy.
+        Do usunięcia grupy potrzebne będzie podpolecenie <em>remove</em> oraz
+        nazwa grupy. 
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf group remove "Obsługa smart card"
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Rozwiązano zależności.
+================================================================================
+ Pakiet              Arch.       Wersja                   Repozytorium    Rozm.
+================================================================================
+Usuwanie:
+ esc                 x86_64      1.1.2-22.el8_4           @AppStream      516 k
+ pcsc-lite-ccid      x86_64      1.4.29-5.1.el8_4         @BaseOS         1.4 M
+Usuwanie nieużywanych zależności:
+ opensc              x86_64      0.20.0-4.el8             @BaseOS         3.8 M
+ pcsc-lite           x86_64      1.9.5-1.el8              @BaseOS         218 k
+ pcsc-lite-libs      x86_64      1.9.5-1.el8              @BaseOS          50 k
+Usuwanie grup:
+ Smart Card Support                                                            
+
+Podsumowanie transakcji
+================================================================================
+Usunięcie  5 pakietów
+
+Zwolnione miejsce: 6.0 M
+W porządku? [t/N]: t
+Wykonywanie sprawdzania transakcji
+Pomyślnie ukończono sprawdzanie transakcji.
+Wykonywanie testu transakcji
+Pomyślnie ukończono test transakcji.
+Wykonywanie transakcji
+  Przygotowywanie                :                                          1/1 
+  Wykonywanie skryptu            : esc-1.1.2-22.el8_4.x86_64                1/1 
+  Usuwanie                       : esc-1.1.2-22.el8_4.x86_64                1/5 
+  Usuwanie                       : opensc-0.20.0-4.el8.x86_64               2/5 
+  Wykonywanie skryptu            : opensc-0.20.0-4.el8.x86_64               2/5 
+  Wykonywanie skryptu            : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Usuwanie                       : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Wykonywanie skryptu            : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Usuwanie                       : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   4/5 
+  Wykonywanie skryptu            : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   4/5 
+  Usuwanie                       : pcsc-lite-libs-1.9.5-1.el8.x86_64        5/5 
+  Wykonywanie skryptu            : pcsc-lite-libs-1.9.5-1.el8.x86_64        5/5 
+  Sprawdzanie                    : esc-1.1.2-22.el8_4.x86_64                1/5 
+  Sprawdzanie                    : opensc-0.20.0-4.el8.x86_64               2/5 
+  Sprawdzanie                    : pcsc-lite-1.9.5-1.el8.x86_64             3/5 
+  Sprawdzanie                    : pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   4/5 
+  Sprawdzanie                    : pcsc-lite-libs-1.9.5-1.el8.x86_64        5/5 
+Installed products updated.
+
+Usunięto:
+  esc-1.1.2-22.el8_4.x86_64            opensc-0.20.0-4.el8.x86_64               
+  pcsc-lite-1.9.5-1.el8.x86_64         pcsc-lite-ccid-1.4.29-5.1.el8_4.x86_64   
+  pcsc-lite-libs-1.9.5-1.el8.x86_64   
+
+Ukończono.
+</pre>
+      <p>
+        Po wykonaniu tej czynności grupa została usunięta z systemu.
+      </p>
+      <h2 id="10.4.modulesmanaging">10.4. Zarządzanie modułami pakietów</h2>
+      <p>
+        Moduły to bardziej rozległe pakiety zawierające nie tylko samą
+        aplikacje ale także jej całe środowisko do działania. Moduły
+        posiadają strumienie, które są odrębnym zestawem pakietów przygotowanym
+        z myslą o konkretnej wersji dostarczanego przez moduł programu. Każdy
+        z modułów posiada jeszcze profil, który określa podzbiór pakietów
+        przygotowany z myślą o przeznaczeniu aplikacji. Aby skorzystać z pewnej
+        jej funkcji nie trzeba instalować gigabajtów pakietów. Do obsługi
+        modułów wykorzystuje się podpolecenie <strong>module</strong>, a pracę 
+        z nimi rozpoczeniemy od wyświetlenia listy modułów.
+      </p>
+      <h3 id="10.4.1.listingmodules">10.4.1. Wyświetlanie modułów</h3>
+      <p>
+        Do wyświetlania list modułów służy podpolecenie <em>list</em>. Na 
+        poniższym przykładzie znajduje się fragment listy dostępnych w lokalnym 
+        repozytorium modułów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:12:51 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name                 Stream          Profiles Summary                                      
+389-ds               1.4                      389 Directory Server (base)                  
+ant                  1.10 [d]        common [d] Java build tool                              
+container-tools      rhel8 [d][e]    common [d] Most recent (rolling) versions of podman, bui
+                                                ldah, skopeo, runc, conmon, runc, conmon, CRI
+                                                U, Udica, etc as well as dependencies such as
+                                                container-selinux built and tested together,
+                                                and updated as frequently as every 12 weeks.
+...
+</pre>
+      <p>
+        Modułów dostępnych w systemie jest kilkadziesiąt. Wyświetlenie listy
+        nie posiada zbyt poręcznego formatu, aby zmieszczać pełny listing tego
+        polecenia. Tak jak w przypadku pozostałych elementów, możemy podać
+        podpoleceniu <em>list</em> argument w postaci ogólnej nazwy np. 
+        <em>php</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list php
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:17:20 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name         Stream         Profiles                          Summary                      
+php          7.2 [d]        common [d], devel, minimal        PHP scripting language       
+php          7.3            common [d], devel, minimal        PHP scripting language       
+php          7.4            common [d], devel, minimal        PHP scripting language       
+php          8.0            common [d], devel, minimal        PHP scripting language       
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+</pre>
+      <p>
+        Jak możemy zauważyć na powyższym przykładzie do dyspozycji mamy kilka
+        strumieni. Domyślnym strumieniem jest 
+        <code class="code-inline">7.2</code>, a domyślnym profilem dla tych
+        strumieni jest <code class="code-inline">common</code>. Domyślny
+        strumień oraz profil zostanie wybrany w momencie gdy nie sprecyzujemy
+        tego podczas instalacji. W ostatniej linii znajduje się legenda, litery
+        w nawiasach kwadartowych zdradzają stan modułu zainstalowanego w
+        systemie. Za pomocą modyfikatora <em>--enabled</em> możemy wyświetlić 
+        wszystkie włączone strumienie modułów.
+      </p>
+      <h3 id="10.4.2.infoaboumodule">10.4.2. Informacje na temat modułu</h3>
+      <p>
+        Za pomocą podpolecenia <em>info</em> możemy wyświetlić na przykład
+        jakie pakiety zawiera moduł. Podczas wyświetlania tego typu informacji
+        warto podać interesujący nas strumień, aby zmniejszyć ilość
+        generowanych danych. Strumień podajemy wraz z nazwą modułu oddzielając
+        go dwukropkiem.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module info php:7.2
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:47:02 temu w dniu pon, 11 lip 2022, 12:31:38.
+Name             : php
+Stream           : 7.2 [d][a]
+Version          : 8020020191108065827
+Context          : 2c7ca891
+Architecture     : x86_64
+Profiles         : common [d], devel, minimal
+Default profiles : common
+Repo             : AppStream
+Summary          : PHP scripting language
+Description      : php 7.2 module
+Requires         : httpd:[2.4]
+                 : nginx:[]
+                 : platform:[el8]
+Artifacts        : apcu-panel-0:5.1.12-2.module+el8.1.0+3202+af5476b9.noarch
+                 : libzip-0:1.5.1-2.module+el8.1.0+3202+af5476b9.src
+                 : libzip-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : libzip-debuginfo-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : libzip-debugsource-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : libzip-devel-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : libzip-tools-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : libzip-tools-debuginfo-0:1.5.1-2.module+el8.1.0+3202+af5476b9.x86_64
+                 : php-0:7.2.24-1.module+el8.2.0+4601+7c76a223.src
+                 : php-0:7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64
+                 : php-bcmath-0:7.2.24-1.module+el8.2.0+4601+7c76a223.x86_64
+...
+</pre>
+      <p>
+        Lista pakietów występuje w wierszu 
+        <code class="code-inline">Artifacts</code>.
+      </p>
+      <h3 id="10.4.3.moduleinstallation">10.4.3. Instalacja modułów</h3>
+      <p>
+        Instalacja modułów wygląda podobnie do instalacji takich elementów jak
+        grupy czy pojedyncze pakiety, używamy podpolecenia <em>install</em>
+        podpolecenia przeznaczonego do obsługi tego elementu. Podając moduł
+        możemy równocześnie wybrać zarówno strumień jak i profil korzystając
+        ze składni: <code class="code-inline">moduł:strumień/profil</code>.
+        Dla przykładu zainstaluje moduł języka <em>perl</em> w domyślnym
+        strumieniu oraz domyślnym profilu. Nie będe zmieszczał tutaj
+        informacji zwracanej przez polecenie, ponieważ jest to moduł, który
+        zawiera ponad 100 pakietów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module install perl
+</pre>
+      <p>
+        Za pomocą podpolecenia <em>list</em> sprawdzimy jak wygląda na liście
+        zainstalowany przed chwilą w systemie moduł.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list perl
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:17:20 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name    Stream         Profiles                  Summary                                   
+perl    5.24           common [d], minimal       Practical Extraction and Report Language  
+perl    5.26 [d][e]    common [d] [i], minimal   Practical Extraction and Report Language  
+perl    5.30           common [d], minimal       Practical Extraction and Report Language  
+perl    5.32           common [d], minimal       Practical Extraction and Report Language  
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+</pre>
+      <p>
+        Na powyższym przykładzie możemy zobaczyć, że po zainstalowaniu
+        modułu <em>perl</em> z domyślnym strumieniem oraz domyślnym profilem.
+        Strumień <code class="code-inline">5.26</code> został włączony a 
+        profil <code class="code-inline">common</code> został zainstalowany. 
+        Warto też dodać, że jeśli jakiś z komponentów był już zainstalowany to
+        podczas instalacji modułu zostanie sprawdzony czy nie wymaga 
+        aktualizacji.
+      </p>
+      <h3 id="10.4.4.moduleupdates">10.4.4. Aktualizacja modułu</h3>
+      <p>
+        Aktualizacji modułu, dokonuje tak samo jak aktualizacji grupy czy 
+        pojedynczego pakietu za pomocą podpolecenia <em>update</em>, tylko, że
+        tym przypadku będzie to podpolecenie podpolecenia <em>module</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module update perl -y
+</pre>
+      <p>
+        W tym przypadku użyłem flagi <code class="code-inline">-y</code>, która
+        automatycznie potwierdza wykonanie czynności. <em>Dnf</em> nie będzie
+        nas o nic pytać.
+      </p>
+      <h3 id="10.4.5.removethemodule">10.4.5. Usuwanie modułu</h3>
+      <p>
+        Usuwanie modułów wymaga już dwóch czynności piersza klasyczna
+        wykonywana również na innych elementach. Drugą czynnością jest
+        przywrócenie modułu wykonywane za pomocą podpolecenia <em>reset</em>.
+        Usuniemy teraz moduł <em>perl</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module remove perl -y
+</pre>
+      <p>
+        Wydałem powyższe polecenie a następnie sprawdziłem jak wygląda lista
+        stumieni modułu <em>perl</em> za pomocą poniższego polecenia.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list perl
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:54:15 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name     Stream          Profiles               Summary                                    
+perl     5.24            common [d], minimal    Practical Extraction and Report Language   
+perl     5.26 [d][e]     common [d], minimal    Practical Extraction and Report Language   
+perl     5.30            common [d], minimal    Practical Extraction and Report Language   
+perl     5.32            common [d], minimal    Practical Extraction and Report Language   
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+</pre>
+      <p>
+        Jak widzimy ten strumień jest nadal włączony mimo, iż domyślny profil
+        został odinstalowany. Dlatego też musimy przywrócić moduł.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module reset perl -y
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:58:36 temu w dniu pon, 11 lip 2022, 12:31:38.
+Rozwiązano zależności.
+===========================================================================================
+ Pakiet               Architektura        Wersja                Repozytorium         Rozm.
+===========================================================================================
+Przywracanie modułów:
+ perl                                                                                     
+
+Podsumowanie transakcji
+===========================================================================================
+
+Ukończono.
+
+[user@rhel8-vm1 ~]$ sudo dnf module list perl:5.26
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:59:21 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name      Stream       Profiles                Summary                                     
+perl      5.26 [d]     common [d], minimal     Practical Extraction and Report Language    
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+</pre>
+      <p>
+        Na powyższym przykładzie przywróciłem moduł i sprawdziłem jak wygląda
+        jego status w systemie. Teraz strumień nie jest włączony.
+      </p>
+      <h3 id="10.4.6.swichingstreams">10.4.6. Przełączanie się miedzy strumieniami</h3>
+      <p>
+        Załóżmy taką sytuacje, że musimy zmień wersję <em>php</em> na serwerze
+        z najnowszej (8.0) na niższą. Aby to zrobić musimy przełączyć się
+        między strumieniami. Niestety nie ma lepszej metody niż ta opisana
+        tutaj.
+      </p>
+      <p>
+        Na początku musimy przeprowadzić klasyczne usunięcie modułu, tak jak
+        we wcześniejszym podrozdziale, ale na początku wyświetlimy sobie listę 
+        modułów <em>php</em>.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list php
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:26:58 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name        Stream        Profiles                             Summary                     
+php         7.2 [d]       common [d], devel, minimal           PHP scripting language      
+php         7.3           common [d], devel, minimal           PHP scripting language      
+php         7.4           common [d], devel, minimal           PHP scripting language      
+php         8.0 [e]       common [d] [i], devel, minimal       PHP scripting language      
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+
+[user@rhel8-vm1 ~]$ sudo dnf module remove php:8.0 -y
+[user@rhel8-vm1 ~]$ sudo dnf module reset php:8.0
+</pre>
+      <p>
+        Następnie instalujemy nowy strumień modułu z dodatkową opcją
+        pozwalającą na usunięcie pakietów, aby rozwiązać zależności.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module install php:7.4 --allowerasing -y
+</pre>
+      <p>
+        Przełączenie gotowe. Teraz możemy to zweryfikować. Wyświetlając jeszcze
+        raz listę modułów.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo dnf module list php
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 2:30:25 temu w dniu pon, 11 lip 2022, 12:31:38.
+AppStream
+Name        Stream        Profiles                             Summary                     
+php         7.2 [d]       common [d], devel, minimal           PHP scripting language      
+php         7.3           common [d], devel, minimal           PHP scripting language      
+php         7.4 [e]       common [d] [i], devel, minimal       PHP scripting language      
+php         8.0           common [d], devel, minimal           PHP scripting language      
+
+Wskazówka: [d]omyślne, [e]włączone, [x]wyłączone, [i]zainstalowane
+</pre>
+      <h3 id="exec10.1">Ćwiczenie 1: Konfiguracja dostępu do repozytorium</h3>
+      <p>
+        Na maszynie <em>server1</em> z <strong>RHEL 9</strong> skonfiguruj
+        dostęp do lokalnego repozytorium wykorzystując do tego płyte/obraz
+        płyty z RHEL 9. Plik nazwij <em>local.repo</em>. Uwaga, repozytorium
+        musi być dostępne odrazu po ponownym uruchomioniu maszyny. 
+      </p>
+      <h3 id="exec10.2">Ćwiczenie 2: Instalacja i zarządzanie pojedynczymi pakietami</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong> wykorzystując użytkownika z
+        możliwością podniesienia uprawnień, użyj polecenia <em>dnf</em> do
+        wyświetlenia oddzielnie pakietów możliwych do instalacji oraz 
+        pakietów zainstalowanych. Wyświetl informacje na temat pakietu 
+        <em>httpd</em>, pokaż jego zależności, następnie zainstaluj go, 
+        potwierdź tę czynność wyświetlając plik dziennika <em>/var/log/dnf.log</em>.
+        na koniec usuń pakiet.
+      </p>
+      <h3 id="exec10.3">Ćwiczenie 3: Instalacja i zarządzanie grupami pakietów</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong> wykorzystując użytkownika z
+        możliwością podniesienia uprawnień, użyj polecenia <em>dnf</em> do
+        wyświetlenia zainstalowanych i możliwych do zainstalowania grup.
+        Zainstaluj grupę "Security Tools" i "Scientific Support". Potwierdź to
+        wyświetlając plik dziennika narzędzia. Pokaż pakiety zawarte w grupie
+        "Scientific Support", a następnie usuń tę grupę.
+      </p>
+      <h3 id="exec10.4">Ćwiczenie 4: Instalacja i zarządzanie modułami</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong> wykorzystując użytkownika z
+        możliwością podniesienia uprawnień, użyj polecenia <em>dnf</em> do
+        wyświetlenia listy modułów w systemie. Zainstaluj php w domyślnym
+        strumieniu o profilu rozwojowym. Zweryfikuj instalacje, następnie
+        usuń moduł.
+      </p>
+      <h3 id="exec10.5">Ćwiczenie 5: Przełączanie się miedzy strumieniami.</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong> wykorzystując użytkownika z
+        możliwością podniesienia uprawnień, użyj polecenia <em>dnf</em> do
+        zainstalowania modułu <em>postgresql</em>, w domyslnym strumieniu i
+        domyślnym profilu. Następnie dokonaj przełączenia między strumieniami
+        na starszą wersję o profilu klienta.
+      </p>
+      <h2 id="ch10summary">Podsumowanie</h2>
+      <p>
+        Tym rodziałem zakończyliśmy zarządzanie pakietami. Ten rodział
+        pokazał nam jak zarządzać pakietami za pomocą bardziej zaawansowanego
+        narzędzia jakim jest <em>dnf</em>. Nauczyliśmy się zarządać 
+        pojednyczymi
+        pakietami, grupami oraz modułami. W następnym rodziale zajmiemy się
+        uruchamianiem systemu operacyjnego.
+      </p>
+      <h1 id="11.bootprocess">11. Proces ładowania systemu, GRUB oraz jądro</h1>
+      <p>
+        Proces ładowania systemu następuje w momencie gdy naciskamy przycisk
+        zasilania komputera. Pierwsza faza - faza oprogramowania układowego
+        jest niezależna od stosowanego systemu operacyjnego. Jej zadaniem jest
+        przeprowadzenie tzw. POST-u, czyli sprawdzenia wszystkich komponentów
+        sprzętowych przed uruchomieniem komputera po to aby nadawał
+        się on do stablinej pracy. Faza pierwsza przeprowadzana jest przez 
+        oprogramowanie układowe, które może występować dwóch postaciach:
+        <strong>BIOS</strong> oraz <strong>UEFI</strong>. <em>UEFI</em> jest 
+        oprogramowaniem
+        występującym w wszystkich nowszych komputerach, posiada ono znacznie
+        większe możliwości niż tradycyjny <em>BIOS</em>. Po teście następuję
+        poszukiwanie urządzenia pamięci masowej przechowywującego system
+        operacyjny. Teraz przechodzimy do drugiej fazy rozruchu - fazy
+        programu ładującego. Program ładujący rezyduje w pierwszym sektorze
+        dysku jest on odpowiedzialny za odnalezienie jądra na dysku,
+        rozpakowanie go, załadowanie do pamięci i uruchomienie. Programy
+        rozruchowe (a przynajmniej te wykorzystywane z dystrybucjami Linuks)
+        pozwalają użytkownikowi komputera na wybór jądra oraz zmianę domyślnych
+        parametrów uruchomieniowych. Kiedy jądro jest uruchamiane wówczas
+        rozpoczyna się start systemu operacyjnego. Zadaniami jądra 
+        w odniesieniu do procesu ładowania jest zainicjowanie wszystkich
+        urządzeń oraz uruchomienie programu typu <em>init</em>, tym samym
+        przechodząc do czwartej ostatniej fazy - fazy inicjalizacji w niej
+        program typu <em>init</em> uruchamia wszystkie usługi, uruchamiajac
+        tym samym <em>przestrzeń użytkownika</em>, pod koniec tej fazy
+        użytkownik ma przed sobą gotowy do działania system. Stan systemu
+        operacyjnego pozwalający na zalogowanie się użytkownika do niego kończy
+        cały proces uruchamiania.
+      </p>
+      <h2 id="11.1.grub">11.1. Program rozruchowy GRUB</h2>
+      <p>
+        Dla dystrybucji Linuksa istnieje kilka programów rozruchowych. Tutaj
+        jednak skupimy sie na jednym z nich, który jest stosowany w RHEL a jest
+        nim <strong>GRUB</strong>. Jest on najczęsciej stosowany wśród
+        wiodących dystrybucji. Styczność z nim mamy już na samym początku
+        uruchomienia naszego systemu, po jego uruchomieniu wyświetla on menu
+        zawierające wpisy uruchomieniowe naszego systemu. Poniżej znajduje się
+        obrazek przedstawiający to menu. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/t4w6rxr/tabela-grub-rhel8.png" alt="tabela-grub-rhel8" border="0">
+      </p>
+      <p>
+        Na obrazku możemy zobaczyć dwa wpisy i jeden jest zaznaczony na biało.
+        Jest on domyślną opcją rozruchową. Jeśli nie dokonamy żadnych zmian
+        po upływie czasu odmierzanego w ostatniej linii tekstu pod menu,
+        zaznaczona opcja zostanie automatycznie zatwierdzona i rozpocznie
+        się uruchamianie systemu. Po menu możemy poruszać się za pomocą
+        strzałek w górę oraz w dół.
+      </p>
+      <p>
+        Opcje uruchomieniowe kryjące się za wpisami w menu możemy edytować
+        zaznaczając wybrany wpis, a następnie naciskając klawisz <em>e</em>.
+        <em>GRUB</em> daje nam możliwość debugowania rozruchu za pomocą 
+        wbudowanej powłoki. Powłokę możemy uruchomić naciskając klawisz
+        <em>c</em> podczas wyświetlania menu. W powłoce kryje się około 100
+        poleceń do wykorzystania.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/z2Szgw5/grub-shell-rhel8.png" alt="grub-shell-rhel8" border="0">
+      </p>
+      <h3 id="11.1.1.grubconfig">11.1.1. Konfiguracja programu GRUB</h3>
+      <p>
+        Za wyświetlanie menu odpowiedzialny jest plik konfiguracjyny
+        <em>grub.cfg</em> znajdujący się w katalogu <em>/boot/grub2</em>.
+        Jednak plik ten nie nadaje się do modyfikacji, gdyż aktualizacja jądra
+        nadpisze wszystkie dokonane w nim zmiany, ponieważ jest generowany
+        automatycznie przez specjalnie przygotowane do tego narzędzie.
+      </p>
+      <p>
+        Zmian w <em>GRUB</em> możemy dokonać edytując inny pliki, taki jak
+        <em>/etc/default/grub</em>. Na poniższym przykładzie znajduje się jego
+        zawartość:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ nl /etc/default/grub 
+     1 GRUB_TIMEOUT=5
+     2 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
+     3 GRUB_DEFAULT=saved
+     4 GRUB_DISABLE_SUBMENU=true
+     5 GRUB_TERMINAL_OUTPUT="console"
+     6 GRUB_CMDLINE_LINUX="crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet"
+     7 GRUB_DISABLE_RECOVERY="true"
+     8 GRUB_ENABLE_BLSCFG=true
+</pre>
+      <p>
+       Gdzie każda z tych linii oznacza m.in.:
+      </p>
+      <ul>
+        <li><code class="code-inline">GRUB_TIMEOUT=5</code>, określa czas
+          odliczany do uruchomienia domyślnego wpisu.</li>
+        <li><code class="code-inline">GRUB_DISTRIBUTOR</code>, określa nazwę
+          dystrybucji.</li>
+        <li><code class="code-inline">GRUB_DEFAULT</code>, przechowuje
+          identyfikator domyślnego wpisu. Jeśli posiada wartość 
+          <code class="code-inline">saved</code>, oznacza to, że identyfikator
+          wpisu zostanie pozyskany za pomocą opcji <em>GRUB_SAVEDEFAULT</em>
+          lub <em>grub-set-default</em>.</li>
+        <li><code class="code-inline">GRUB_DISABLE_SUBMENU=true</code>, wyłącza
+          stosowanie podmenu w menu główym.</li>
+        <li><code class="code-inline">GRUB_TERMINAL_OUTPUT="console"</code>,
+          ustawia wyście terminala programu, w tym przypadku jest to domyślna
+          konsola.</li>
+        <li><code class="code-inline">GRUB_CMDLINE_LINUX="crashkernel=auto
+          resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root 
+          rd.lvm.lv=rhel/swap rhgb quiet"</code> - opcja przechowuje 
+          argumenty przekazywane jądru Linuksa.</li>
+        <li><code class="code-inline">GRUB_DISABLE_RECOVERY="true"</code>,
+          jeśli ta opcja ustawiona jest na <em>true</em>, podczas generowania
+          menu nie będą generowane automatyczne wpisy <em>GRUB</em> z opcjami
+          pozwalającymi na uruchomienie systemu w trybie awaryjnym
+          (Mimo to w RHEL pojawia się taki wpis, więc musi być to
+          zrealizowane w inny sposób).</li>
+        <li><code class="code-inline">GRUB_ENABLE_BLSCFG=true</code>, opcja
+          pozwala na użycie plików <em>blscfg</em> zamiast klasycznych wpisów
+          w <em>/boot/grub/grub.cfg</em>.</li>
+      </ul>
+      <p>
+        W tym pliku możemy dokonywać zmian, jednak najpierw warto zaponać się
+        bliżej z <em>GRUB</em>, rozszerzając wiedzę z tego rodziału o np.
+        dokumentację <em>Red Hat</em>, ostatni wpis jest dość specyficzyny i 
+        używany
+        w nowszych dystrybucjach klasy <em>enterprise</em>. Jeśli już dokonamy
+        w nim zmian, zmiany te trzeba zatwierdzić po przez wygenerowanie nowego
+        pliku <em>grub.cfg</em> a służy do tego polecenie
+        <strong>grub2-mkconfig</strong> po opcji <em>-o</em> należy podać
+        ścieżkę docelową, gdzie polecenie ma zapisać nową konfigurację w
+        przeciwnym wypadku zwróci ją na standardowe wyjście.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
+[sudo] hasło użytkownika user: 
+Generating grub configuration file ...
+done
+</pre>
+      <p>
+        Poza plikiem <em>/etc/default/grub</em>, wyżej przedstawione polecenie
+        wykorzystuje również skrypty pomocnicze znajdujące się w katalogu
+        <em>/etc/grub.d</em>. Poniżej znajduje się listing jego zawartości:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ sudo ls -l /etc/grub.d/
+[sudo] hasło użytkownika user: 
+razem 96
+-rwxr-xr-x. 1 root root  8958 03-28 16:12 00_header
+-rwxr-xr-x. 1 root root  1043 02-09 12:13 00_tuned
+-rwxr-xr-x. 1 root root   232 03-28 16:12 01_users
+-rwxr-xr-x. 1 root root   832 03-28 16:12 08_fallback_counting
+-rwxr-xr-x. 1 root root 14088 03-28 16:12 10_linux
+-rwxr-xr-x. 1 root root   830 03-28 16:12 10_reset_boot_success
+-rwxr-xr-x. 1 root root   889 03-28 16:12 12_menu_auto_hide
+-rwxr-xr-x. 1 root root 11696 03-28 16:12 20_linux_xen
+-rwxr-xr-x. 1 root root  2559 03-28 16:12 20_ppc_terminfo
+-rwxr-xr-x. 1 root root 10670 03-28 16:12 30_os-prober
+-rwxr-xr-x. 1 root root  1412 03-28 16:12 30_uefi-firmware
+-rwxr-xr-x. 1 root root   700 04-01 11:49 35_fwupd
+-rwxr-xr-x. 1 root root   214 03-28 16:12 40_custom
+-rwxr-xr-x. 1 root root   216 03-28 16:12 41_custom
+-rw-r--r--. 1 root root   483 03-28 16:12 README
+</pre>
+      <p>
+        Plików w tym katalogu jest całkiem sporo. Istotną rzeczą w tych plikach
+        są liczby na początku nazw. Te liczby prócz znaczeń opisanych w pliku
+        <em>README</em> okreslają kolejność uruchamiania tych skryptów.
+        Każdy pliki wykonuje jakąś czynność podczas generowania pliku
+        konfiguracyjnego, np. <em>00_header</em> ładuje plik
+        <em>/etc/default/grub</em>; <em>10_linux</em> odpowiada za generowanie
+        wpisów uruchamiających dystrybucje, jednak jak wiemy w RHEL odpowiada 
+        za to inny mechanizm; <em>30_os-prober</em> odpowiada za poszukiwanie
+        zainstalowanych na dyskach komputera innych systemów operacyjnych, np.
+        MS Windows; <em>40_custom</em> oraz <em>41_custom</em> pozwalają na
+        zapisanie swojej konfiguracji.
+      </p>
+      <h3 id="11.1.2.rescuemode">11.1.2. Ładowanie systemu do określonego trybu</h3>
+      <p>
+        Edytując wpis ładujący system z poziomu menu <em>GRUB</em> możemy
+        uruchomić system w trybie ratunkowym, odzyskiwania lub przerwać jego
+        ładowanie w momencie gdy głównym system plików jest jeszcze
+        <em>intrd</em> (mały obraz systemu plików ładowany do pamięci przez
+        jądro aby zapewnić mu dostęp do sterowników dysków, żeby mógł
+        zamontować właściwy system plików z katalogiem głównym). Za pomocą
+        takiego uruchomienia systemu możemy zmienić zapomniane hasło 
+        superużytkownika. Aby zapoznać się z tym trybem przywrócimy utracone
+        hasło <em>root</em>. <strong>Do tego ćwiczenia potrzebny będzie RHEL 8,
+        gdyż w RHEL 9 nie ważne jaki tryb uruchominy, nadal wymagane będzie
+        hasło aby przejść do powłoki.</strong> Zatem jedyną opcją na odzyskanie
+        dostępu w RHEL 9 jest podmontowanie systemu plików w środowisku 
+        powłoki instalatora.
+      </p>
+      <p>
+        Po uruchomieniu maszyny, podczas wyświetlania menu <em>GRUB</em> 
+        naciskamy <em>e</em>, następnie w linii rozpoczynającej się od 
+        <em>linux</em> dopisujemy na końcu <strong>rd.break</strong>.
+        Następnie naciskamy <em>Ctrl+x</em>, aby uruchomić tak zmodyfikowany
+        wpis. Po uruchomieniu się systemu uzyskamy poniższy znak zachęty: 
+      </p>
+<pre class="code-block">
+switch_root:/#
+</pre>
+      <p>
+        W tym momencie musimy zmienić katalog główny <em>ramdysku</em> na
+        katalog główny znajdujący się na dysku. Kernel po odnalezieniu
+        dysku z katalogiem głównym montuje go w katalogu <em>/sysroot</em>
+        środowiska <em>ramdysku</em>. Do przełączenia katalogu głównego
+        posłuży nam polecenie <strong>chroot</strong>:
+      </p>
+<pre class="code-block">
+switch_root:/# chroot /sysroot
+</pre>
+      <p>
+        Po przełączeniu się uzyskamy taki znak zachęty jak ten poniżej.
+      </p>
+<pre class="code-block">
+sh-4.4#
+</pre>
+      <p>
+        Z zamontowanym w tym momencie katalogiem głównym jest pewien problem,
+        otóż na tym etapie uruchomienia systemu jest on zamontowany w trybie
+        tylko do odczytu, a zmiana hasła wymaga zapisania informacji w
+        pliku <em>/etc/shadow</em>, dlatego też musimy zamontować katalog
+        główny tym razem w pełnym dostępie.
+      </p>
+<pre class="code-block">
+sh-4.4# mount -o remount,rw /
+</pre>
+      <p>
+        Teraz możemy wydawać polecenie <em>passwd</em> i ustalić nowe hasło dla
+        superużytkownika. Następnie musimy stworzyć pusty plik w katalogu
+        głównym o nazwie <em>.autorelabel</em>. Ponieważ <em>SELinux</em> musi
+        wytworzyć nowe etykiety, jeśli tego nie zrobimy zmiany nie przyniosą
+        skutku.
+      </p>
+<pre class="code-block">
+sh-4.4# passwd
+sh-4.4# touch .autorelabel
+</pre>
+      <p>
+        Po wykonaniu tych czynności możemy opuścić środowisko zmienionego
+        katalogu a następnie zrestartować maszynę uruchamiając ją już
+        normalnie.
+      </p>
+<pre class="code-block">
+sh-4.4# exit
+switch_root:/# reboot
+</pre>
+      <p>
+        Po uruchomieniu systemu nastąpi nadawanie nowych etykiet, po tym
+        system może zostać ponownie uruchomiony, kiedy będzie gotowy do pracy
+        możemy zalować się nowym hasłem na super użytkownika.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Musimy wiedzieć jak załadować system do określonego trybu z poziomu
+        menu GRUB2, aby na przykład móc zmodyfikować plik <em>/etc/fstab</em>,
+        lub zresetować hasło superużytkownika.
+      </p>
+      <h2 id="11.2.kernel">11.2. Jądro systemu Linuks</h2>
+      <p>
+        Jądro to rdzeń każdej dystrybucji, odpowiada za wiele apektów działania
+        systemów oraz udostępnia masę funkcji, bez których dystrybucjom ciężko
+        było by być systemami operacyjnymi. Jedną z takich funkcji jest
+        zarządzanie urządzeniami. Do komunikacji z nimi jądro potrzebuje
+        sterowników. Sterownik w odniesieniu do jądra nazywane są modułami
+        część modułów wymaganych przez jądro może być już w nie wbudowana a
+        część jest ładowana w razie potrzeby (do tego też służy 
+        <em>initrd</em>).
+        <em>RHEL</em> 8.6, którego używam również i w tym rozdziale jest 
+        dostarczany
+        z jądrem 4.18.0-372.9.1.el8.x86_64, tę informację można uzyskać za
+        pomocą polecenia <code class="code-inline">uname -r</code>. I to jądro
+        wystarcza dla potrzeb systemu operacyjnego.
+      </p>
+      <p>
+        Warto jednak pamiętać o tym, że rozwój technologiczny komputerów oraz
+        całej dziedziny informatyki nie stoi w miejscu i jądro Linuks próbuje
+        za nim nadąrzyć. W związku z tym funkcjonalność jądra również ulega
+        zmianie, więc jeśli odbiorcy chcą skorzystać z tych zmian muszą
+        przebudować jądra używane na ich komputerach. Najprostszą i za razem
+        bezpieczną metodą jest instalacja jednego jądra obok drugiego.
+        Oczywiście tylko jedno jądro może działać w tym samym czasie. Ta
+        metoda w względu na przechowywanie dotychczas używanego jądra pozwala
+        wrócić do niego, gdy nowe jądro okaże się nie odpowiednie dla naszego
+        środowiska. Rozwój jądra Linuks to nie tylko dokładanie nowych funkcji
+        ale również usuwanie już niewspieranych technologii, chociaż
+        dystrybucje mogą działajać na różnym sprzęcie, który może mieć lata
+        świetności dawno za sobą, stąd też modułowa budowa jądra. Rózwój jądra
+        nie jest jedym powodem do jego <em>przebudowania</em>, nie które
+        aplikacje lub systemy bazodanowe mogą wymagać nowszej jego wersji, aby
+        zapewnić maksimum wydajności. Tym zajmiemy się w tym podrozdziale:
+        <em>przebudowa jądra</em>. Omówimy sobie również gdzie znajduje się
+        jądro w systemie. 
+      </p>
+      <h3 id="11.2.1.kernelfiles">11.2.1. Pliki jądra w systemie</h3>
+      <p>
+        Jądro to zwykły program, którego zadaniem jest wykonanie czynności
+        i zapewnienie funkcji, które przez większość z nas uznałaby za 
+        "systemowe". Jednak to nadal program, więc musi gdzieś w systemie
+        plików istnieć jego plik. Pliki jądra najczęściej znajdują się w
+        katalogu <em>/boot</em>. Plik jądra zazwyczaj nazywa się 
+        <em>vmlinuz-*</em>, część po myślniku już zależy od dystrybucji. Obok
+        pliku jądra w tym samym katalogu znajduje sie również plik
+        <em>ramdysku</em>. W przypadku RHEL w katalogu <em>/boot</em> znajdują
+        się podkatalogi: <em>grub</em> - zawierający konfigurację programu
+        ładującego, <em>loaders</em> - zawierający pliki <em>blscfg</em>
+        zawierajace wpisy menu programu ładującego oraz katalog <em>efi</em>
+        przechowujący program ładujący dla komputerów uruchamianych w trybie 
+        UEFI. W tym katalogu znajdują się również pliki pomocnicze jądra takie 
+        jak <em>config-*</em> oraz <em>System.map-*</em>. Gwiazdki
+        (<strong>*</strong>) w nazwach plików oznaczczają wersję jądra. Poniżej
+        znajduje się listing zawartości tego katalogu.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ ls -l /boot
+razem 213492
+-rw-r--r--. 1 root root    195982 04-16 04:33 config-4.18.0-372.9.1.el8.x86_64
+drwxr-xr-x. 3 root root        17 07-10 17:27 efi
+drwx------. 4 root root        83 07-14 07:33 grub2
+-rw-------. 1 root root 112548052 07-10 17:50 initramfs-0-rescue-1ad7389b6ff44aac9cfcab2485444bc8.img
+-rw-------. 1 root root  53300132 07-10 17:57 initramfs-4.18.0-372.9.1.el8.x86_64.img
+-rw-------. 1 root root  27283456 07-10 18:00 initramfs-4.18.0-372.9.1.el8.x86_64kdump.img
+drwxr-xr-x. 3 root root        21 07-10 17:42 loader
+lrwxrwxrwx. 1 root root        49 07-10 17:45 symvers-4.18.0-372.9.1.el8.x86_64.gz -> /lib/modules/4.18.0-372.9.1.el8.x86_64/symvers.gz
+-rw-------. 1 root root   4359450 04-16 04:33 System.map-4.18.0-372.9.1.el8.x86_64
+-rwxr-xr-x. 1 root root  10460528 07-10 17:47 vmlinuz-0-rescue-1ad7389b6ff44aac9cfcab2485444bc8
+-rwxr-xr-x. 1 root root  10460528 04-16 04:34 vmlinuz-4.18.0-372.9.1.el8.x86_64
+</pre>
+      <p>
+        Katalog <em>/boot</em> nie jest jedynym miejscem, w którym znajdują się
+        pliki jądra. Dynamicznie ładowane modułu znajdują sie w katalogu
+        <em>/usr/lib/modules</em>. Katalog zawiera cała strukturę katalogową,
+        w której znajdują sie najróżniejsze moduły z podziałem na wersję jądra
+        dostępne w systemie.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ ls -l /usr/lib/modules
+razem 4
+drwxr-xr-x. 3 root root   19 07-10 17:31 4.18.0-372.2.1.el8.x86_64
+drwxr-xr-x. 6 root root 4096 07-10 17:55 4.18.0-372.9.1.el8.x86_64
+</pre>
+      <p>
+        W wewnątrz tej struktury znajdują się moduły sterowników:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ ls -l /usr/lib/modules/4.18.0-372.9.1.el8.x86_64/kernel/drivers/ | head -25
+razem 48
+drwxr-xr-x.  5 root root  239 07-10 17:30 acpi
+drwxr-xr-x.  2 root root  169 07-10 17:30 ata
+drwxr-xr-x.  3 root root   20 07-10 17:30 base
+drwxr-xr-x.  2 root root   24 07-10 17:30 bcma
+drwxr-xr-x.  3 root root  180 07-10 17:30 block
+drwxr-xr-x.  2 root root  272 07-10 17:30 bluetooth
+drwxr-xr-x.  3 root root   17 07-10 17:30 bus
+drwxr-xr-x.  2 root root   25 07-10 17:30 cdrom
+drwxr-xr-x.  6 root root  192 07-10 17:30 char
+drwxr-xr-x.  2 root root   50 07-10 17:30 counter
+drwxr-xr-x.  2 root root  143 07-10 17:30 cpufreq
+drwxr-xr-x.  2 root root   36 07-10 17:30 cpuidle
+drwxr-xr-x.  6 root root  107 07-10 17:30 crypto
+drwxr-xr-x.  4 root root   54 07-10 17:30 dax
+drwxr-xr-x.  2 root root   23 07-10 17:30 dca
+drwxr-xr-x.  5 root root   60 07-10 17:30 dma
+drwxr-xr-x.  2 root root 4096 07-10 17:30 edac
+drwxr-xr-x.  2 root root  113 07-10 17:30 firewire
+drwxr-xr-x.  2 root root   69 07-10 17:30 firmware
+drwxr-xr-x.  2 root root  107 07-10 17:30 gpio
+drwxr-xr-x.  3 root root   17 07-10 17:30 gpu
+drwxr-xr-x.  5 root root 4096 07-10 17:30 hid
+drwxr-xr-x.  2 root root   74 07-10 17:30 hv
+drwxr-xr-x.  3 root root 4096 07-10 17:30 hwmon
+...
+</pre>
+      <p>
+        Poza zwykłymi plikami jądra, w systemie istnieje interfejs przez nie
+        udostępniany, a jest nim katalog <strong>/proc</strong>. Ten katalog
+        zawiera masę podkatalogów odpowiadających uruchomionym w systemie
+        procesom oraz kilkdziesiąt plików pomocniczych. Z tego katalogu
+        korzystają takie narzędzia jak: <em>ps</em>, <em>top</em>, <em>mem</em>
+        czy <em>lscpu</em>. Poniżej znajduje się listing podkatalogów procesów:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ ls -l /proc | head 
+razem 0
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 10
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1000
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1010
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1011
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1015
+dr-xr-xr-x.  9 root           root                         0 07-14 07:29 1017
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 1020
+dr-xr-xr-x.  9 root           root                         0 07-14 07:28 11
+</pre>
+      <p>
+        Informacje na temat procesora oraz pamięci możemy uzyskać bezpośrednio
+        od jądra korzystając takich plików jak <em>/proc/cpuinfo</em> oraz
+        <em>/proc/meminfo</em>.
+      </p>
+      <p>
+        Plik zawierający informacje o procesorze:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ cat /proc/cpuinfo 
+processor      : 0
+vendor_id      : GenuineIntel
+cpu family     : 6
+model          : 60
+model name     : Intel Core Processor (Haswell, no TSX)
+stepping       : 1
+microcode      : 0x1
+cpu MHz                : 1696.073
+cache size     : 16384 KB
+physical id    : 0
+siblings       : 1
+core id                : 0
+cpu cores      : 1
+apicid         : 0
+initial apicid : 0
+fpu            : yes
+fpu_exception  : yes
+cpuid level    : 13
+...
+</pre>
+      <p>
+        Plik zawierający informacje o pamięci:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ cat /proc/meminfo 
+MemTotal:         824024 kB
+MemFree:           92668 kB
+MemAvailable:     285968 kB
+Buffers:              20 kB
+Cached:           284704 kB
+SwapCached:         1628 kB
+Active:           167040 kB
+Inactive:         396240 kB
+...
+</pre>
+      <h3 id="11.2.2.kernelpackes">11.2.2. Pakiety jądra</h3>
+      <p>
+        Jądro do dystrybucji dostarczane jest za pomocą zwykłych pakietów
+        z oprogramowaniem, które mozemy zainstalować z repozytorium. Jądro
+        rozbite jest na kilka pakietów, których lista oraz opis zawartości
+        znajdują się poniżej.
+      </p>
+      <ul>
+        <li><strong>kernel</strong> - Nie zawiera plików, zapewnia jedynie
+          poprawną instalację innych pakietów jądra.</li>
+        <li><strong>kernel-core</strong> - Zawiera pliki jądra wraz z niewielką
+          ilością modułów zepewniającą podstawową funkcjonalność.</li>
+        <li><strong>kernel-devel</strong> - Zawiera pliki wspomagające
+          kompilację modułów.</li>
+        <li><strong>kernel-modules</strong> - Zawiera moduły powszechnie
+          znanych urządzeń.</li>
+        <li><strong>kernel-modules-extra</strong> - Zawiera moduły dodatkowych,
+          różnych urządzeń (mniej spotykanych).</li>
+        <li><strong>kernel-headers</strong> - Zawiera pliki wspierające wymianę
+          informacji pomiędzy jądrem, bibliotekami przestrzeni użytkownika oraz
+          programami.</li>
+        <li><strong>kernel-tools</strong> - Zawiera narzędzia pozwalające na
+          kontrolę jądra.</li>
+        <li><strong>kernel-tools-libs</strong> - Zawiera biblioteki
+          wspomagające działanie narzędzi jądra.</li>
+      </ul>
+      <p>
+        Nie wszystkie z tych pakietów muszą występować w systemie, aby jądro
+        normalnie funkcjonowało, oraz nie wszystkie one są potrzebne do jego
+        przebudowania. Za pomoca polecenia poniżej możemy sprawdzić jakie 
+        pakiety jądra są zainstalowane w naszym systemie.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ rpm -qa | grep 'kernel'
+kernel-tools-libs-4.18.0-372.9.1.el8.x86_64
+kernel-tools-4.18.0-372.9.1.el8.x86_64
+kernel-4.18.0-372.9.1.el8.x86_64
+kernel-core-4.18.0-372.9.1.el8.x86_64
+kernel-modules-4.18.0-372.9.1.el8.x86_64
+</pre>
+      <p>
+        Te pakiety trzeba będzie pobrać, kiedy bedziemy chcieli przebudować
+        jądro. Zanim jednak to nastąpi przeanalizujemy wersje jądra aby móc
+        wybrać to najbardziej odpowiednie.
+      </p>
+      <h3 id="11.2.3.kernelversion">11.2.3. Wersja jądra</h3>
+      <p>
+        Wersje jądra możemy sprawdzić za pomocą polecenia
+        <code class="code-inline">uname -r</code>. Dzieli się ona na kilka
+        części, które mogą pomóc nam w zidentyfikowaniu nowego jądra
+        odpowiedniego dla naszego systemu:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ uname -r
+4.18.0-372.9.1.el8.x86_64
+</pre>
+      <ul>
+        <li><code class="code-inline">4</code> - Numer główny wersji. Numer
+          rodziny wersji jądra. Ulega on zmianie gdy następuje wewnątrz jądra
+          duża zmiana.</li>
+        <li><code class="code-inline">18</code> - Numer rewizji. Zmiany 
+          zachodące w jądrze są za małe aby utworzyć na nową linię (zmienić
+          główny numer), jednak są dość znaczące.</li>
+        <li><code class="code-inline">0</code> - Numer łatki. Łatki poprawiają
+          błędy oraz zabezpieczenia, mogą również wprowadzać drobne ulepszenia.
+        </li>
+        <li><code class="code-inline">-372.9.1.el8</code> - sygnatura budowania
+          jądra przez dystrybucję. Każda główna dystrybucja zajmuje się
+          samodzielnym budowaniem jądra. Więc w tej części znajduje się
+          numer <em>buildu</em> przprowadzanego prze dystrybucje. Kiedy
+          będziemy wybierać jądro dla naszej dystrybucji możemy kierować się
+          tymi oznaczeniami.</li>
+        <li><code class="code-inline">x86_64</code></li> - nazwa architektury.
+          W tym przypadku jest AMD64 lub kto woli EM64T.</li>
+      </ul>
+      <p>
+        Po za zapoznaniu się z wersją, możemy przejść do przebudowy jądra na
+        naszych maszynych.
+      </p>
+      <h3 id="11.2.4.rebuidkernel">11.2.4. Przebudowa jądra</h3>
+      <p>
+        Przebudowę jądra rozpoczniemy od ustalenia jego obecnej wersji oraz
+        wybrania odpowiedniej dla naszych rozwiązań. Z racji tego, iż jest to
+        tylko przykład wybierzemy kolejny <em>build</em> dystrybucji.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ uname -r
+4.18.0-372.9.1.el8.x86_64
+</pre>
+      <p>
+        W wiec w naszym przypadku najlepiej będzie zainstalować wersje np.
+        <em>373</em> lub inną podobną. Teraz musimy ustalić źródło, skąd
+        pobierzemy pakiety potrzebne do zainstalowania nowego jądra. Opcje
+        mamy dwie: strona <em>Red Hat</em> (ponieważ nasze system nie są 
+        zarejestrowane
+        w sieci <em>Red Hat</em>, musimy pobrać pakiety logując się na stronie 
+        a następnie wybrać z sekcji pobierania odpowiednie pakiety) lub strona
+        <em>rpmfind.net</em>, która jest wyszukiwarką pakietów wśród wielu
+        serwerów lustrzanych różnych dystrybucji klasy
+        <em>enterprise</em>. Skutkiem użycia pakietów ze strony <em>rpmfind</em>
+        jest to, iż poźniej nasze jądro może widnieć jako np. <em>CentOS</em> w
+        menu <em>GRUB</em>, więc najlepszym rozwiazaniem jest skorzystanie z
+        strony <em>Red Hat</em>. Pakiety możemy pobrać na maszynie za pomocą
+        zainstalowanej przeglądarki lub na komputerze który ją hostuje i
+        następnie przesłać zbiorcze archiwum za pomocą <em>sftp</em> (patrz:
+        rozdział 19).
+        Listę pakietów niezbędnych do zainstalowania nowego jądra możemy
+        wyświetlić za pomocą polecenia:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ rpm -qa | grep 'kernel'
+kernel-tools-libs-4.18.0-372.9.1.el8.x86_64
+kernel-tools-4.18.0-372.9.1.el8.x86_64
+kernel-4.18.0-372.9.1.el8.x86_64
+kernel-core-4.18.0-372.9.1.el8.x86_64
+kernel-modules-4.18.0-372.9.1.el8.x86_64
+</pre>
+      <p>
+        Na komputerze na którym hostuje maszynę wirtualną pobrałem z strony
+        <em>Red Hat</em> najnowsze pakiety jądra przeznaczone dla <em>RHEL</em>
+        8. Stworzyłem
+        z nich archiwum nastepnie przesłałem do wcześniej utworzonego 
+        podkatalogu w katalogu <em>/tmp</em> na maszynie z <em>RHEL</em> 8. 
+        Poniżej znajduje się lista pobranych pakietów:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 kernel]$ ls -l 
+razem 97736
+-rw-r--r--. 1 user user  8436304 07-14 10:22 kernel-4.18.0-372.16.1.el8_6.x86_64.rpm
+-rw-r--r--. 1 user user 41240076 07-14 10:22 kernel-core-4.18.0-372.16.1.el8_6.x86_64.rpm
+-rw-r--r--. 1 user user 33296868 07-14 10:22 kernel-modules-4.18.0-372.16.1.el8_6.x86_64.rpm
+-rw-r--r--. 1 user user  8654240 07-14 10:23 kernel-tools-4.18.0-372.16.1.el8_6.x86_64.rpm
+-rw-r--r--. 1 user user  8445172 07-14 10:23 kernel-tools-libs-4.18.0-372.16.1.el8_6.x86_64.rpm
+</pre>
+      <p>
+        Teraz instalacja jest już banalna, wystarczy użyć polecenia
+        <em>dnf</em>, a ono wykona wszystkie czynności za nas.
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 kernel]$ sudo dnf install kernel-*
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Rozwiązano zależności.
+================================================================================
+ Pakiet               Arch.     Wersja                    Repozytorium    Rozm.
+================================================================================
+Instalowanie:
+ kernel               x86_64    4.18.0-372.16.1.el8_6     @commandline    8.0 M
+Aktualizowanie:
+ kernel-tools         x86_64    4.18.0-372.16.1.el8_6     @commandline    8.3 M
+ kernel-tools-libs    x86_64    4.18.0-372.16.1.el8_6     @commandline    8.1 M
+Instalowanie zależności:
+ kernel-core          x86_64    4.18.0-372.16.1.el8_6     @commandline     39 M
+ kernel-modules       x86_64    4.18.0-372.16.1.el8_6     @commandline     32 M
+
+Podsumowanie transakcji
+================================================================================
+Instalacja    3 pakiety
+Aktualizacja  2 pakiety
+
+Całkowity rozmiar: 95 M
+W porządku? [t/N]: 
+</pre>
+      <p>
+        Po zatwierdzeniu rozpocznie się instalacja. Po skończonej instalacji
+        musimy uruchomić ponownie maszynę. W menu <em>GRUB</em> nowe jądro
+        będzie na pierwszej domyślnej pozycji. Po załadowaniu systemu wersją
+        jądra używana przez ten system to:
+      </p>
+<pre class="code-block">
+[user@rhel8-vm1 ~]$ uname -r
+4.18.0-372.16.1.el8_6.x86_64
+</pre>
+      <p>
+        Jak możemy zauważyć to jądro różni się od porzedniego drobnymi 
+        zmianami wprowadzonymi przez dystrybucję, gdyż zmianie uległ numer 
+        rewizji w numerze <em>buildu</em>.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Zawsze należy instalować nowe jądro, a nie aktualizować stare.
+        Aktualizacja usuwa każde istniejące jądro i zastępuje je nowym w
+        przypadku problemów po instalacji z nowym jądrem nie będzie możliwości
+        powrotu do poprzedniego działającego poprawnie jądra.
+      </p>
+      <h3 id="exec11.1">Ćwiczenie 1: Właczenie komunikatów podczas ładowania systemu</h3>
+      <p>
+        Jako użytkownik z możlwością podniesienia uprawnień na maszynie
+        z <strong>RHEL 8</strong>, usuń wartość
+        <em>quiet</em>, z opcji <em>GRUB_CMDLINE_LINUX</em> w pliku
+        <em>/etc/default/grub</em>. Następnie uruchom polecenie
+        <em>grub2-mkconfig</em> aby wygenerować nowy plik konfiguracyjny
+        <em>GRUB</em>. Na koniec uruchom ponownie system, aby zobaczyć 
+        komunikaty generowane przez jądro.
+      </p>
+      <h3 id="exec11.2">Ćwiczenie 2: Przywrócenie hasła superużytkownika</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong>, przerwij ładowanie systemu i
+        zmień hasło superużytkownika. Po ponownym uruchomieniu maszyny zaloguj
+        się na jego konto i ustaw hasło takie jakie było do tej pory
+        (chyba, że go nie pamiętasz).
+      </p>
+      <h3 id="exec11.3">Ćwiczenie 3: Instalacja nowego jądra</h3>
+      <p>
+        Na maszynie z <strong>RHEL 8</strong>, jako użytkownik z możliwością
+        podniesienia uprawnień, sprawdź wersję jądra domyślnie używaną w
+        w systemie, następnie ustal jakie pakiety jądra są zainstalowane.
+        Pobierz nowszą wersję jądra z 
+        <em>Red Hat Customer Portal</em> lub <em>rpmfind.net</em> i 
+        przeprowadź instalacje nowego jądra. Po czym zrestartuj system i
+        sprawdź obecną jego wersję.
+      </p>
+      <h2 id="ch11summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale zapoznaliśmy się z procesem ładowania systemu. Poznaliśmy
+        po krótce każdą z jego faz. Przyjrzeliśmy się bliżej z programowi 
+        ładującemu
+        <em>GRUB</em> jego plikom konfiguracyjnymi oraz narzędziom z nim
+        związanym. Nauczyliśmy się uruchamiać system w trybie awaryjnym aby
+        przywrócić hasło superużytkownika lub poprawić wpisy w pliku
+        <em>/etc/fstab</em>. Na koniec poruszyliśmy temat jądra, dowiedzieliśmy
+        sie gdzie znajdują się pliki jądra, jakie pakiety odpowiadają za nie
+        w systemie oraz nauczyliśmy się poprawnie interpretować jego wersje
+        jądra aby móc zainstalować nową jego wersję. Następnym rodziale 
+        przyjrzymy się ostatniej fazie rozruchu.
+      </p>
+      <h1 id="12.sysinitlogsandtuned">12. Inicjalizacja systemu, pliki dziennika oraz dostarajanie systemu</h1>
+      <p>
+        W tym rozdziale zajmiemy się czwartą ostatnią fazą uruchamiania systemu
+        czyli jego inicjalizacją. Dla dystrybucji Linuksa istnieje wiele
+        programów typu <em>init</em>. Większość z wiodących dystrybucji
+        używa <em>Systemd</em> (ang. <em>System daemon</em>), jednak wielu
+        programistów uważa, że <em>systemd</em> jest sprzeczne z filozofią
+        <em>Uniksa</em>, dlatego też wśród społeczności powstało wiele
+        rozwidleń, będących odpowiednikami dystrybucji wiodących ale dających
+        końcowemu użytkownikowi wybór z jakiego (poza <em>systemd</em>) 
+        z programów typu <em>init</em> chce korzystać. W niektórych przypadkach
+        decyzje podejmujemy sciągając odpowiedni obraz płyty, a w niektórych
+        wyboru dokonujemy go podczas instalacji. Nie mniej jednak RHEL korzysta
+        z <em>systemd</em> i to nim się zajmiemy, dlatego też odniesienia jako
+        programu lub procesu typu <em>init</em> będą odnośić się do <em>systemd</em>.
+      </p>
+      <p>
+        Jak zapewne zdajemy sobie sprawę wiele programów generuje komunikaty
+        diagnostyczne. Nie które z nich są wyświetlane na naszych terminalach,
+        inne te których nie widzimy, albo nie są generowane albo są zbierane
+        przez jednego z demonów systemowych i zapisywane w jednym z systemowych
+        katalogów. W jednym z nich znajdują się właśnie pliki dziennika.
+      </p>
+      <p>
+        Poza instalacją i konfiguracją oprogramowania, zarządzaniem plikami,
+        katalogami czy użytkownikami być może będziemy musieli dostoswać nasz
+        system, aby był bardziej wydajny co może spowodować większy pobór 
+        energii elektrycznej lub będziemy zmuszeni, aby nasz system był 
+        bardziej energooszczędny, to bedziemy mogli zrealizować za pomocą 
+        jednego z demonów, którego będzie trzeba zainstalować.
+      </p>
+      <h2 id="12.1.systeminit">12.1. Inicjalizacja systemu - systemd</h2>
+      <p>
+        W większości wiodących dystrybucji, wybiera <em>systemd</em> jak
+        program typu <em>init</em> dla swoich systemów. Mimo sprzeciwu części
+        społeczności, to <em>systemd</em> nie jest programem, który jest
+        pozbawiony zalet. Ma ich bardzo wiele i są one dość istotne. 
+        <em>Systemd</em> jest to program typu <em>init</em>, którego głównymi
+        zadaniami jest przygotowanie systemu do pracy oraz zarządanie usługami.
+        W fazie inicjalizacji uruchamiana jest większość usług, które do czasu
+        wdrożenia <em>systemd</em> uruchamiane są jedna po drugiej co wydłużało
+        proces uruchamiania systemu. Natomiast nowy program postawił na 
+        współbieżność uruchamiania - wszystkie usługi startują w tym samym
+        czasie. <em>Systemd</em> może również opóźnić uruchomienie konkretej
+        usługi kiedy będzie ona rzeczywiście wymaga zaoszczędzając przy tym
+        zasoby systemu. Kolejną rzeczą, którą wprowadza <em>systemd</em> jest
+        zarządzanie zasobami, którymi operuja usługi. Program za pomocą
+        oczywiście odpowiedniej konfiguracji jest wstanie stworzyć zasób, który
+        potrzebują inne usługi, następnie uruchomić demona, który taki zasób
+        powinien udostępniać w momencie gdy demon z zasobem jeszcze się
+        uruchamia, inne te które go wymagają widzą że jest on dostępny i
+        wysyłają zapytania do tego demona o dostęp do zasobu. Te zapytania są 
+        buforowane do momentu
+        jego pełnego uruchomienia, na koniec te zapytania wraz kontrolą nad
+        zasobem są przekazywane do niego. Jest to kolejna cecha, która 
+        przyspiesza ładowanie systemu. Kolejną cechą <em>systemd</em> jest
+        zmiana administracji usług. Teraz nie są wymgane już skrypty wystarczy
+        krótki plik, kilka, kilkanaście linijek i usługa jest już zdefiniowana. 
+      </p>
+      <h3 id="12.1.1.units">12.1.1. Jednostki</h3>
+      <p>
+        <strong>Jednostki</strong> są to pliki za pomocą których opisuje się 
+        różne komponenty
+        systemu dla <em>systemd</em>. Pliki jednostek są to zwykłe pliki
+        tekstowe, podzielone na dwie, trzy sekcje. Pierwsza sekcją służy do
+        opisu jednostki, druga jest zależna od typu jednostki i zawiera
+        specyficzne dla niego dyrektywy. Trzecia sekcja służy w zazwyczaj
+        od określania włączania i wyłączania jednostki (Uwaga, tutaj włączanie
+        i wyłączanie tyczy się angielskich słów <em>enable</em> oraz 
+        <em>disable</em>.  Jednostki <em>systemd</em> się aktywuje lub
+        uruchamia [ang. <em>start</em>]). Poniżej znajduje się plik jednostki
+        demona <em>ssh</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ cat /usr/lib/systemd/system/sshd.service
+[Unit]
+Description=OpenSSH server daemon
+Documentation=man:sshd(8) man:sshd_config(5)
+After=network.target sshd-keygen.target
+Wants=sshd-keygen.target
+
+[Service]
+Type=notify
+EnvironmentFile=-/etc/sysconfig/sshd
+ExecStart=/usr/sbin/sshd -D $OPTIONS
+ExecReload=/bin/kill -HUP $MAINPID
+KillMode=process
+Restart=on-failure
+RestartSec=42s
+
+[Install]
+WantedBy=multi-user.target
+</pre>
+      <p>
+        Ten plik przestawia jednostkę usługi. Omawianie dyrektyw wykracza
+        poza ramy tego materiału, dlatego nie będzie tutaj to realizowane.
+        Więcej wiedzy znajduje się na stronie podręcznika
+        <code class="code-inline">man systemd.unit</code>. Poniżej znajduje
+        się lista typów jednostek oraz krótki opis za co odpowiadają w
+        systemie.
+      </p>
+      <ul>
+        <li><strong>.socket</strong> - Jednostki gniazd zazwyczaj są powiązane
+          z jednostkami usług, służą do przedstawiania gniazd, które są
+          wykorzystywane w komunikacji miedzyprocesowej lub sieciowej.</li>
+        <li><strong>.device</strong> - Jednostka urządzenia, wystąpienie
+          urządzenia w ujęciu <em>systemd</em>. Takie jednostki są
+          wykorzystywane do aktywacji innych jednostek w momencie pojawienia
+          się urządzenia w systemie.</li>
+        <li><strong>.mount</strong> - Jednostka montowania, określa gdzie i jak
+          zamontować lub odmontować określony system plików.</li>
+        <li><strong>.automount</strong> - Jednostka automontowania wspomaga
+          montowanie systemów plików na żądanie.</li>
+        <li><strong>.swap</strong> - Jednostka przestrzeni wymiany, określa
+          przestrzeń wymiany w odniesieniu do <em>systemd</em>.</li>
+        <li><strong>.target</strong> - Cel. Jednostka logiczna, zestaw plików
+          jednostek.</li>
+        <li><strong>.path</strong> - Jednostka ścieżki. Wykorzystywana do
+          aktywacji innej jednostki w momencie próby uzyskania dostępu do
+          określonego pliku lub katalogu.</li>
+        <li><strong>.timer</strong> - Jednostka służy do aktywacji innej
+          jednostki na podstawie czasu w niej zdefiniowanego.</li>
+        <li><strong>.slice</strong> - Jednostka wycinka, służy do przydzielania
+          i zarządania zasobami grupie procesów.</li>
+        <li><strong>.service</strong> - Jednostka usługi. Wystąpienie
+          demona w <em>systemd</em>.</li>
+      </ul>
+      <h3 id="12.1.2.target">12.1.2. Jednostki celu</h3>
+      <p>
+        <strong>Cel</strong> w ujęciu <em>systemd</em> jest logiczna grupą
+        jednostek
+        różnego rozdzaju, które mogą na przykład składać się na jeden z
+        komponentów systemu operacyjnego, na przykład środowisko graficzne.
+        Często cele mogą odpowiadać klasycznym poziomom uruchomienia systemu.
+        W systemie jest zdefiniowanych kilka celów, o to one: 
+      </p>
+      <ul>
+        <li><strong>halt</strong> - Zamyka i zatrzymuje system. Wyłączenie
+          komputera wymaga naciśnięcia przycisku zasilania.</li>
+        <li><strong>poweroff</strong> - Zamyka i wyłącza system.</li>
+        <li><strong>shutdown</strong> - Zamyka system.</li>
+        <li><strong>rescue</strong> - Tryb jednego użytkownika dla funkcji
+          administracyjnych oraz przywracania systemu. Lokalne systemy plików
+          zostają zamontowane, nie które podstawowe usługi są uruchamiane ale
+          sieć pozostaje odłączona od systemu.</li>
+        <li><strong>emergency</strong> - Uruchomiana zostaje powłoka ratunkowa,
+          a główny system plików zostaje zamontowany w trybie tylko do odczytu.
+          Sieć oraz pozostałe usługi są wyłączone.</li>
+        <li><strong>multi-user</strong> - Normalne działanie systemu, ale bez
+          trybu graficznego.</li>
+        <li><strong>graphical</strong> - Normalne działanie systemu z trybem
+          graficznym.</li>
+        <li><strong>reboot</strong> - Zamyka system, a następnie uruchamia
+          komputer ponownie.</li>
+        <li><strong>default</strong> - Dowiązanie symboliczne najczęściej do
+          celu <em>graphical</em> lub <em>multi-user</em>.</li>
+        <li><strong>hibernate</strong> - Przenosi system w stan hibernacji.</li>
+      </ul>
+      <p>
+        Cele wykorzystywane są do uruchamiania wielu jednostek zapisanych w ich
+        zależnościach.
+      </p>
+      <h3 id="12.1.3.systemctl">12.1.3. Polecenie systemctl</h3>
+      <p>
+        Polecenie służącym do zarządzania <em>systemd</em> jest
+        <strong>systemctl</strong>, za jego pomocą możemy wykonywać
+        proste czyności administracyjne związane z jednostkami oraz celami.
+        Polecenie to zawiera duża ilość różnego rodzaju podpoleceń oraz
+        modyfikatorów, są one opisane na stronie podręcznika tego polecenia.
+        My za poznamy się z nim w praktyce.
+      </p>
+      <p>
+        Wydając polecenie <em>systemctl</em> bez żadnej opcji polecenie
+        wyświetli table przedstawiącą wszystkie aktywne jednostki wraz z ich
+        stanem oraz krótkim opisem. Poniżej znajduje się jej fragment
+      </p>
+<pre class="code-block">
+UNIT                                LOAD   ACTIVE SUB       DESCRIPTION
+...
+rhsmcertd.service                   loaded active running   Enable periodic update of ...
+rsyslog.service                     loaded active running   System Logging Service
+rtkit-daemon.service                loaded active running   RealtimeKit Scheduling Policy ...
+spice-vdagentd.service              loaded active running   Agent daemon for Spice guests
+sshd.service                        loaded active running   OpenSSH server daemon
+switcheroo-control.service          loaded active running   Switcheroo Control Proxy service
+systemd-journal-flush.service       loaded active exited    Flush Journal to Persistent ...
+...
+</pre>
+      <p>
+        Tego nie widać na przykładzie ale jeśli wywołamy w terminalu polecenie,
+        możemy zobaczyć, że poszczególne typy jednostek są oddzielone od siebie
+        za pomocą poziomej linii. W drugiej kolumnie znajduje się stan
+        jednostki. Ta kolumna podzielona jest na trzy mniejsze kolumny.
+        Pierwsza określa czy jednostka jest załadowana, druga określa tzw.
+        stan wyższego poziomu aktywacji. Jest to ogólny stan aktywacji i może
+        przybierać on różne wartości takim najważniejszymi są <em>active</em>,
+        <em>failed</em>, <em>inactive</em>. Trzecia zaś określa niższy poziom
+        aktywacji, może on zawierać informacje specyficzne dla typu jednostki
+        lub demona. 
+      </p>
+      <p>
+        Powyższy przykład zawiera tylko załadowane jednostki, ale jeśli
+        chcielibyśmy zobaczyć wszystkie jednostki dostępne w systemie musimy
+        dodać do polecenia modyfikator <em>--all</em>. Innym przydatnym
+        modyfikatorem jest <em>-t</em> pozwalający podać typ jednostki.
+      </p>
+<pre class="code-block">
+  UNIT                          LOAD      ACTIVE   SUB     DESCRIPTION                                                                  
+  accounts-daemon.service       loaded    active   running Accounts Service
+  alsa-restore.service          loaded    inactive dead    Save/Restore Sound Card State
+  alsa-state.service            loaded    active   running Manage Sound Card State (restore and store)
+  atd.service                   loaded    active   running Deferred execution scheduler
+  auditd.service                loaded    active   running Security Auditing Service
+● auto-cpufreq.service          not-found inactive dead    auto-cpufreq.service
+● autofs.service                not-found inactive dead    autofs.service
+  avahi-daemon.service          loaded    active   running Avahi mDNS/DNS-SD Stack
+  blk-availability.service      loaded    inactive dead    Availability of block devices
+  chronyd.service               loaded    active   running NTP client/server
+  colord.service                loaded    active   running Manage, Install and Generate Color Profiles
+  cpupower.service              loaded    inactive dead    Configure CPU power related settings
+  crond.service                 loaded    active   running Command Scheduler
+  cups.service                  loaded    active   running CUPS Scheduler
+  dbus-broker.service           loaded    active   running D-Bus System Message Bus
+  dm-event.service              loaded    inactive dead    Device-mapper event daemon
+</pre>
+      <p>
+        Kolejnym dość istonym modyfikatorem, który pozwoli man namierzyć
+        jednostki, których aktywacja zakończyła się niepowodzeniem. Jest
+        <em>--failed</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ systemctl --failed
+  UNIT          LOAD   ACTIVE SUB    DESCRIPTION                 
+● kdump.service loaded failed failed Crash recovery kernel arming
+
+LOAD   = Reflects whether the unit definition was properly loaded.
+ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
+SUB    = The low-level unit activation state, values depend on unit type.
+1 loaded units listed.
+</pre>
+      <p>
+        Pod tabelą znajduje się również krótki opis kolumn ze stanem.
+      </p>
+      <p>
+        Za pomocą podpolecenia <em>list-dependencies</em> możemy wyświetlić 
+        zależności jednostki.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ systemctl list-dependencies tuned.service
+tuned.service
+● ├─dbus-broker.service
+● ├─dbus.socket
+● ├─polkit.service
+● ├─system.slice
+● └─sysinit.target
+●   ├─dev-hugepages.mount
+●   ├─dev-mqueue.mount
+●   ├─dracut-shutdown.service
+○   ├─iscsi-onboot.service
+●   ├─kmod-static-nodes.service
+○   ├─ldconfig.service
+●   ├─lvm2-lvmpolld.socket
+●   ├─lvm2-monitor.service
+○   ├─multipathd.service
+...
+</pre>
+      <p>
+        Koła oznaczają aktywną jednostkę, a okręgi nieaktywną jednostkę.
+      </p>
+      <h3 id="12.1.4.managingunits">12.1.4. Zarządzanie jednostkami</h3>
+      <p>
+        Poza podpolecaniami służacymi wyświetlaniu informacji o jednostkach,
+        <em>systemctl</em> posiada dużą ilość podpoleceń związanych z
+        zarządzaniem jednostkami. Jednostki możemy aktywować, dezaktywować,
+        włączać, wyłączać, wyświetlić podsumowanie na ich temat czy zablokwać
+        zmianę stanu. Pierwszą rzeczą jak zrobimy z będzie wyświetlenie
+        informacji o jednostce, a służy do tego podpolecenie
+        <strong>status</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl status atd.service
+[sudo] password for user: 
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 07:40:58 CEST; 1h 34min ago
+       Docs: man:atd(8)
+   Main PID: 934 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 300.0K
+        CPU: 5ms
+     CGroup: /system.slice/atd.service
+             └─934 /usr/sbin/atd -f
+
+Jul 17 07:40:58 server1.example.com systemd[1]: Started Deferred execution scheduler.
+</pre>
+      <p>
+        Na podstawie tych informacji możemy wywnioskować, że jednostka jest
+        załadowana, jest aktywna a jej demon nadal działa. Znamy także stronę
+        podręcznika opisującą tego demona oraz jego <em>PID</em>. Ważną rzeczą
+        podczas wyświetlania status jednostki jest wykonanie tego z
+        uprawnieniami administratora, wówczas na samym dole zostaną nam
+        wyświetlone komunikaty diagnostyczne, pobrane z plików dziennika
+        <em>systemd</em>, te komunikaty pomagają zlokalizować usterki, które
+        mogą być odpowiedzialne za problem z aktywacją jednostki.
+      </p>
+      <p>
+        Jednostkę możemy zatrzymać oraz uruchomić za pomocą podpoleceń
+        <strong>stop</strong> oraz <strong>start</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl stop atd.service
+[sudo] password for user: 
+[user@server1 ~]$ sudo systemctl status atd.service
+○ atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: inactive (dead) since Sun 2022-07-17 09:23:11 CEST; 2s ago
+       Docs: man:atd(8)
+    Process: 934 ExecStart=/usr/sbin/atd -f $OPTS (code=exited, status=0/SUCCESS)
+   Main PID: 934 (code=exited, status=0/SUCCESS)
+        CPU: 5ms
+
+Jul 17 07:40:58 server1.example.com systemd[1]: Started Deferred execution scheduler.
+Jul 17 09:23:11 server1.example.com systemd[1]: Stopping Deferred execution scheduler...
+Jul 17 09:23:11 server1.example.com systemd[1]: atd.service: Deactivated successfully.
+Jul 17 09:23:11 server1.example.com systemd[1]: Stopped Deferred execution scheduler.
+
+[user@server1 ~]$ sudo systemctl start atd.service
+[user@server1 ~]$ sudo systemctl status atd.service
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 09:23:44 CEST; 2s ago
+       Docs: man:atd(8)
+   Main PID: 1576 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 260.0K
+        CPU: 4ms
+     CGroup: /system.slice/atd.service
+             └─1576 /usr/sbin/atd -f
+
+Jul 17 09:23:44 server1.example.com systemd[1]: Started Deferred execution scheduler.
+</pre>
+      <p>
+        Do ponownego uruchomienia jednostki służy inne podpolecenie niż 
+        <em>stop</em>, <em>start</em>, a jest nim <strong>restart</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl restart atd.service
+[sudo] password for user: 
+[user@server1 ~]$ sudo systemctl status atd.service
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 09:41:38 CEST; 3s ago
+       Docs: man:atd(8)
+   Main PID: 1595 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 264.0K
+        CPU: 3ms
+     CGroup: /system.slice/atd.service
+             └─1595 /usr/sbin/atd -f
+
+Jul 17 09:41:38 server1.example.com systemd[1]: Started Deferred execution scheduler.
+</pre>
+      <p>
+        Do włączanie i wyłączania jednostek służą podpolecenia takie jak
+        <strong>enable</strong> oraz <strong>disable</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl disable atd.service
+[sudo] password for user: 
+Removed /etc/systemd/system/multi-user.target.wants/atd.service.
+[user@server1 ~]$ sudo systemctl status atd.service
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; disabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 09:41:38 CEST; 6min ago
+       Docs: man:atd(8)
+   Main PID: 1595 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 264.0K
+        CPU: 3ms
+     CGroup: /system.slice/atd.service
+             └─1595 /usr/sbin/atd -f
+
+Jul 17 09:41:38 server1.example.com systemd[1]: Started Deferred execution scheduler.
+</pre>
+      <p>
+        W linii <code class="code-inline">Loaded:</code> za ścieżką do pliku
+        jednostki, status zmienił się z <em>enabled</em> na
+        <code class="code-inline">disabled</code>. Jeśli użyjemy podpolecenia
+        <em>enable</em>, status wróci do poprzedniej wartości.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl enable atd.service
+Created symlink /etc/systemd/system/multi-user.target.wants/atd.service → /usr/lib/systemd/system/atd.service.
+[user@server1 ~]$ sudo systemctl status atd.service
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 09:41:38 CEST; 9min ago
+       Docs: man:atd(8)
+   Main PID: 1595 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 264.0K
+        CPU: 3ms
+     CGroup: /system.slice/atd.service
+             └─1595 /usr/sbin/atd -f
+
+Jul 17 09:41:38 server1.example.com systemd[1]: Started Deferred execution scheduler.
+</pre>
+      <p>
+        Włączenie jednostki powoduje utworzenie dowiązania symbolicznego w
+        katalogu zależności celu, natomiast wyłączenie usuwa to dowiązanie.
+      </p>
+      <p>
+        Za pomocą podpoleceń <strong>mask</strong> oraz 
+        <strong>unmask</strong> możemy zablokować włączenie oraz aktywację 
+        jednostki. Użycie podpolecenia <em>mask</em> tworzy dowiązanie do pliku
+        <em>/dev/null</em> i zaznacza w <em>systemd</em>, że jednostka jest
+        zablokowana. Podpolecenie <em>umask</em> odwraca działania podpolecenia
+        <em>mask</em>. Usuwa stworzone dowiązanie oraz zmienia status jednostki
+        w <em>systemd</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl mask atd.service
+[sudo] password for user: 
+Created symlink /etc/systemd/system/atd.service → /dev/null.
+[user@server1 ~]$ sudo systemctl status atd.service 
+● atd.service
+     Loaded: masked (Reason: Unit atd.service is masked.)
+     Active: active (running) since Sun 2022-07-17 09:41:38 CEST; 28min ago
+   Main PID: 1595 (atd)
+        CPU: 3ms
+     CGroup: /system.slice/atd.service
+             └─1595 /usr/sbin/atd -f
+
+Jul 17 09:41:38 server1.example.com systemd[1]: Started Deferred execution scheduler.
+Jul 17 10:09:58 server1.example.com systemd[1]: atd.service: Current command vanished from the unit file, execution of the command list ...
+
+[user@server1 ~]$ sudo systemctl unmask atd.service
+Removed /etc/systemd/system/atd.service.
+[user@server1 ~]$ sudo systemctl status atd.service 
+● atd.service - Deferred execution scheduler
+     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Sun 2022-07-17 09:41:38 CEST; 30min ago
+       Docs: man:atd(8)
+   Main PID: 1595 (atd)
+      Tasks: 1 (limit: 5760)
+     Memory: 264.0K
+        CPU: 3ms
+     CGroup: /system.slice/atd.service
+             └─1595 /usr/sbin/atd -f
+
+Jul 17 09:41:38 server1.example.com systemd[1]: Started Deferred execution scheduler.
+Jul 17 10:09:58 server1.example.com systemd[1]: atd.service: Current command vanished from the unit file, execution of the command list ...
+</pre>
+      <h3 id="12.1.5.managingtargets">12.1.5. Zarządzanie jednostkami celów</h3>
+      <p>
+        Zarządzaniem jednostkami celów, różni się od zarządzania jednostkami
+        usług czy innych typów. Jednostki celów przedstawiają różne stany
+        uruchomienia systemu operacyjnego, więc aby miało to jakiś sens
+        zarządzanie nim sprowadza się głównie do dwóch czynności, jedną z nich
+        jest określenie oraz ustawienie domyślnego stanu, w którym to system
+        operacyjny jest zdatny do użycia. W tym przypadku określa to jednostka
+        celu - <strong>default</strong>. Za pomocą podpoleceń możemy sprawdzić
+        która z dostarczonych z systemem jednostek jest wskazywana przez to
+        dowiązanie. Możemy to określić za pomocą podpolecenia
+        <strong>get-default</strong>.
+      </p> 
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl get-default
+[sudo] password for user: 
+graphical.target
+</pre>
+      <p>
+        Tę wartość możemy zmienić, wpływając również na sposób ładowania
+        systemu. Jeśli zmienię domyślny cel z
+        <code class="code-inline">graphical.target</code> na 
+        <em>multi-user.target</em>, wówczas system zatrzyma ładowanie systemu
+        przed uruchomieniem środowiska graficznego. Zmianie domyślnego celu
+        służy podpolecenie <strong>set-default</strong>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl set-default multi-user.target
+[sudo] password for user: 
+Removed /etc/systemd/system/default.target.
+Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.
+[user@server1 ~]$ sudo systemctl get-default
+multi-user.target
+</pre>
+      <p>
+        Jeśli zrestartujemy teraz maszynę, uruchomi się ona bez środowiska
+        graficznego. 
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Może być tak, że na egzaminie będzie trzeba zmienić domyślny cel
+        ładowanie systemu.
+      </p>
+      <p>
+        Pomiędzy celami możemy się przełączać w trakcie działania systemu.
+        Służy do tego podpolecenie <strong>isolate</strong>. 
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl isolate multi-user.target
+</pre>
+      <p>
+        Po wydaniu tego polecenia, jeśli otworzymy okno maszyny zobaczymy, że
+        środowisko graficzne zostało wyłączone. Aby włączyć je z powrotem
+        użyjemy tego samego polecenia, jednak wskazując inny cel.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo systemctl isolate graphical.target
+[sudo] password for user: 
+</pre>
+      <p>
+        Tym że akcentem zakończyliśmy omawianie <em>systemd</em>. Oczywiście
+        to zagadnienia jest tak obszerne, że można by napisać około 200, 300
+        stronicową książke na ten temat bazując na samej dokumentacji programu.
+      </p>
+      <h2 id="12.2.logging">12.2. Prowadzenie plików dzienników systemowych</h2>
+      <p>
+        Zbieranie informacji o tym co się dzieje w systemie to bardzo ważna
+        czynność wykonywana przez systemy operacyjne. Nie które z komponentów
+        instalowanych w nich zwracają bardzo ubogie w informacje komunikaty
+        o błędach lub ostrzeżenia z których nic nie wynika. Najczęściej ma to
+        na celu poprawienie wyglądu oraz doświadczeń użytkownika 
+        (<em>UI/UX Design</em>), przez co wielu użytkowników zostaje na lodzie
+        chcąc samodzielnie rozwiązać problemy. Ta cecha nie tyczy się tylko
+        systemów MS Windows. Wiodące środowiska graficzne w dystrybucjach
+        również mają z tym problem. Ale w Uniksach mamy dobrze zorganizowane
+        pliki dzienników, dzieki którym w możemy znaleźć przyczynę, nie których
+        problemów. 
+      </p>
+      <h3 id="12.2.1.rsyslog">12.2.1. Rejestrator systemowy - rsyslog</h3>
+      <p>
+        <strong>Rsyslog</strong> jest odpowiedzialny za zbieranie komunikatów
+        diagnostycznych i umieszczenie ich w przeznaczonych dla nich miejscach.
+        Nie które komunikaty mogą trafiać do plików inne mogą być wyświetlane
+        w terminalach pracujących na serwerze użytkowników. Te reguły są
+        zapisane w pliku konfiguracyjnym demona <em>/etc/rsyslog.conf</em>.
+        Program wspiera dostoswane pliki konfiguracyjne użytkowników
+        przechowywane w <em>/etc/rsyslog.d</em>. Plik konfiguracyjny
+        <em>rsyslog</em> wygląda następująco:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep -v -e '^#' -e '^$' /etc/rsyslog.conf 
+global(workDirectory="/var/lib/rsyslog")
+module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat")
+include(file="/etc/rsyslog.d/*.conf" mode="optional")
+module(load="imuxsock"           # provides support for local system logging (e.g. via logger command)
+       SysSock.Use="off") # Turn off message reception via local log socket; 
+                         # local messages are retrieved through imjournal now.
+module(load="imjournal"            # provides access to the systemd journal
+       StateFile="imjournal.state") # File to store the position in the journal
+*.info;mail.none;authpriv.none;cron.none                /var/log/messages
+authpriv.*                                              /var/log/secure
+mail.*                                                  -/var/log/maillog
+cron.*                                                  /var/log/cron
+*.emerg                                                 :omusrmsg:*
+uucp,news.crit                                          /var/log/spooler
+local7.*                                                /var/log/boot.log
+</pre>
+      <p>
+        Ostatnie linie na końcu zawierają <strong>zasady</strong>, 
+        które określaja jakie komunikaty należy zbierać i co z nimi 
+        zrobić. Zasady dzielą się na dwie części na <strong>selektor</strong>,
+        określający komunikaty diagostyczne oraz <strong>akcje</strong>
+        definiującą dla nich miejsce docelowe. Poza tym selektor również możemy
+        rozłożyć na <strong>funkcje</strong> - wskazującą na demona lub
+        komponent od którego
+        należy przechwycić komunikaty oraz <strong>priorytet</strong>
+        określający ważność komunikatu. Funkcję od priorytetu oddziela się
+        kropką. Spis funkcji oraz priorytetów znajduje się na stronie
+        podręcznika pliku <em>/etc/rsyslog.conf</em>. Gwiazdka to symbol
+        wieloznaczny wskazujący zarówno wszystkie priorytety jak i wszystkie
+        funkcje w zależności gdzie został użyty. Priorytet
+        <code class="code-inline">none</code> wskazuje aby nie przechwytywać
+        komunikatów z tej funkcji. Jak możemy zobaczyć w pierwszej zasadzie
+        na jedną akcje może przypadać wiele selektorów. Selektory oddziela się
+        średnikiem (<strong>;</strong>). W polu akcji zazwyczaj znajdują się
+        ścieżki do plików wskazujących gdzie należy zapisać komunikaty
+        diagnostyczne, jedyny wyjątkiem są komunikaty o najwyższym priorytecie
+        za pomocą wewnętrzengo modułu są one wyświetlane w terminalach jako
+        wiadomości do użytkowników.
+      </p>
+      <p>
+        Jak możemy zauważyć większość plików dzienników znajduje się w katalogu
+        <em>/var/log</em>. A prawie wszystkie komunikaty diagostyczne trafiają
+        do jednego pliku <em>/var/log/messages</em>. Ten plik jest głównym
+        plikiem dziennika w systemie. Każda linia reprezentuje jeden z
+        komunikatów. Taki plik najlepiej wyświetlać za pomocą polecenia 
+        <em>less</em>
+        lub <em>more</em>.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Używanie polecenie <em>tail</em> wraz z opcją <em>-f</em> może okazać
+        się przydatne podczas śledzenia komunikatów diagnostycznych w trakcie
+        uruchamiania usług lub testowania, aby wychwycić wszysktie problemy.
+      </p>
+      <p>
+        Jeśli będziemy chcieli coś zmienić w konfiguracji <em>rsyslog</em>, 
+        warto przed
+        uruchomieniem ponowym usługi sprawdzić poprawność konfiguracji za
+        pomocą polecenia <code class="code-inline">rsyslog -N 1</code>. Gdzie
+        <code class="code-inline">1</code> oznacza ilość wyświetlanych 
+        przez polecenie komunikatów.
+      </p>
+      <h3 id="12.2.2.logrotating">12.2.2. Obrót plików dziennika</h3>
+      <p>
+        Pliki dziennika to zwykłe pliki tekstowe, które potrafią bardzo szybko
+        przyrastać w zależności od tego co się dzieje w systemie. Taki nie
+        kontrolowany przyrost plików może szybko wypełnić dostępne miejsce
+        dysku. Zastosowano więc mechanizm rotacji plików dziennika. Stare pliki
+        są usuwane robiąc miejsce nowym. Tym zadaniem zajmuje się wywoływany
+        w codziennym katalogu <em>cron</em> (<em>/etc/cron.daily</em>) skrypt
+        <strong>logrotate</strong>. Skrypt ten posiada swój plik konfiguracyjny
+        <em>/etc/logrotate.conf</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ grep -v -e '^$' /etc/logrotate.conf 
+# see "man logrotate" for details
+# global options do not affect preceding include directives
+# rotate log files weekly
+weekly
+# keep 4 weeks worth of backlogs
+rotate 4
+# create new (empty) log files after rotating old ones
+create
+# use date as a suffix of the rotated file
+dateext
+# uncomment this if you want your log files compressed
+#compress
+# packages drop log rotation information into this directory
+include /etc/logrotate.d
+# system-specific logs may be also be configured here.
+</pre>
+      <p>
+        Na podstawie tego pliku możemy dowiedzieć się, że rotacja jest
+        dokonywana co tydzień, pozostawione mają zostać pliki dziennika na
+        cztery tygodnie wstecz oraz po usunięciu starych, następnie zmianie 
+        nazw obecnym skrypt utworzy nowe puste pliki dla nowych komunikatów
+        zapisywanych w plikach dzienika. Definicje zachowania dla
+        rotacji plików dziennika dostarczane wraz z programami znajdują się w 
+        katalogu <em>/etc/logrotate.d</em>. Oto zawartość tego katalogu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /etc/logrotate.d/
+total 56
+-rw-r--r--. 1 root root  91 Mar 31  2021 bootlog
+-rw-r--r--. 1 root root 130 Oct 14  2019 btmp
+-rw-r--r--. 1 root root 160 May 12  2021 chrony
+-rw-r--r--. 1 root root  88 Oct 21  2021 dnf
+-rw-r--r--. 1 root root  93 Nov 23  2021 firewalld
+-rw-r--r--. 1 root root 172 Jul 29  2021 iscsiuiolog
+-rw-r--r--. 1 root root 162 Apr 14 19:04 kvm_stat
+-rw-r--r--. 1 root root 312 Nov  1  2021 psacct
+-rw-r--r--. 1 root root 226 Jan 19 16:31 rsyslog
+-rw-r--r--. 1 root root 155 Mar 18 10:32 samba
+-rw-r--r--. 1 root root 237 Jan 17 20:46 sssd
+-rw-r--r--. 1 root root  88 Apr 13 17:00 subscription-manager
+-rw-r--r--. 1 root root 100 Feb  4 15:58 wpa_supplicant
+-rw-r--r--. 1 root root 145 Oct 14  2019 wtmp
+</pre>
+      <p>
+        Zawartość takiego pliku może zdradzać, w jaki sposób <em>logrotate</em>
+        zachowa się wobec takiego pliku, nadpisując tym samym konfigurację
+        z pliku, z wcześniejszego przykładu (globalnego pliku konfiguracji).
+      </p>
+      <h3 id="12.2.3.bootlog">12.2.3. Plik dziennika rozruchu</h3>
+      <p>
+        W katalogu <em>/var/log</em> znajduje się plik <em>boot.log</em>
+        przedstawiający uruchamianie ostatniej fazy rozruchu. W tym pliku
+        możemy podejrzeć czy wszystkie usługi wystartowały czy też nie. Uwaga,
+        plik nie nadaje się do przeglądania za pomocą polecenie <em>less</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo head /var/log/boot.log
+[  OK  ] Started User Login Management.
+[  OK  ] Started Daemon for power management.
+[  OK  ] Started Authorization Manager.
+         Starting Modem Manager...
+         Starting firewalld - dynamic firewall daemon...
+[  OK  ] Finished Rotate log files.
+[  OK  ] Started Accounts Service.
+[  OK  ] Started Power Profiles daemon.
+[  OK  ] Started Modem Manager.
+[  OK  ] Started Disk Manager.
+...
+[FAILED] Failed to start Crash recovery kernel arming.
+See 'systemctl status kdump.service' for details.
+</pre>
+      <p>
+        W nawiasach kwadratowych wyświetla on <code class="code-inline">OK</code>
+        lub <code class="code-inline">FAILED</code>.
+      </p>
+      <h3 id="12.2.4.logger">12.2.4. Własne komunikaty diagnostyczne</h3>
+      <p>
+        Czasami możemy chcieć uzupełnić systemowy plik dziennika
+        <em>/var/log/messages</em> o kilka komunikatów, które będą wyznaczać
+        początek i koniec testowanego oprogramowania lub dodwać kilka notatek
+        wyjaśniających takie a nie inne komunikaty. Dzięki <em>rsyslog</em> za
+        pomocą jednego z jego wewnętrznych modułów możemy dokonać wpisów do
+        tego pliku dziennika. Realizować to będziemy za pomocą polecenia
+        <em>logger</em>. Na przykład:
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ logger "Hello, World! It's $LOGNAME"
+[user@server1 ~]$ sudo tail -1 /var/log/messages
+[sudo] password for user: 
+Jul 17 13:03:42 server1 user[2706]: Hello, World! It's user
+</pre>
+      <p>
+        Te komunikaty są rozpoznawane przez <em>rsyslog</em> jako 
+        <em>user.notice</em>, jednak za pomocą opcji <em>-p</em> możemy podać 
+        swój
+        selektor. Polecenie <em>logger</em> możemy być przydatne do testowania
+        zmian w konfiguracji <em>rsyslog</em>. 
+      </p>
+      <h2 id="12.3.systemdjournal">12.3. Dzienniki systemd</h2>
+      <p>
+        <em>Systemd</em> poza funkcjami omówionymi na początku tego rozdziału
+        dostarcza wielu narzędzi, które czasami bywają irytujące, ale nie które
+        z nich jak np. demon <strong>systemd-journald</strong> są całkiem przydatne, 
+        ponieważ to za jego zasługą dowiadujemy się dlaczego nasza usługa
+        nie chce się uruchomić. Ten demon przechwytuje komunikaty z bardzo
+        wielu źródeł od jądra przez <em>ramdysk</em> do różnorakich usług.
+        Swoje komunikaty przechowuje w pliku <em>/run/log/journal</em>, zatem
+        w pliku, który nie jest trwały i zostanie zniszczony w momencie 
+        zamknięcia systemu. Konfiguracja tego demona przechowywana jest w pliku
+        <em>/etc/systemd/journald.conf</em>, w którym w razie potrzeby możemy
+        zmienić.
+      </p>
+      <h3 id="12.3.1.displaingjournald">12.3.1. Wyświetlanie dziennika systemd</h3>
+      <p>
+        Do wyświetlenia informacji zebranych przez demona 
+        <em>systemd-journald</em> mamy do dyspozycji takie polecenie jak 
+        <strong>journalctl</strong>. Jesli wydamy to polecenie bez żadnych 
+        opcji to polecenie zwróci ono treść podobną do zawartości
+        <em>/var/log/messages</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo journalctl 
+[sudo] password for user: 
+Jul 16 12:48:20 server1.example.com kernel: Linux version 5.14.0-70.13.1.el9_0.x86_64 (mockbuild@x86-vm-08.build.eng.bos.redhat.com) (gcc (GCC) 11.2.>
+Jul 16 12:48:20 server1.example.com kernel: Linux version 5.14.0-70.13.1.el9_0.x86_64 (mockbuild@x86-vm-08.build.eng.bos.redhat.com) (gcc (GCC) 11.2.>
+Jul 16 12:48:20 server1.example.com kernel: The list of certified hardware and cloud instances for Red Hat Enterprise Linux 9 can be viewed at the Re>
+Jul 16 12:48:20 server1.example.com kernel: Linux version 5.14.0-70.13.1.el9_0.x86_64 (mockbuild@x86-vm-08.build.eng.bos.redhat.com) (gcc (GCC) 11.2.>
+Jul 16 12:48:20 server1.example.com kernel: Linux version 5.14.0-70.13.1.el9_0.x86_64 (mockbuild@x86-vm-08.build.eng.bos.redhat.com) (gcc (GCC) 11.2.>
+Jul 16 12:48:20 server1.example.com kernel: The list of certified hardware and cloud instances for Red Hat Enterprise Linux 9 can be viewed at the Re>
+Jul 16 12:48:20 server1.example.com kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.14.0-70.13.1.el9_0.x86_64 root=/dev/mapper/rhel-root ro c>
+Jul 16 12:48:20 server1.example.com kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
+Jul 16 12:48:20 server1.example.com kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
+Jul 16 12:48:20 server1.example.com kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
+...
+</pre>
+      <p> 
+        Przy użyciu opcji <em>-o</em> wraz z wartością <em>verbose</em>,
+        narzędzie zwróci bardzo szczegółowy opis każdego z komunikatów.
+      </p>
+<pre class="code-block">
+Sat 2022-07-16 12:48:20.235840 CEST [s=5135ad3430d34e718c820bc5b157f883;i=1;b=9ca0ad75315f4891b4807b449a2ce046;m=233ae8;t=5e3e9df815e40;x=7786ef23901>
+    _SOURCE_MONOTONIC_TIMESTAMP=0
+    _TRANSPORT=kernel
+    PRIORITY=5
+    SYSLOG_FACILITY=0
+    SYSLOG_IDENTIFIER=kernel
+    MESSAGE=Linux version 5.14.0-70.13.1.el9_0.x86_64 (mockbuild@x86-vm-08.build.eng.bos.redhat.com) (gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9), G>
+    _BOOT_ID=9ca0ad75315f4891b4807b449a2ce046
+    _MACHINE_ID=4015aef220c344e1875a3fbbd1453b45
+    _HOSTNAME=server1.example.com
+</pre>
+      <p>
+        Polecenie ma masę opcji nie ma sensu ich tutaj wszystkich przytaczać.
+        Znajdziemy je na stronie podręcznika 
+        <code class="code-inline">man journalctl</code>.
+      </p>
+      <p>
+        Komunikaty dla poszczególnych usług znajdziemy na końcu informacji
+        zwracanych przez <em>systemctl status</em>. Dlatego ważne jest, aby
+        używać tego polecenia z uprawnieniami administratora.
+      </p>
+      <h3 id="12.3.2.storageforjournald">12.3.2. Konfiguracja miejsca do przechwywania dzienników systemd</h3>
+      <p>
+        Jak wiemy dziennik <em>systemd</em> nie jest przechowywany na stałe w
+        systemie. To możemy zmienić. W bardzo prosty sposób. Otóz, dyrektywa
+        <em>Storage</em> w konfiguracji demona może mieć cztery wartości:
+      </p> 
+      <ul>
+          <li><em>volatile</em> - Przechowuje informacje tylko w pamięci</li>
+          <li><em>persistent</em> - Przechowuje informacje w katalogu
+            <em>/var/log/journal</em>, jeśli katalog nie istnieje zostanie
+            utworzony, chyba że jest z tym jakiś problem to demon wraca do
+            przechowywania komunikatów wyłącznie w pamięci.</li>
+          <li><em>auto</em> - Podobnie do <em>presistent</em>, jednak nie
+            tworzy ona katalogu.</li>
+          <li><em>none</em> - wyłącza przechowywanie komunikatów
+            diagnostycznych gdzie kolwiek.</li>
+      </ul>
+      <p>
+        Domyślną jej wartością jest <em>auto</em>, więc aby włączyć 
+        przechowywanie
+        dzienników na stałe, wystarczy utworzyć katalog <em>journal</em> w
+        katalogu <em>/var/log</em>. Tutaj pragnę zaznaczyć, że w <em>RHEL</em>
+        8 wystarczyło zrestartować usługę, ale w przypadku <em>RHEL</em> 9
+        należy zrestartować cały system. Kiedy system będzie gotowy wewnątrz
+        katalogu zostanie utworzony podkatalogu o nazwany wartością 
+        <em>/etc/machine-id</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ ls -l /var/log/journal/
+total 4
+drwxr-sr-x+ 2 root systemd-journal 4096 Jul 16 20:17 4015aef220c344e1875a3fbbd1453b45
+[user@server1 ~]$ cat /etc/machine-id 
+4015aef220c344e1875a3fbbd1453b45
+</pre>
+      <p>
+        Teraz komunikaty dziennika <em>systemd</em> bedą przechowywane w tym
+        katalogu. 
+      </p>
+      <h2 id="12.4.tuned">12.4. Dostosowywanie systemu</h2>
+      <p>
+        W <em>RHEL</em> jak i inych systemach klasy <em>enterprise</em> możemy
+        spotkać się z narzędziem, które na podstawie monitorowania zasobów
+        komputera może zmienić ich ustawienia aby podnieść ich wydajność lub
+        gdy przestanie być to konieczne ją obniżyć aby zaoszczędzić
+        wykorzystywaną energię elektryczną. Tym zajmuje się demon <em>tuned</em>.
+        Nie występuję on domyślnie w systemie i trzeba go zainstalować.
+      </p>
+      <p>
+        <em>Tuned</em> może dynamicznie na podstawie danych uzyskanych z
+        różnych monitorów zasobów dostosowywać wydajność sprzętu do potrzeb.
+        Może on również zostać przez nas statycznie skonfigurowany za pomocą
+        predefiniowanych profili. Wydajność systemu wówczas nie zmieni się
+        dopóki my nie załadujemy innego profilu. Konfiguracja statyczna jest
+        jego domyślną konfiguracją.
+      </p>
+      <h3 id="12.4.1.tuned-adm">12.4.1. Polecenie tuned-adm</h3>
+      <p>
+        Demon <em>tuned</em> dostarczany jest w postaci pakietów i znajduje się 
+        na płycie instalacyjnej z <em>RHEL</em>. Instalacji dokonuje za pomocą
+        poniższego polecenia:
+      </p> 
+<pre class="code-block">
+[user@server1 ~]$ sudo dnf install tuned -y
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Last metadata expiration check: 2:38:24 ago on Sun 17 Jul 2022 11:44:30 AM CEST.
+Package tuned-2.18.0-1.el9.noarch is already installed.
+Dependencies resolved.
+Nothing to do.
+Complete!
+</pre>
+      <p>
+        Uwaga, w <em>RHEL</em> 9 demon może wymagać ręcznej aktywacji
+        jednostki za pomocą polecenia <em>systemctl</em>.
+        Wraz z demonem zostanie nam dostarczone polecenie 
+        <strong>tuned-adm</strong> za pomocą, którego będziemy mogli 
+        administrować wydajnością systemu dostosowywaną przez te profile.
+        Za pomocą podpolecenia <em>list</em> możemy wyświetlić listę dostępnych
+        profili.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm list
+Available profiles:
+- accelerator-performance     - Throughput performance based tuning with disabled higher latency STOP states
+- balanced                    - General non-specialized tuned profile
+- desktop                     - Optimize for the desktop use-case
+- hpc-compute                 - Optimize for HPC compute workloads
+- intel-sst                   - Configure for Intel Speed Select Base Frequency
+- latency-performance         - Optimize for deterministic performance at the cost of increased power consumption
+- network-latency             - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance
+- network-throughput          - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
+- optimize-serial-console     - Optimize for serial console use.
+- powersave                   - Optimize for low power consumption
+- throughput-performance      - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
+- virtual-guest               - Optimize for running inside a virtual guest
+- virtual-host                - Optimize for running KVM guests
+Current active profile: virtual-guest
+</pre>
+      <p>
+        Poza listą podpolecenie zwraca również aktywny profil. Identyczne 
+        działanie możemy otrzymać poprzez wydanie polecenia <em>tuned-adm</em>
+        wraz z podpoleceniem <em>active</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm active
+[sudo] password for user: 
+Current active profile: virtual-guest
+</pre>
+      <p>
+        Zmiany profilu dokonujemy za pomocą podpolecenia <em>profile</em> a
+        następnie podajemy nazwę profilu.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm profile balanced
+[user@server1 ~]$ sudo tuned-adm active
+Current active profile: balanced
+</pre>
+      <p>
+        Demon sam jest wstanie na podstawie naszej konfiguracji sprzętowej
+        dobrać odpowiedni profil. Aby uzyskać od niego taką informację wydajemy
+        polecenie z podpoleceniem <em>recommend</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm recommend
+virtual-guest
+</pre>
+      <p>
+        Profil rekomendowany możemy ustawić przez podanie jego nazwy jako
+        argumentu podpolecenia <em>profile</em> lub tak jak przedstawiłem to
+        na poniższym przykładzie.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm profile $(sudo tuned-adm recommend)
+</pre>
+      <p>
+        Jeśli dostosowanie wydajności nie jest już nam potrzebne możemy je
+        wyłączyć za pomocą podpolecenia <em>off</em>.
+      </p>
+<pre class="code-block">
+[user@server1 ~]$ sudo tuned-adm off
+[user@server1 ~]$ sudo tuned-adm active
+No current active profile.
+</pre>
+      <h3 id="exec12.1">Ćwiczenie 1: Zmiana domyślnego celu ładowania systemu</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em> zmień domyślny cel ładowania systemu
+        na <em>multi-user.target</em>. Uruchom ponownie maszynę i za pomocą
+        polecenia <em>systemctl</em> oraz <em>who</em> sprawdź zmiany.
+        Następnie wróć do standardowego celu i ponownie zweryfikuj zmiany.
+      </p>
+      <h3 id="exec12.2">Ćwiczenie 2: Zapis własnego komunikatu diagnostycznego</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em> zapis swój komunikat diagnostyczny.
+        Następnie wyświetl go w terminalu lub konsoli.
+      </p>
+      <h3 id="exec12.3">Ćwiczenie 3: Zastosowanie profili wydajności</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em> za pomocą polecenia <em>tuned-adm</em>
+        Wyświetl listę profil, następnie ustaw profil <em>balanced</em> i 
+        potwierdź to za pomocą odpowiednie podpolecenia. Ustaw profil 
+        rekomendowany, następnie wyłacz profil. Pamiętaj! Może być konieczna
+        ręczna aktywacja jednostki <em>tuned.service</em>. 
+      </p>
+      <h2 id="ch12summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale dowiedzieliśmy się w jaki sposób realizowany jest
+        ostatni etap rozruchu systemu. Poznaliśmy odpowiedzialne za nie
+        narzędzie oraz część jego możliwości. Dowiedzieliśmy się za co
+        odpowiada <em>rsyslogd</em> oraz gdzie możemy szukać zapisanych w
+        systemie komunikatów diagnostycznych. Na koniec poznaliśmy narzędzie
+        które możemy dostoswać wydajność naszego komputera do określonych
+        potrzeb. W następnym rodziale zajmiemy się podstawami obsługi dysków.
+      </p>
+      <h1 id="13.basicsofstoragemanagement">13. Podstawy zarządzania pamięcią masową</h1>
+      <p>
+        Dane na których operują użytkownicy, wyniki ich pracy czy programy
+        przez nich używane muszą być gdzieś składowane, aby co ponowne
+        uruchomienie komputera nie trzeba było konfigurować naszego środowiska
+        na nowo. Odziwo istnieją użytkownicy, który korzystają z dystrybucji
+        Linuksa w trybie <em>LiveCD</em> (systemu załadowanego z płyty do
+        pamięci komputera). Aby
+        móc wykorzystać komputer do składowania danych potrzebujemy specjalnych
+        urządzeń - <strong>dysków</strong>, i to zarządzaniem dyskami zajmiemy 
+        się w tym rozdziale.
+      </p>
+      <p>
+        W tym rozdziale powinna znaleźć się także obsługą dysków za pomocą
+        technologii <em>VDO</em>, jednak z <em>RHEL</em> 9 została ona
+        wciągnieta do <em>LVM</em>, które będą omawaiane w następnym rozdziale.
+        Także omówimy sobie <em>VDO</em> zaraz po nauczeniu się podstaw
+        <em>LVM</em>.
+      </p>
+      <p>
+        Do wykonania ćwiczeń oraz przykładów będzie nam potrzebna maszyna
+        oznaczona jak <em>server2</em> (patrz: rodział 1).
+      </p>
+      <h2 id="13.1.basicsterminology">13.1. Podstawowe pojęcia związane z zarządzaniem dyskami</h2>
+      <p>
+        Dyski w systemach uniksowych są urządzeniami blokowymi służącymi do
+        przechowywania danych. Dyski mogą być podzielone na logiczne części
+        nazwane <strong>partycjami</strong>. Partycje w ujęciu systemów
+        operacyjnych są podstawową jednoską związaną z zarządzaniem dyskami,
+        więc aby uzyskać dostęp do przestrzenii znajdującej się na dysku,
+        musimy utworzyć na nim partycję. Na tym polega zarządzanie dyskami,
+        na tworzeniu, zmienianiu i usuwaniu partycji. Informacja o partycjach
+        zwana <strong>tablicą partycji</strong>
+        znajdujących się na dysku znajduje się w pierwszym jego sektorze obok
+        programu rozruchowego. Partycjami możemy zarządzać za pomocą dwóch
+        schematów <strong>MBR</strong> oraz <strong>GPT</strong>.
+      </p>
+      <h3 id="13.1.1.mbr">13.1.1 Schemat partycjonowania MBR (Master Boot Record)</h3>
+      <p>
+        <em>MBR</em> jest jednym z pierwszych schematów partycjonowania,
+        został on ustanowiony dawno temu, więc posiada pewne ograniczenia
+        względem dysków stosowanych w obecnych komputerach.
+        Schemat ten jest domyślnym schematem wykorzystywanym przez komputery
+        obsługiwane z pomocą <em>BIOS</em>-u. Pozwala on podzielenie dysku na
+        maksymalnie 4 partycje podstawowe (służące do przechowywania danych).
+        Jeśli wymagana jest większa ilość, to wówczas należy poświęcić jedną
+        z partycji podstawowych na partycję rozszerzoną (kontener na
+        partycje logiczne), a następnie realizować dalsze partycjonowanie za
+        pomocą partycji logicznych (te partycje również służą do przechowywania
+        danych jednak różnią się one nieco do partycji podstawowych). Partycji
+        logicznych na dysku może być maksymalnie 11, co daje nam maksymalną
+        ilość partycji na dysku wynoszącą 14. W praktycje może
+        oznaczać, że to więcej niż kto kolwiek, kiedy kolwiek potrzebował.
+        Schemat ten ma jeszcze jedno ograniczenie otóż, nie może zaadresować
+        przestrzenii większej niż 2TB ze względu na to iż jest to 
+        <em>32-bitowy</em> schemat partycjonowania, jak wiemy obecne dostępne
+        dyski dysponują przestrzenią powyżej 10TB. 
+      </p>
+      <h3 id="13.1.2.gpt">13.1.2. Schemat patycjonowania GPT (GUID Partition Table)</h3>
+      <p>
+        Wraz rozwojem komputerów, wprowadzeniem nowego oprogramowania układowego
+        jakim jest <em>UEFI</em>, zaczął być wdrażany kompatybilny z nim 
+        schemat <em>GPT</em>. Schemat ten nie posiada podziałów na partycje
+        podstawowe, rozszerzone, logiczne itd. Wszystkie są podstawowe i może
+        być ich aż do 128. Maksymalna pojemność dysków, które GPT może
+        zaadresować jest nadal daleko po za zasięgiem ludzkości. Umożliwia on
+        także nadawanie etykiet partycjom co nie było możliwe w przypadku
+        <em>MBR</em>. Poza tym <em>GPT</em>, tworzy kopie obszaru na którym
+        zajduje się informacja o partycjach zaraz przed końcem dysku, co
+        również nie było realizowane w schemacie <em>MBR</em>.
+      </p>
+      <h3 id="13.1.3.partitionsonthesystem">13.1.3. Partycje dyskowe w systemie</h3>
+      <p>
+        Podczas partycjowania należy uważać aby nie nadpisać obecnie
+        istniejących partycji, albo nie zostawiać między nimi przerw marnując
+        tym samym przestrzeń dysku. Partycje w systemie są uprządkowane
+        za pomocą numeracji. W przypadku partycjonowania ze schematem <em>MBR</em>,
+        partycje podstawowe otrzymują numery od 1 do 4, natomiast numeracja
+        dysków logicznych rozpocznyna sie od 5. W przypadku schematu <em>GPT</em>
+        numeracja rozpoczynia się od 1. Za pomocą polecenia 
+        <strong>lsblk</strong>
+        możemy wświetlić dostępne w systemie urządzenia blokowe:
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ lsblk
+NAME          MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
+sr0            11:0    1    8G  0 rom  /mnt
+vda           252:0    0   10G  0 disk 
+├─vda1        252:1    0    1G  0 part /boot
+└─vda2        252:2    0    9G  0 part 
+  ├─rhel-root 253:0    0    8G  0 lvm  /
+  └─rhel-swap 253:1    0    1G  0 lvm  [SWAP]
+vdb           252:16   0  256M  0 disk 
+vdc           252:32   0  256M  0 disk 
+vdd           252:48   0  256M  0 disk 
+vde           252:64   0  256M  0 disk 
+vdf           252:80   0    4G  0 disk 
+vdg           252:96   0    1G  0 disk 
+vdh           252:112  0    1G  0 disk 
+</pre>
+      <p>
+        W moim przypadku dyski noszą nazwy <code class="code-inline">vdX</code>,
+        gdzie <em>X</em> to litera porządkowa dysku zatem pierwszy dysk to
+        <em>vda</em>, drugi <em>vdb</em> i tak dalej. Przy niektóych nazwach
+        widnieją cyfry, te nazwy to nazwy partycji. W Twoim przypadku
+        oznaczenia dysku mogą być nieco inne, ponieważ ja zamiast 
+        <em>VirtualBox</em>
+        używam wirtualizacji <em>KVM</em> wraz ze innym sterownikiem
+        odpowiedzialnym za obsługę pamięci masowych. Nie miej jednak polecenie
+        z przykładu zwraca nazwę urządzenia, przedstawiając dysk w postaci
+        drzewa, zwraca rozmiar zarówno dysków jak i partycji, typ urządzenia
+        oraz punkt montowania partycji w systemie.
+        Typ <code class="code-inline">lvm</code> oznacza logiczne woluminy
+        <em>LVM</em> (będzie o tym w następny rozdziale).
+      </p>
+      <h3 id="13.1.4.storagemanagementools">13.1.4. Narzędzia do zarządzania pamięcią masową</h3>
+      <p>
+        W <em>RHEL</em> dostępnych jest wiele narzędzi odpowiedzialnych za 
+        zarządzanie dyskami. Każda technologia wdrożona do systemu posiada
+        swoje oprogramowanie. W tym rozdziale skupimy się wyłączenia na dwóch
+        z nich. Na programie <strong>parted</strong> pozwalającym na obsługę
+        schematu <em>MBR</em> oraz 
+        <strong>gdisk</strong> obsługującym schemat <em>GPT</em>. Ze względu
+        na to iż będzie pracować z urządzeniami komputera, do wykonywania
+        czynności przy użyciu tych narzędzi będą potrzebne uprawnienia
+        administratora.
+      </p>
+      <h3 id="13.1.5.thinprovisioning">13.1.5. Technologia thin provisioning</h3>
+      <p>
+        Omawiając podstawy zarządzania dyskami należałoby wspomnieć o
+        technologii <strong>thin provisioning</strong> jest technika polegająca
+        na przedstawianiu logiczynych zasobów dyskowy znacznie większych niż
+        są one w rzeczywistości. Przez utworzone w ten sposób woluminy
+        posiadają one znaczenie wiekszą pojemność niż utrzymujące je fizyczne
+        urządzenia, kiedy
+        dochodzi się do poziomu wyczerpywania fizycznego miejsca, rozszerza się 
+        wolumin o
+        kolejne fizyczne dyski. Dzięki tej technologii można logicznie założyć
+        duży zasób dyskowy do wykorzystania i jeśli rzeczywiście będzie 
+        potrzeba
+        użycia takie ilości przestrzeni będzie się dodwać stopniowo kolejne
+        dyski nie wydając pieniędzy na przestrzeń, której nigdy nie
+        wykorzystamy.
+      </p>
+      <h2 id="13.2.mbrpartitioning">13.2. Zarządzenie partycjami ze schematem MBR</h2>
+      <p>
+        W tym podrozdziale nauczymy się zarządzać partycjami ze schematem
+        <em>MBR</em> przy użyciu narzędzia <em>parted</em>. Tego polecenia
+        możemy używać albo w trybie interaktywnym albo bezpośrednio z wiersza
+        polecenia. Poniższe czynności będą opierać się wyłącznie na obsłudze
+        z poziomu wiersza polecenia. Na początek wyświetlimy sobie zawartość
+        dysku.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo parted /dev/vdb print
+Error: /dev/vdb: unrecognised disk label
+Model: Virtio Block Device (virtblk)                                      
+Disk /dev/vdb: 268MB
+Sector size (logical/physical): 512B/512B
+Partition Table: unknown
+Disk Flags: 
+</pre>
+      <p>
+        Za pomocą podpolecenia <code class="code-inline">print</code> możemy
+        wyświetlić informacje na temat dysku oraz znajdujące się na nim
+        partycje. Zwróćmy uwagę na pierwszą linię, mówi ona o tym, że nie
+        znaleziony etykiety dysku, w tym przypadku chodzi o schemat
+        partycjonowania (tablicę partycji). Zapamiętajmy też składnie tego 
+        polecenia, gdyż pierwszym
+        argumentem zawsze jest nazwa urządzenia następnie podpolecenie
+        wykonujące określoną czynność. Poniższe polecenie nada etykietę
+        <em>msdos</em> ustawiając tym samym schemat na <em>MBR</em>.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo parted /dev/vdb mklabel msdos
+[sudo] password for user: 
+Information: You may need to update /etc/fstab.
+
+[user@server2 ~]$ sudo parted /dev/vdb print                      
+Model: Virtio Block Device (virtblk)
+Disk /dev/vdb: 268MB
+Sector size (logical/physical): 512B/512B
+Partition Table: msdos
+Disk Flags: 
+
+Number  Start  End  Size  Type  File system  Flags
+</pre>
+      <p>
+        Teraz kiedy zdecydowaliśmy o schemacie partycjonowania, możemy utworzyć
+        partycję. Przy tworzeniu partycji jest pewien haczyk. Otóż podczas
+        tworzenia partycji 
+        w <em>parted</em> należy podać początek oraz koniec.
+        Zatem chcąc stworzyć partycję o wielkości
+        100 MB podajemy początek 1 (co jest równe 1M, jest również pierwsza
+        partycja więc rozpoczyna się od pierwszego megabajta dysku) 
+        101M stosując również skróty jednostek 
+        odnoszące się wyłacznie do wielkorotności jak <em>M</em> - megabajt,
+        <em>G</em> - gigabajt itd. Następną partycję moglibyśmy zacząć od 101M
+        i ustawiając jej koniec, na koniec pozostałej wolnej części dysku za
+        pomocą takiego wyrażenia jak: <em>100%Free</em>.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo parted /dev/vdb mkpart primary 1 101M
+[sudo] password for user: 
+Information: You may need to update /etc/fstab.
+
+[user@server2 ~]$ sudo parted /dev/vdb print
+Model: Virtio Block Device (virtblk)
+Disk /dev/vdb: 268MB
+Sector size (logical/physical): 512B/512B
+Partition Table: msdos
+Disk Flags: 
+
+Number  Start   End    Size    Type     File system  Flags
+ 1      1049kB  101MB  99.6MB  primary
+
+</pre>
+      <p>
+        Po podpoleceniu podajemy rodzaj partycji w tym przypadku jest to
+        <code class="code-inline">primary</code>, następnie podajemy jej
+        początek <code class="code-inline">1</code> oraz koniec
+        <code class="code-inline">101M</code>. Tak utworzą partycję możemy
+        teraz usunąć za pomocą podpolecenia <em>rm</em>, które przyjmuje
+        numer jako argument.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo parted /dev/vdb rm 1
+[sudo] password for user: 
+Information: You may need to update /etc/fstab.
+
+[user@server2 ~]$ sudo parted /dev/vdb print                              
+Model: Virtio Block Device (virtblk)
+Disk /dev/vdb: 268MB
+Sector size (logical/physical): 512B/512B
+Partition Table: msdos
+Disk Flags: 
+
+Number  Start  End  Size  Type  File system  Flags
+</pre>
+      <h2 id="13.3.gptpartitioning">13.3. Zarządzanie partycjami ze schematem GPT</h2>
+      <p>
+        Zarządzanie partycjami ze schematem <em>GPT</em> różni się od tego
+        ze schematem <em>MBR</em>. Nie tylko tym, że wykorzystuje się do tego
+        inne narzędzia. Te narzędzia mają również inną zasadę działania. Do
+        zarządzania partycjami <em>GPT</em> wykorzystuje się narzędzie
+        <strong>gdisk</strong>, które jest narzędziem interaktywnym, jego
+        różnica polega na tym, że nie zapisze ono zmian na dysku do póki nie
+        użyjemy odpowiednie polecenia. Polecenia w tym narzędziu przyjmują
+        postać pojedynczych liter, a ich listę możemy uzyskać w momencie
+        wydania polecenia znaku zapytania (<strong>?</strong>). Polecenie
+        uruchamia się podając nazwę urządzenia jako argument.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo gdisk /dev/vdd
+GPT fdisk (gdisk) version 1.0.7
+
+Partition table scan:
+  MBR: not present
+  BSD: not present
+  APM: not present
+  GPT: not present
+
+Creating new GPT entries in memory.
+
+Command (? for help): ?
+b      back up GPT data to a file
+c      change a partition's name
+d      delete a partition
+i      show detailed information on a partition
+l      list known partition types
+n      add a new partition
+o      create a new empty GUID partition table (GPT)
+p      print the partition table
+q      quit without saving changes
+r      recovery and transformation options (experts only)
+s      sort partitions
+t      change a partition's type code
+v      verify disk
+w      write table to disk and exit
+x      extra functionality (experts only)
+?      print this menu
+
+Command (? for help): 
+</pre>
+      <p>
+        Polecenie na początku zwróci listę używanych na dysku schematów tablicy
+        partycji. Następnie wydałem odpowiednie polecenie aby wyświetić listę
+        dostępnych polecenień. Jak widać na dysku nie ma żadnej tablicy za
+        pomocą polecenia <em>o</em> zostanie stworzona nowa tablica
+        partycji (miejsce z informacjami o partycjach dysku) w schemacie 
+        <em>GPT</em>.
+      </p>
+<pre class="code-block">
+Command (? for help): o       
+This option deletes all partitions and creates a new protective MBR.
+Proceed? (Y/N): Y
+Command (? for help): w
+
+Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
+PARTITIONS!!
+
+Do you want to proceed? (Y/N): y
+OK; writing new GUID partition table (GPT) to /dev/vdd.
+The operation has completed successfully.
+</pre>
+      <p>
+        Poza utworzeniem nowej tablicy partycji ze schematem <em>GPT</em>,
+        program zabezpieczy <em>MBR</em> dla wstecznej zgodności z komputerami
+        obsługiwanymi przez <em>BIOS</em>. Na koniec wyszedłem, aby zapisać
+        zmiany i uruchomiłem program ponownie.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo gdisk /dev/vdd
+GPT fdisk (gdisk) version 1.0.7
+
+Partition table scan:
+  MBR: protective
+  BSD: not present
+  APM: not present
+  GPT: present
+
+Found valid GPT with protective MBR; using GPT.
+
+Command (? for help): 
+</pre>
+      <p>
+        Teraz program przedstawia, że odnalazł prawidłową tablicę ze schematem
+        <em>GPT</em> oraz zabezpieczony <em>MBR</em>. Teraz aby utworzyć
+        partycję użyje opcji <em>n</em> następnie pozostawie część domyślnych
+        informacji. Podam tylko jej wielkość w linii oznaczonej jako ostatnii
+        sektor. Wiecej szczegółów znajduje się na przykładzie poniżej:
+      </p>
+<pre class="code-block">
+Command (? for help): n
+Partition number (1-128, default 1): 
+First sector (34-524254, default = 2048) or {+-}size{KMGTP}: 
+Last sector (2048-524254, default = 524254) or {+-}size{KMGTP}: +100M
+Current type is 8300 (Linux filesystem)
+Hex code or GUID (L to show codes, Enter = 8300): 
+Changed type of partition to 'Linux filesystem'
+
+Command (? for help): p   
+Disk /dev/vdd: 524288 sectors, 256.0 MiB
+Sector size (logical/physical): 512/512 bytes
+Disk identifier (GUID): F5BE61A0-220E-409E-AB2F-18AFDD56D410
+Partition table holds up to 128 entries
+Main partition table begins at sector 2 and ends at sector 33
+First usable sector is 34, last usable sector is 524254
+Partitions will be aligned on 2048-sector boundaries
+Total free space is 319421 sectors (156.0 MiB)
+
+Number  Start (sector)    End (sector)  Size       Code  Name
+   1            2048          206847   100.0 MiB   8300  Linux filesystem
+
+</pre>
+      <p>
+        Warto zwrócić uwagę na to w jaki sposób została podana wielkość
+        partycji (<code class="code-inline">+100M</code>). Za pomocą opcji
+        <em>p</em> możemy wyświetlić zmiany jakie zaszły póki co w pamięci. 
+        Więc żeby zmiany, które zostały utworzone zapisać podajemy polecnie 
+        <em>w</em>, nastepnie potwierdzamy zapisanie zmian.
+      </p>
+<pre class="code-block">
+Command (? for help): w
+
+Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
+PARTITIONS!!
+
+Do you want to proceed? (Y/N): y
+OK; writing new GUID partition table (GPT) to /dev/vdd.
+The operation has completed successfully.
+</pre>
+      <p>
+        Aby usunąc partycję podajemy opcję <em>d</em>, która następnie
+        poprosi o podanie numery partycji o ile jest więcej niż jedna. Jeśli
+        jest tylko jedna automatycznie ją usunie.
+      </p>
+<pre class="code-block">
+[user@server2 ~]$ sudo gdisk /dev/vdd
+[sudo] password for user: 
+GPT fdisk (gdisk) version 1.0.7
+
+Partition table scan:
+  MBR: protective
+  BSD: not present
+  APM: not present
+  GPT: present
+
+Found valid GPT with protective MBR; using GPT.
+
+Command (? for help): d
+Using 1
+
+Command (? for help): p
+Disk /dev/vdd: 524288 sectors, 256.0 MiB
+Sector size (logical/physical): 512/512 bytes
+Disk identifier (GUID): F5BE61A0-220E-409E-AB2F-18AFDD56D410
+Partition table holds up to 128 entries
+Main partition table begins at sector 2 and ends at sector 33
+First usable sector is 34, last usable sector is 524254
+Partitions will be aligned on 2048-sector boundaries
+Total free space is 524221 sectors (256.0 MiB)
+
+Number  Start (sector)    End (sector)  Size       Code  Name
+</pre>
+      <p>
+        Oczywiście jeśli przypadkowo coś usuneliśmy lub zmieniliśmy możemy
+        użyć opcji <em>q</em>, aby zakończyć działanie programu bez zapisywania
+        zmian na dysku.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Znajomość zarówno <em>parted</em> oraz <em>gdisk</em> jest
+        wystarczająca, aby zrealizować proste zadania związane z zarządzaniem
+        dyskami na egzaminie.
+      </p>
+      <h3 id="exec13.1">Ćwiczenie 1: Zarządzanie partycjami za pomocą parted</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em> utwórz jedną 100 MB partycję na
+        jednym z dysków o pojemności 250 MB. Użyj do tego tablicy o schemacie
+        <em>MBR</em>. Do utworzenia partycji użyj narzędzia <em>parted</em> z
+        poziomu wiersza polecenia. Nastepnie utworz taką samą partycję ale w
+        trybie interaktywnym tego polecenia. Wyświetl informacje na temat
+        dysku. Na koniec usuń obie partycje używając wiersza polecenia. 
+      </p>
+      <h3 id="exec13.2">Ćwiczenie 2: Zarządzanie partycjami za pomocą gdisk</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em> utwórz przy tablicy w schemacie
+        <em>GPT</em> dwie partycje po 80MB każda. Wyświetl informacje na temat
+        dysku. Jeśli chcesz usuń te partycje.
+      </p>
+      <h2 id="ch13summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale poznaliśmy podstawy teoretyczne oraz praktyczne
+        zarządzania dyskami. Nauczyliśmy się tworzenia oraz usuwania partycji
+        przy różnych schematach tablic. W następnym rozdziale przejdziemy do
+        bardziej zaawansowanych czynności związanych z zarządzaniem pamięcią
+        masową w <em>RHEL</em>.
+      </p>
+      <h1 id="14.advancedstoragemanagement">14. Zaawansowane zarządzanie pamięcią masową</h1>
+      <p>
+        W tym rodziale zajmiemy się bardziej zawansowanymi zagadnieniami
+        związanymi zarządzaniem pamiecią masową. W tym rozdziale poruszymy
+        również pominięty z względu na zmiany w <em>RHEL</em> podrozdział
+        związany z bardziej efektywnym wykorzystaniem przestrzeni na dysku
+        dzięki <em>VDO</em>. Kolejnym zagadnienieniem będzie <em>LVM</em>,
+        który pozwala spojrzeć nieco inaczej na urządzenia służące do
+        przechowywania danych. Ostatnim tematem będzie <em>Stratis</em>,
+        który łączy ze sobą kilka komponentów systemu pozwalających na
+        stworzenie stablinego i wydajnego systemu plików (o systemach plików
+        będzie w następnym rozdziale).
+      </p>
+      <h2 id="14.1.lvm">14.1. Zarządzanie pamięcią masową przy użyciu LVM</h2>
+      <p>
+        <strong>LVM</strong>, czyli <em>Logical Volume Manager</em> pozwala
+        inaczej spojrzeć na dostępne w naszych komputerach dyski. Za pomocą
+        tego narzędzia możemy zebrać wszystkie dostępne w systemie dyski
+        zainicjować je, aby były gotowe do pracy z <em>LVM</em>, wówczas
+        dyski stają się <strong>woluminami fizycznymi</strong>. Woluminy
+        fizyczne łączy się w <strong>grupę woluminów</strong>, która staje
+        się pulą to tworzenie nowych urządzeń dyskowych bazujących na miejscu
+        dostępnym w grupie. Takie urządzenia noszą nazwę
+        <strong>woluminów logicznych</strong>. W ujęciu <em>LVM</em>
+        najmiejszą logiczną jednostką alokacji przestrzeni dyskowej są 
+        <strong>ekstenty</strong>. Ekstenty dzielą się na logiczne będące
+        cząstkami woluminów logicznych oraz na fizyczne będące elementami
+        woluminów fizycznych. Ekstenty podczas tworzenia grupy woluminów
+        mają domyślną wielkość wynoszącą około <strong>4 MB</strong>. 
+        Oczywiście można to zmienić. A wielkości ekstentów (logicznych i
+        fizycznych) nie muszą być sobie równe. Pojęcie ekstenów będzie 
+        potrzebne nam przy <em>VDO</em>.
+      </p>
+      <p>
+        Elementy logiczne <em>LVM</em> są bardzo eleastyczne, może je dodawać
+        usuwać, rozszerzać, zmniejszać i zmieniać wcześniej nadane nazwy.
+        Tym się właśnie zajmiemy w tym rodziale. Oczywiście będziemy pracować
+        z urządzeniami więc niezbędne będą uprawnienia administratora.
+      </p>
+      <h3 id="14.1.1.createpv">14.1.1. Tworzenie woluminów fizycznych</h3>
+      <p>
+        Aby rozpocząć pracę z <em>LVM</em> musimy przekształcić dysk lub
+        partycję aby nadawała się do pracy z tym rozwiązaniem. Na tych
+        urządzeniach blokowych zostaną utworzone specjalne struktury, dzięki
+        czemu będzie można później włączyć je do grupy.
+      </p>
+      <p>
+        Chcąc użyć partycji jako woluminu fizycznego tworzmy partycje, bez
+        znaczenia czy jest schemat tablicy partycji GPT czy MBR, następnie
+        partycji ustawiamy flagę <em>lvm</em>. Tak przygotowana partycja
+        jest gotowa by użyć jej jako woluminu fizycznego. Poniżej znajduje się
+        przykład przedstawiający jak to zrealizować.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo gdisk /dev/vdb
+GPT fdisk (gdisk) version 1.0.7
+
+Partition table scan:
+  MBR: not present
+  BSD: not present
+  APM: not present
+  GPT: not present
+
+Creating new GPT entries in memory.
+
+Command (? for help): o
+This option deletes all partitions and creates a new protective MBR.
+Proceed? (Y/N): Y
+
+Command (? for help): p
+Disk /dev/vdb: 524288 sectors, 256.0 MiB
+Sector size (logical/physical): 512/512 bytes
+Disk identifier (GUID): 66CCB514-9659-461D-834B-1661E9D112F4
+Partition table holds up to 128 entries
+Main partition table begins at sector 2 and ends at sector 33
+First usable sector is 34, last usable sector is 524254
+Partitions will be aligned on 2048-sector boundaries
+Total free space is 524221 sectors (256.0 MiB)
+
+Number  Start (sector)    End (sector)  Size       Code  Name
+
+Command (? for help): n
+Partition number (1-128, default 1): 
+First sector (34-524254, default = 2048) or {+-}size{KMGTP}: 
+Last sector (2048-524254, default = 524254) or {+-}size{KMGTP}: +128M
+Current type is 8300 (Linux filesystem)
+Hex code or GUID (L to show codes, Enter = 8300): 8e00
+Changed type of partition to 'Linux LVM'
+
+Command (? for help): w
+
+Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
+PARTITIONS!!
+
+Do you want to proceed? (Y/N): y
+OK; writing new GUID partition table (GPT) to /dev/vdb.
+The operation has completed successfully.
+</pre>
+      <p>
+        Tak utworzoną partycje możemy zainicjować jako wolumin fizyczny za
+        pomocą polecenia <strong>pvcreate</strong>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo pvcreate /dev/vdb1
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Physical volume "/dev/vdb1" successfully created.
+</pre>
+      <p>
+        Teraz wolumin nadaje się do podłączenia do grupy.
+      </p>
+      <p>
+        Inicjowanie całych dysków jest o wiele prostsze. Wystarczy użyć
+        polecenie <em>pvcreate</em> i podać nazwę urządzenia jako argument.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo pvcreate /dev/vdc
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Physical volume "/dev/vdc" successfully created.
+</pre>
+      <p>
+        Listę dostępnych w systemie woluminów fizycznych możemy wyświetlić
+        za pomocą polecenia <strong>pvs</strong>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo pvs
+[sudo] hasło użytkownika user: 
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  PV         VG   Fmt  Attr PSize   PFree  
+  /dev/vda2  rhel lvm2 a--  &lt;11,00g      0 
+  /dev/vdb1       lvm2 ---  128,00m 128,00m
+  /dev/vdc        lvm2 ---  256,00m 256,00m
+</pre>
+      <p>
+        Kolumny oznaczają kolejno: fizyczny wolumin 
+        (<code class="code-inline">PV</code>), grupę do której należy fizyczny
+        wolumin (<code class="code-inline">VG</code>), format
+        (<code class="code-inline">Fmt</code>), atrybuty
+        (<code class="code-inline">Attr</code>, wartości poszczególnych bitów
+        są rozpisane w na stronie podręcznika), rozmiar fizyczny
+        (<code class="code-inline">PSize</code>) oraz fizyczną ilość wolnego
+        miejsca (<code class="code-inline">PFree</code>).
+      </p>
+      <h3 id="14.1.2.vgcreate">14.1.2. Tworzenie grup woluminów</h3>
+      <p>
+        Posiadając już odpowiednie zasoby w postaci woluminów fizycznych,
+        możemy utworzyć grupę woluminów, aby móc zarządzać zaawansowanymi
+        właściwościami <em>LVM</em>. Grupy tworzone są za pomocą polecenia
+        <strong>vgcreate</strong>. Utworzę teraz grupę z wcześniej stworzonych
+        woluminów.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgcreate vg_course /dev/vdb1 /dev/vdc
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Volume group "vg_course" successfully created
+</pre>
+      <p>
+        Polecenie przyjmuje jako pierwszy argument nazwę grupy a następnie
+        wchodzące w jej skład fizyczne woluminy. Listę utworzonych w systemie
+        grup możemy wyświetlić za pomocą polecenia <strong>vgs</strong>.
+        Natomiast bardziej szczegółowe informacje na temat grupy możemy
+        uzyskać więcej informacji za pomocą polecenia <strong>vgdisplay</strong>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgs
+[sudo] hasło użytkownika user: 
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  VG        #PV #LV #SN Attr   VSize   VFree  
+  rhel        1   2   0 wz--n- &lt;11,00g      0 
+  vg_course   2   0   0 wz--n- 376,00m 376,00m
+</pre>
+      <p>
+        Polecenie to zwraca informacje podobne do poprzedniego polecenia
+        <em>pvs</em>. Dodatkowe kolumny zwracają informacje na temat
+        ilość woluminów fizycznych w grupie
+        (<code class="code-inline">#PV</code>), ilość woluminów logicznych
+        (<code class="code-inline">#LV</code>) oraz ilość <em>snapshotów</em> w
+        grupie woluminów. Reszta kolumn jest podobna do tych informacji
+        zwracanych przez <em>pvs</em>. Innym narzędziem zwracającym więcej
+        informacji na temat grupy woluminów jest <strong>vgdisplay</strong>,
+        jako argument przyjmuje ona nazwę grupy, jeśli zostanie pominięta
+        polecenie zwróci informacje na temat wszystkich grup w systemie.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgdisplay vg_course 
+[sudo] hasło użytkownika user: 
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  --- Volume group ---
+  VG Name               vg_course
+  System ID             
+  Format                lvm2
+  Metadata Areas        2
+  Metadata Sequence No  1
+  VG Access             read/write
+  VG Status             resizable
+  MAX LV                0
+  Cur LV                0
+  Open LV               0
+  Max PV                0
+  Cur PV                2
+  Act PV                2
+  VG Size               376,00 MiB
+  PE Size               4,00 MiB
+  Total PE              94
+  Alloc PE / Size       0 / 0   
+  Free  PE / Size       94 / 376,00 MiB
+  VG UUID               g4X6FW-P1fu-jS0t-UaGg-8mIK-Kv0J-2bLWSD
+</pre>
+      <p>
+        Polecenie to zwraca rozmiar fizycznych ekstentów, który w tym
+        przypadku posiada wartość domyślną. Rozmiar ten możemy zmienić
+        podając opcje <em>-s</em> oraz wielkość fizycznych ekstentów jako
+        argument opcji podczas tworzenia grupy. Chcąc wydobyć konkretne
+        informacje z tego polecenia możemy posłużyć się poleceniem 
+        <em>grep</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgdisplay vg_course | grep 'PE Size'
+[sudo] hasło użytkownika user: 
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  PE Size               4,00 MiB
+</pre>
+      <h3 id="14.1.3.lvcreate">14.1.3. Tworzenie woluminów logicznych LVM</h3>
+      <p>
+        Do tworzenia woluminów logicznych służy polecenie 
+        <strong>lvcreate</strong>. Wydając to polecenie wraz z opcją
+        <em>--help</em>, zostaną nam zwrócone wszystkie możliwe rodzaje
+        segmentów
+        woluminów logicznych. W tym materiale będą nas interesować tylko dwa
+        <em>linear</em> (liniowy, zwykły) oraz <em>VDO</em>. O 
+        <em>VDO</em> będzie w
+        następnym podrozdziale. Zatem do stworzenia liniowego woluminu
+        logicznego potrzebujemy wielkości (opcja <em>-L</em>) oraz nazwy grupy 
+        w której ma zostać stworzony. 
+        Inną dość przydatną opcją, niezależną od rodzaju woluminu
+        jest opcja <em>-n</em>, która pozwala na nadanie nazwy woluminowi.
+        Teraz utworzę wolumin logiczny w grupie, którą wcześniej utworzyłem.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvcreate -L 100MB -n lvol0 vg_course
+  Logical volume "lvol0" created.
+</pre>
+      <p>
+        Czasami podana wielkość woluminu może zostać zaokrąglona, ze względu
+        na potrzebę użycia okrągłej liczby ekstentów. W przypadku tego woluminu
+        zostały użyte 25 ekstenty (25 x 4MB = 100MB), co możemy podejrzeć 
+        wydając polecenie
+        <em>vgdisplay</em> z opcją <em>-v</em> Przez co zwróci ona bardziej
+        szczegółowe informacje na temat grupy, w tym informacje na temat
+        woluminów logicznych w niej zawartych.
+      </p> 
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgdisplay -v vg_course
+...
+  --- Logical volume ---
+  LV Path                /dev/vg_course/lvol0
+  LV Name                lvol0
+  VG Name                vg_course
+  LV UUID                Z2cH37-sWGu-NEIR-JoKN-AT5M-o5EI-d8QmKU
+  LV Write Access        read/write
+  LV Creation host, time rhel90, 2022-07-22 11:35:47 +0200
+  LV Status              available
+  # open                 0
+  LV Size                100,00 MiB
+  Current LE             25
+  Segments               1
+  Allocation             inherit
+  Read ahead sectors     auto
+  - currently set to     256
+  Block device           253:2
+...
+</pre>
+      <p>
+        Innm narzędziem, które zwraca informacje na temat woluminów logicznych
+        jest <strong>lvs</strong>. Zwraca ono podobne informacje do <em>vgs</em>
+        na przykład:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvs
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  LV   VG   Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
+  root rhel -wi-ao---- 9,79g                                                    
+  swap rhel -wi-ao---- 1,20g       
+</pre>
+      <p>
+        Informacje zawierają nazwę woluminu 
+        (<code class="code-inline">LV</code>),
+        grupę woluminów (<code class="code-inline">VG</code>), atrybuty
+        (<code class="code-inline">Attr</code>) oraz wielkości
+        (<code class="code-inline">LSize</code>).
+      </p>
+      <p>
+        Poza klasyczną wielkością podawną w wielkrotnościach bajtów, wielkość
+        woluminu możemy podawać ilości ekstentów, służy do tego opcją 
+        <em>-l</em>.
+      </p>
+      <p>
+        Tak utworzone woluminy są pełno prawnymi urządzeniami blokowymi
+        przypominającymi partycję. Możemy zainstalować na nich odpowiedni 
+        system
+        plików (będzie o tym w następnym rozdziale), zamontować je w systemie
+        i wykorzystać do przechowywania danych.
+      </p>
+      <h3 id="14.1.4.rename">14.1.4. Zmiana nazwy elementów LVM</h3>
+      <p>
+        Nazwę możemy zmienić takim elementom jak wolumin logiczny - polecenie
+        <strong>lvrename</strong> oraz grupa woluminów - polecenie
+        <strong>vgrename</strong>. Polecenie <em>lvrename</em> wymaga podania 
+        scieżki do woluminu (znajdziemy go za pomocą polecenia 
+        <em>vgdisplay -v</em>) oraz nowej nazwy. Możemy ominąć potrzebę
+        podawania ścieżki do woluminu, poprzedzając jego nazwę, nazwą grupy. 
+        Ze zmianą nazwy grupy jest o wiele prościej wystarczy podać poleceniu
+        <em>vgrename</em> starą nazwę grupy oraz nową.
+      </p>
+      <p>
+        Zmiana nazwy woluminu za pomoca ścieżki woluminu:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvrename /dev/vg_course/lvol0 rhelvol0
+  Renamed "lvol0" to "rhelvol0" in volume group "vg_course"
+</pre>
+      <p>
+        Zmiana nazwy woluminu za pomocą nazwy grupy:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvrename vg_course rhelvol0 rhel9vol0
+  Renamed "rhelvol0" to "rhel9vol0" in volume group "vg_course"
+</pre>
+      <p>
+        Zmiana nazwy grupy:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgrename vg_course rhcsa9
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Volume group "vg_course" successfully renamed to "rhcsa9"
+</pre>
+      <h3 id="14.1.5.extend">14.1.5. Rozszerzanie elementów LVM</h3>
+      <p>
+        Za pomocą poleceń <strong>vgextend</strong> możemy rozszerzyć grupę
+        woluminów o dodatkowe woluminy fizyczne. Natomiast za pomocą polecenia
+        <strong>lvextend</strong> możemy rozszerzyć wolumin logiczny o
+        dodatkowe miejsce, przy czym wolumin należy podać w postaci ścieżki. 
+      </p>
+      <p>
+        Rozszerzenie grupy woluminów o kolejny wolumin fizyczny:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgextend rhcsa9 /dev/vdd
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Volume group "rhcsa9" successfully extended
+</pre>
+      <p>
+        Rozszerzenie woluminów logicznych o dodatkową przestrzeń:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvextend -L +100M /dev/rhcsa9/rhel9vol0
+  Size of logical volume rhcsa9/rhel9vol0 changed from 100,00 MiB (25 extents) to 200,00 MiB (50 extents).
+  Logical volume rhcsa9/rhel9vol0 successfully resized.
+</pre>
+      <p>
+        Zwróćmy uwagę w jaki sposób podajemy wielkość o którą chcemy rozszerzyć
+        podany wolumin.
+      </p>
+      <h3 id="14.1.6.reduce">14.1.6. Zmniejszanie elementów LVM</h3>
+      <p>
+        Za pomocą kolejnej pary poleceń <strong>lvreduce</strong>, oraz
+        <strong>vgreduce</strong> możemy zmniejszyć ilość miejsca w
+        przypadku woluminów logicznych oraz usunąć z grupy okreslone woluminy
+        fizyczne. Przyczym warto dodać, o ile rozszerzenie miejsca nie było
+        działaniem destrukcyjnym (gdy np. na woluminach logicznych znajdują
+        sie systemy plików oraz dane) to zmieniejszanie z całą pewnością jest
+        takim działaniem.
+      </p>
+      <p>
+        Zmniejszenie woluminu logicznego o 50 MB, przy czym wielkość możemy
+        podać odejmując podaną wartość lub podając nową wielkość dla
+        woluminu. Obie formy są poprawne.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvreduce -L -50M /dev/rhcsa9/rhel9vol0
+[sudo] hasło użytkownika user: 
+  Rounding size to boundary between physical extents: 48,00 MiB.
+  WARNING: Reducing active logical volume to 152,00 MiB.
+  THIS MAY DESTROY YOUR DATA (filesystem etc.)
+Do you really want to reduce rhcsa9/rhel9vol0? [y/n]: y
+  Size of logical volume rhcsa9/rhel9vol0 changed from 200,00 MiB (50 extents) to 152,00 MiB (38 extents).
+  Logical volume rhcsa9/rhel9vol0 successfully resized.
+
+[user@rhel90 ~]$ sudo lvreduce -L 100M /dev/rhcsa9/rhel9vol0
+  WARNING: Reducing active logical volume to 100,00 MiB.
+  THIS MAY DESTROY YOUR DATA (filesystem etc.)
+Do you really want to reduce rhcsa9/rhel9vol0? [y/n]: y
+  Size of logical volume rhcsa9/rhel9vol0 changed from 152,00 MiB (38 extents) to 100,00 MiB (25 extents).
+  Logical volume rhcsa9/rhel9vol0 successfully resized.
+</pre>
+      <p>
+        Usunięcie z grupy jednego z woluminów fizycznych. 
+      </p> 
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgreduce rhcsa9 /dev/vdd
+[sudo] hasło użytkownika user: 
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Removed "/dev/vdd" from volume group "rhcsa9"
+</pre>
+      <h3 id="14.1.7.undo">14.1.7. Wycofywanie zmian LVM na dyskach</h3>
+      <p>
+        Wycofywanie zmian rozpoczniemy od usunięcia woluminów logicznych a
+        służy temu polecenie <strong>lvremove</strong>, aby usunąć wolumin
+        podaje się nazwę grupy oraz nazwę woluminu:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvremove rhcsa9 rhel9vol0
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+Do you really want to remove active logical volume rhcsa9/rhel9vol0? [y/n]: y
+  Logical volume "rhel9vol0" successfully removed.
+  Volume group "rhel9vol0" not found
+  Cannot process volume group rhel9vol0
+</pre>
+      <p>
+        Kombinację tych dwóch wartości możemy zastąpić ścieżką do woluminu, a
+        potwierdzenie możemy wymusić za pomocą opcji <em>-f</em>. 
+      </p>
+      <p>
+        Po usunięciu woluminów przyszedł czas na usunięcie grupy woluminów, do
+        tego należy wykorzystać polecenie <strong>vgremove</strong>. Polecenie
+        to przyjmuje nazwę grupy jako argument.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgremove rhcsa9
+[sudo] hasło użytkownika user: 
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Volume group "rhcsa9" successfully removed
+</pre>
+      <p>
+        Po usunięciu grupy pozostaje tylko wyczyszcznie dysków ze wszelkich
+        struktur stworzonych na potrzeby <em>LVM</em>. Polecenie, które wykona
+        tę czynność to <strong>pvremove</strong>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo pvremove /dev/vdb1 /dev/vdc
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Labels on physical volume "/dev/vdb1" successfully wiped.
+  Labels on physical volume "/dev/vdc" successfully wiped.
+</pre>
+      <h2 id="14.2.vdo">14.2. Wykorzystanie VDO do zarządzania pamięciami masowymi</h2>
+      <p>
+        <strong>VDO</strong>, czyli <em>Virtual Disk Optimizer</em> jest 
+        technologia zarządzania pamięciami masowymi pozwalająca na 
+        zaoszczędzenie wykorzystywanej przestrzeni, zwiększenie wydajności
+        przesyłanych danych oraz zaoszczędzenie pieniędzy przeznaczonych na
+        zakup dysków. <em>VDO</em> wykorzystuje takie techniki jak kompresja,
+        technologia <em>thin provisioning</em> oraz unikanie tworzenia
+        duplikatów plików. Kiedyś <em>VDO</em> było odrębną techniką tak jak
+        <em>LVM</em> czy <em>Stratis</em>. Obecnie od <em>RHEL</em> 8.5
+        zostało zunifikowane wraz z <em>LVM</em> jako jeden z rodzajów 
+        logicznych woluminów. Tym zajmiemy się tym podrodziale otóż utworzymy
+        logiczny volumin <em>VDO</em>.
+      </p>
+      <p>
+        Aby użyć wolumin typu <em>VDO</em> musimy dysponować co najmniej 5GB
+        przestrzenii w grupie woluminów. Ja poniżej stworzyłem grupę składającą
+        się z jednego 10GB fizycznego voluminu.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo pvcreate /dev/vdf
+[sudo] hasło użytkownika user: 
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Physical volume "/dev/vdf" successfully created.
+[user@rhel90 ~]$ sudo vgcreate vg-vdo /dev/vdf
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Volume group "vg-vdo" successfully created
+[user@rhel90 ~]$ sudo vgs
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  VG     #PV #LV #SN Attr   VSize   VFree  
+  rhel     1   2   0 wz--n- &lt;11,00g      0 
+  vg-vdo   1   0   0 wz--n- &lt;10,00g &lt;10,00g
+</pre>
+      <p>
+        Przed utworzeniem woluminu, musimy poznać ilość ekstentów dostępnych
+        w grupie. Za pomocą poniższego polecenia możemy ustalić te liczbę.
+        Jest ona istotna, ponieważ jeśli jej nie podamy nie będziemy mogi
+        skorzystać z <em>thin provisioning</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgdisplay -v vg-vdo | grep 'Free PE'
+[sudo] hasło użytkownika user: 
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  Total PE / Free PE    2559 / 2559
+</pre>
+      <p>
+        Teraz możemy za pomocą polecenia <em>lvcreate</em> utworzyć wolumin
+        logiczny w stylu <em>VDO</em>:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvcreate --type vdo -n vdo-vol0 -l 2559 -V 1TB vg-vdo
+    The VDO volume can address 6 GB in 3 data slabs, each 2 GB.
+    It can grow to address at most 16 TB of physical storage in 8192 slabs.
+    If a larger maximum size might be needed, use bigger slabs.
+  Logical volume "vdo-vol0" created.
+</pre>
+      <p>
+        W ten sposób stworzyłem wolumin w stylu <em>VDO</em>, za pomocą opcji
+        <em>-V</em> podaje wirtualną wielkość tego urządzenia. Polecenie poza
+        utworzeniem podanego woluminu utworzy dodatkowy wolumin puli. Tak 
+        utworzony wolumin
+        <em>VDO</em> może nam posłużyć do przechowywania danych na serwerze.
+        Poniżej znajduje się wynik działania poleceń <em>lvs</em> oraz
+        <em>vgdisplay</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvs -a vg-vdo
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  LV             VG     Attr       LSize   Pool   Origin Data%  Meta%  Move Log Cpy%Sync Convert
+  vdo-vol0       vg-vdo vwi-a-v---   1,00t vpool0        0,00                                   
+  vpool0         vg-vdo dwi------- &lt;10,00g            40,02                                  
+  [vpool0_vdata] vg-vdo Dwi-ao---- &lt;10,00g                                                      
+</pre>
+      <p>
+        Zwróćmy uwagę, że samo utrzymanie takiego woluminu, kosztuje nas 4GB
+        miejsca na dysku i nie jest to zależne od jego rozmiaru. Poniżej
+        znajdują się informacje uzyskane z polecenia <em>vgdisplay</em>: 
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vgdisplay -v vg-vdo
+  Devices file PVID none last seen on /dev/vdd1 not found.
+  Devices file PVID none last seen on /dev/vdd2 not found.
+  Devices file PVID none last seen on /dev/vdc1 not found.
+  --- Volume group ---
+  VG Name               vg-vdo
+  System ID             
+  Format                lvm2
+  Metadata Areas        1
+  Metadata Sequence No  16
+  VG Access             read/write
+  VG Status             resizable
+  MAX LV                0
+  Cur LV                2
+  Open LV               0
+  Max PV                0
+  Cur PV                1
+  Act PV                1
+  VG Size               &lt;10,00 GiB
+  PE Size               4,00 MiB
+  Total PE              2559
+  Alloc PE / Size       2559 / &lt;10,00 GiB
+  Free  PE / Size       0 / 0   
+  VG UUID               qPdY4n-YQUG-x5tu-szTe-B3bT-idC8-vseZXH
+   
+  --- Logical volume ---
+  LV Path                /dev/vg-vdo/vpool0
+  LV Name                vpool0
+  VG Name                vg-vdo
+  LV UUID                H9mloX-8x8N-4OHz-HHvz-qWhZ-dnJE-Sq1sCX
+  LV Write Access        read/write
+  LV Creation host, time rhel90, 2022-07-22 15:17:50 +0200
+  LV VDO Pool data       vpool0_vdata
+  LV VDO Pool usage      40,02%
+  LV VDO Pool saving     100,00%
+  LV VDO Operating mode  normal
+  LV VDO Index state     online
+  LV VDO Compression st  online
+  LV VDO Used size       4,00 GiB
+  LV Status              NOT available
+  LV Size                &lt;10,00 GiB
+  Current LE             2559
+  Segments               1
+  Allocation             inherit
+  Read ahead sectors     auto
+   
+  --- Logical volume ---
+  LV Path                /dev/vg-vdo/vdo-vol0
+  LV Name                vdo-vol0
+  VG Name                vg-vdo
+  LV UUID                sc5RL6-LfF6-jzCT-6TNK-c4Q3-J2sf-m1ZufS
+  LV Write Access        read/write
+  LV Creation host, time rhel90, 2022-07-22 15:17:53 +0200
+  LV VDO Pool name       vpool0
+  LV Status              available
+  # open                 0
+  LV Size                1,00 TiB
+  Current LE             262144
+  Segments               1
+  Allocation             inherit
+  Read ahead sectors     auto
+  - currently set to     256
+  Block device           253:4
+   
+  --- Physical volumes ---
+  PV Name               /dev/vdf     
+  PV UUID               kAxqd2-v4Xo-nmB8-311H-nM2d-DtHn-WutyCf
+  PV Status             allocatable
+  Total PE / Free PE    2559 / 0
+</pre>
+      <p>
+        W <em>RHEL</em> pozostało jeszcze jedno polecenie, które pozwala 
+        zwrócić
+        statystykę na temat obecnego w systemie woluminu puli <em>VDO</em>,
+        takim poleceniem jest <em>vdostats</em>. Poniżej znajduje się
+        przykład jego użycia.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo vdostats --si
+Device                    Size      Used Available Use% Space saving%
+vg--vdo-vpool0-vpool     10.7G      4.3G      6.4G  40%            0%
+</pre>
+      <p>
+        Na powyższym przykładzie użyłem opcji 
+        <code class="code-inline">--si</code>, aby przeskalować jednostki do
+        poziomu czytelnego dla człowieka.
+      </p> 
+      <p>
+        Usuwanie takiego woluminu wygląda jak usuwanie każdego innego woluminu,
+        jednak w tym przypadku program zapyta czy usunąć także zależny wolumin
+        puli.
+      </p>
+      <h2 id="14.3.stratis">14.4. Zarządzanie pamięcią masową za pomocą Stratis</h2>
+      <p>
+        <strong>Stratis</strong> jest to technologia łącząca ze sobą trzy
+        kompnenty systemowe, pozwalając na łączenie dysków w pule oraz
+        tworzenie
+        już gotowych do montowania systemów plików typu <strong>XFS</strong>.
+        <em>Stratis</em> jest praktycznie rzecz biorąc bardzo podobny do
+        <em>LVM</em> jednak nie tworzymy logicznych woluminów, a gotowe
+        <strong>systemy plików</strong>, grupa do której należą dyski nazwane
+        w tym przypadku <strong>blockdev</strong> nazywana jest
+        <strong>pulą</strong>. 
+      </p>
+      <p>
+        Stratis nie jest natywnie dostępny w systemie i trzeba go zainstalować.
+        Pakiety znajdują się w repozytorium na płycie instalacyjnej z 
+        <em>RHEL</em> 9.
+        Aby zainstalować w <em>Stratis</em> za systemie wydajemy poniższe
+        polecenie:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo dnf install stratisd stratis-cli -y
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:36:10 temu w dniu pią, 22 lip 2022, 15:23:29.
+Pakiet stratisd-2.4.2-3.el9.x86_64 jest już zainstalowany.
+Pakiet stratis-cli-2.4.3-2.el9.noarch jest już zainstalowany.
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+</pre>
+      <p>
+        Stratis występuje w systemie w postaci demona, dlatego też należy
+        włączyć i uruchomić jego jednostkę.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo systemctl enable stratisd.service
+[user@rhel90 ~]$ sudo systemctl start stratisd.serivce
+[user@rhel90 ~]$ sudo systemctl status stratisd
+● stratisd.service - Stratis daemon
+     Loaded: loaded (/usr/lib/systemd/system/stratisd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Fri 2022-07-22 08:16:57 CEST; 7h ago
+       Docs: man:stratisd(8)
+   Main PID: 758 (stratisd)
+      Tasks: 6 (limit: 7746)
+     Memory: 4.1M
+        CPU: 8.731s
+     CGroup: /system.slice/stratisd.service
+             └─758 /usr/libexec/stratisd --log-level debug
+
+lip 22 08:16:56 rhel90 stratisd[758]: [2022-07-22T06:16:56Z INFO  libstratis::stratis::run] stratis daemon version 2.4.2 started
+lip 22 08:16:56 rhel90 stratisd[758]: [2022-07-22T06:16:56Z INFO  libstratis::stratis::run] Using StratEngine
+lip 22 08:16:56 rhel90 stratisd[758]: [2022-07-22T06:16:56Z INFO  libstratis::engine::strat_engine::liminal::identify] Beginning initial ...
+lip 22 08:16:56 rhel90 stratisd[758]: [2022-07-22T06:16:56Z DEBUG libstratis::stratis::run] 2: thread started
+lip 22 08:16:56 rhel90 stratisd[758]: [2022-07-22T06:16:56Z DEBUG libstratis::stratis::run] 3: thread started
+lip 22 08:16:57 rhel90 stratisd[758]: [2022-07-22T06:16:57Z INFO  libstratis::stratis::ipc_support::dbus_support] D-Bus API is available
+...
+</pre>
+      <h3 id="14.3.1.createpool">14.3.1. Tworzenie puli Stratis</h3>
+      <p>
+        Teraz kiedy <em>Stratis</em> jest uruchomiony. Możemy przejść do
+        utworzenia puli. Do utworzenia puli użyjemy podpolecenia <em>pool</em>
+        polecenia <em>stratis</em> oraz podpolecenia <em>create</em>
+        podpolecenia <em>pool</em>. Jako argumenty podajemy nazwę puli oraz
+        listę dysków.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis pool create rhcsa /dev/vdg
+[sudo] hasło użytkownika user: 
+</pre>
+      <p>
+        Informacje na temat puli możemy uzyskać za pomocą podpolecenia
+        <em>list</em> podpolecenia <em>pool</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis pool list
+Name                    Total Physical   Properties                                   UUID
+rhcsa   1 GiB / 37.63 MiB / 986.37 MiB      ~Ca,~Cr   5091bc53-7693-4a92-a434-fe8e682d0f58
+</pre>
+      <p>
+        Z informacji zwracanych z tego polecenie nas na tym etapie powinno
+        interesować kolumna zawierająca informacje o wielkości puli. Teraz
+        możemy utworzyć system plików. 
+      </p>
+      <h3 id="14.3.2.createfilesystem">14.3.2. Tworzenie systemu plików Stratis</h3>
+      <p>
+        Tworzenie systemu plików odbywa się za pomocą podpolecenia
+        <em>create</em>, podpolecenia <em>filesystem</em>. To podpolecenie
+        wymaga jako argumenty nazwę puli oraz nazwę systemu plików.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis filesystem create rhcsa rhcsafs0
+[user@rhel90 ~]$ sudo stratis filesystem
+Pool Name   Name       Used      Created             Device                        UUID                                
+rhcsa       rhcsafs0   546 MiB   Jul 22 2022 16:34   /dev/stratis/rhcsa/rhcsafs0   5ca8e5b1-f32a-42e0-ac90-29777b3fc8ed
+</pre>
+      <p>
+        Zwróćmy uwagę na to, iż <em>Stratis</em> sam dobiera na podstawie
+        wielkości puli wielkość systemu plików. Tak utworzony system jest
+        dostępny pod ścieżką w kolumnie
+        <code class="code-inline">Device</code> i gotowy do montowania.
+      </p>
+      <h3 id="14.3.3.expandandrenamestratis">14.3.3. Rozszerzenie puli oraz zmiana nazwy puli i systemu plików Stratis</h3>
+      <p>
+        Do rozszerzenia puli <em>Stratis</em> służy podpolecenie
+        <em>add-data</em> podpolecenia <em>pool</em>. To podpolecenie oczekuje
+        podania nazwy urządzenia dyskowego.
+      </p> 
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis pool add-data rhcsa /dev/vdh
+[user@rhel90 ~]$ sudo stratis blockdev
+Pool Name   Device Node   Physical Size   Tier
+rhcsa       /dev/vdg              1 GiB   Data
+rhcsa       /dev/vdh              1 GiB   Data
+</pre>
+      <p>
+        Za pomoca podpolecenia <code class="code-inline">blockdev</code>, mamy
+        możliwość podejrzenia przypisanych do puli dysków. Jak widzimy teraz
+        w puli znajdują się dwa dyski, zatem będziemy mogli utworzyć kolejny
+        system plików, ponieważ samych systemów plików nie możemy zmienić.
+        Teraz zmienimy nazwę puli oraz nazwę systemu plików.
+      </p>
+      <p>
+        Do zmiany nazw służy podpolecenie <em>rename</em> kolejno podpolecenia 
+        <em>pool</em>
+        oraz <em>filesystem</em>. Na poniższym przykładzie znajduje się 
+        zastosowanie tego podpolecenia:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis pool rename rhcsa rhcsa9
+[user@rhel90 ~]$ sudo stratis filesystem rename rhcsa9 rhcsafs0 rhcsa9fs0
+</pre>
+      <h3 id="14.3.4.destroy">14.3.4. Usuwanie elementów Stratis</h3>
+      <p>
+        Za pomocą podpolecenia <em>destroy</em> możemy usunąć zarówno system
+        plików jak i pulę <em>Stratis</em>. Poniżej znajduje się przykład
+        użycia, tego podpolecenia w innych ujęciach.
+      </p>
+      <p>
+        Usunięcie systemu plików:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis filesystem destroy rhcsa9 rhcsa9fs0
+</pre>
+      <p>
+        Usunięcie puli <em>Stratis</em>:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo stratis pool destroy rhcsa9
+</pre>
+      <p>
+        Żadna pula już w systemie nie istnieje. 
+      </p>
+<pre class="code-inline">
+[user@rhel90 ~]$ sudo stratis pool
+Name   Total Physical   Properties   UUID
+</pre>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Nie musimy uczyć się na pamięć podpoleceń czy składni. Wiekszość
+        informacji możemy uzyskać wydając polecenie z opcją <em>--help</em> lub
+        wydać samo podpolecenie bez argumentów. Jedyne o czym należy pamiętać
+        to które polecenie lub podpolecenie jest od czego.
+      </p>
+      <h3 id="exec14.1">Ćwiczenie 1: Tworzenie grup woluminów oraz logicznych woluminów</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Stwórz z jedego z 250MB dysków
+        wolumin fizyczny następnie utwórz grupę <em>vg100</em> ustawiając
+        wielkość fizycznych ekstentów na 16MB, wykorzystując utworzony fizyczny
+        wolumin. Utwórz dwa woluminy logiczne o nazwach kolejno <em>lvol0</em>
+        oraz <em>swapvol</em> o wielkości 100 oraz 120MB. Zweryfikuj wykonane
+        wcześniej czynności za pomocą poleceń: <em>pvs</em>, <em>lvs</em>,
+        <em>vgs</em> oraz <em>vgdisplay</em>.
+      </p>
+      <h3 id="exec14.2">Ćwiczenie 2: Rozszerzenie grupy woluminów oraz logicznego woluminu</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Użyj kolejnego dysku o wielkości 
+        250MB jako woluminu fizycznego <em>LVM</em>. Dodaj nowy wolumin do
+        grupy z poprzedniego ćwiczenia. Rozszerz pojemność woluminu logicznego
+        <em>lvol0</em> do 300MB. Sprawdź wykonane czynności za pomocą poleceń:
+        <em>pvs</em>, <em>lvs</em>, <em>vgs</em> oraz <em>vgdisplay</em>.
+      </p>
+      <h3 id="exec14.3">Ćwiczenie 3: Redukcja oraz usunięcie woluminów logicznych</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Zmniejsz rozmiar woluminu
+        logicznego <em>lvol0</em> do 80MB. Usuń oba woluminy logiczne.
+        Sprawdź wykonane czynności za pomocą poleceń:
+        <em>pvs</em>, <em>lvs</em>, <em>vgs</em> oraz <em>vgdisplay</em>.
+      </p>
+      <h3 id="exec14.4">Ćwiczenie 4: Wycofywanie zmian LVM na dyskach</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Usuń grupę woluminów logicznych
+        <em>vg100</em>. Wyczyść konfiguracje <em>LVM</em> z dysków.
+        Sprawdź wykonane czynności za pomocą polecenia <em>lsblk</em>.
+      </p>
+      <h3 id="exec14.5">Ćwiczenie 5: Logiczne woluminy VDO</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Utwórz konfigurację <em>LVM</em> na
+        podstawie jedno z 10GB dysków (jeśli nie masz takiego dysku, dodaj go).
+        W utworzonej grupie utwórz wolumin <em>VDO</em> o wielkości wirtualnej
+        50GB. Zweryfikuj wykonanie czynności za pomocą poleceń 
+        <em>vgdisplay</em> oraz <em>vdostats</em>. Wycofaj wszystkie dokonane
+        zmiany.
+      </p>
+      <h3 id="exec14.6">Ćwiczenie 6: Tworzenie puli Stratis</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Sprawdź za pomocą <em>lsblk</em>
+        dostępność jednego dysków o pojemności 1GB. Nastepnie utwórz z jego
+        użyciem nową pulę <em>Stratis</em> o nazwie <em>strpool</em>.
+        Potwierdź wykonanie czynności wyświetlając informacje o puli oraz
+        o urządzeniach blokowych za pomocą podpoleceń polecenia <em>Stratis</em>
+        oraz polecenia <em>lsblk</em>.
+      </p>
+      <h3 id="exec14.7">Ćwiczenie 7: Rozszerzenie i usunięcie puli Stratis</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na serwerze
+        oznaczonym jako <em>server2</em>. Za pomocą drugiego dysku o pojemności
+        1GB rozszerz rozmiar puli <em>Stratis</em> <em>strpool</em>.
+        Zweryfikuj wykonaną czynność. Na koniec usuń pulę <em>Stratis</em>,
+        zweryfikuj to za pomocą polecenia <em>lsblk</em>.
+      </p>
+      <h2 id="ch14summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale poznaliśmy zaawansowane sposoby na zarządzanie
+        dyskami naszych komputerów. Poznaliśmy wiele poleceń,
+        których składni nie trzeb się uczyć na pamięć. Trzeba się jednak
+        orientować jakie polecenie jest do czego. Poznaliśmy zaległą
+        technologię <em>VDO</em> oraz trochę uprzedzającą fakty zebrane w
+        następnym rodziale technologię <em>Stratis</em>. W następnym rozdziale
+        poznamy systemy plików oraz sposoby na formatowanie tworzonych w tym
+        oraz w poprzednim rozdziale urządzeń blokowych, aby w końcu można
+        było ich użyć do przechowywania danych.
+      </p>
+      <h1 id="15.filesystemsandswap">15. Systemy plików oraz przestrzeń wymiany</h1>
+      <p>
+        W ostatnich dwóch rozdziałach poruszaliśmy temat zarządzania
+        przestrzenią dyskową. Oczywiście opisywane tam metody znajdą również
+        zastosowanie w przypadku innych pamięci masowych niż dyski. Czynności
+        wykonywane tam kończyły się wraz z utworzeniem docelowego urządzenia
+        przeznaczonego do przechowywania danych. To jednak nie koniec, aby
+        takie urządzenie mogło przechowywać dane muszą zostać na nim
+        zainstalowane specjalne struktury, które będą zajmować się organizacją
+        oraz sposobem dostepu do danych zebranych na urządzeniu. Tym właśnie
+        jest <strong>system plików</strong>.
+      </p>
+      <p>
+        Komputery, ktorych używamy do pracy zawsze mają określną liczbę 
+        zasobów. Jednym z nich jest pamięć operacyjna, która przechowuję
+        zarówno kod uruchomionych programów jak i dane, na których one pracują.
+        W zależności od konfiguracji sprzętowej może się ona szybko wyczerpać,
+        więc wymyślono coś takiego jak <strong>przestrzeń wymiany</strong>.
+        Jest specjalny rodzaj alokacji przestrzeni na dysku, przechowywujący
+        w niej nieużywane w danym momencie obszary pamięci operacyjnej. Jeśli
+        te dane będą potrzebne znów wrócą one do pamięci, a inne zostaną
+        przeniesione właśnie do przestrzeni wymiany. Przestrzeń wymiany inaczej
+        nosi nazwę <em>swapu</em> (czyt. <em>słapu</em>).
+      </p>
+      <h2 id="15.1.filesystems">15.1 Systemy plików na RHEL 9</h2>
+      <p>
+        <em>Red Hat Enterprise Linux</em> w wersji 9 natywnie obsługuje cztery 
+        systemy plików są nim między innymi:
+      </p>
+      <ul>
+        <li>Systemy plików <strong>EXT</strong> - jest domyślny system plików
+          dla każdej dystrybucji. Jest on dostępny w 4 wersjach przy czym
+          <em>EXT</em> w wersji 1 jest przestarzy i nie jest już wspierany.
+          Korzystając z <em>EXT</em> nalepiej jest korzystać z wersji 4,
+          zawiera ona najwięcej udogodnień oraz funkcji.</li>
+        <li>Systemy plików <strong>XFS</strong> - jest to system plików
+          stosowany w systemach klasy enterprise, choć obecnie powoli staje
+          się standarem jako podstawowy system plików dla wielu dystrybucji 
+          Linuksa.
+          Może on obsłużyć większe pliki niż <em>EXT4</em> oraz zaalokować
+          przestrzenie dyskowe. Póki co nie ma narzędzia które pozwalało by na
+          zmniejszenie systemu plików tego typu.</li>
+        <li>System plików <strong>VFAT</strong> - system plików utrzymywany w
+          dystrybucjach, aby można było zapewnić zgodność w przesyłaniu plików
+          między Linuksem a systemami MS Windows. Najczęściej jest on stosowany
+          na pamięciach USB.</li>
+        <li>System plików <strong>ISO 9660</strong> - system plików stosowany
+          na płytach CD/DVD, na których przechowywane są dane. Obrazy płyty
+          z systemami operacyjnymi (dystrybucje) również zawierą struktury tego
+          systemu plików.</li>
+      </ul>
+      <p>
+        Zarządzanie systemami plików obejmuje ich tworzenie, rozszerzanie,
+        zmniejszanie, montowanie oraz odmontowywanie. Tworzenie systemu plików
+        nazwywane jest jego instalacją lub <strong>formatowaniem</strong>.
+        Obsługa danego systemu plików dostarcza kilku narzędzi, które będziemy
+        poznawać w trakcie wykonywania przykładów, poza nimi system posiada
+        jeszcze kilka poleceń dotyczących ogólnie systemów plików.
+      </p>
+      <h2 id="15.2.mountandunmount">15.2. Montowanie oraz odłączanie systemów plików</h2>
+      <p>
+        Chcąc skorzystać z przestrzeni dyskowej zawartej na partycji, musi
+        ona zostać sformatowana pod określny system plików. Załóżmy, że zostało
+        już to zrobione. Musi ona również zostać podłączona do katalogu
+        głównego, tym właśnie zajmuje się montowanie. Do montowania służy
+        polecenie <strong>mount</strong>. Wydanie go bez podania żadnego
+        argumentu spowoduje wyświetlenie wszystkich zamontowanych w systemie
+        systemów plików.
+      </p>
+<pre class="code-block">
+/dev/mapper/rhel-root on / type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+selinuxfs on /sys/fs/selinux type selinuxfs (rw,nosuid,noexec,relatime)
+systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=31,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=12986)
+mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime,seclabel)
+hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel,pagesize=2M)
+debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime,seclabel)
+tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime,seclabel)
+fusectl on /sys/fs/fuse/connections type fusectl (rw,nosuid,nodev,noexec,relatime)
+configfs on /sys/kernel/config type configfs (rw,nosuid,nodev,noexec,relatime)
+/dev/vda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+/dev/sr0 on /mnt type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)
+</pre>
+      <p>
+        System do działania potrzebuje wielu systemów plików i to nie tylko
+        tych dyskowych ale także tych wirtualnych dla tego wynik działania tego
+        polecenia nie jest zbyt czytelny. Możemy go jednak bardzej uściślić
+        podając w za pomocą opcji <em>-t</em> interesującyu nas system plików.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ mount -t xfs
+/dev/mapper/rhel-root on / type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+/dev/vda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+</pre>
+      <p>
+        Aby zamontować system plików należy podać po poleceniu <em>mount</em>,
+        nazwę urządzenia, punkt montowania oraz ewentualnie opcje. 
+        <strong>Punkten montowania</strong> może być dowolny katalog znajdujący
+        się w systemie. Najlepiej jakby był pusty, ponieważ pliki z
+        zamontowanego katalogu przesłonią jego rzeczywistą zawartość.
+      </p>
+      <p>
+        Innym argumentem są opcje montowania. Polecenie posiada kilka opcji
+        ogólnych, natomiast montowanie określnego systemu plików pozwala także
+        na użycie specyficznych dla niego opcji. Poniżej znajduje się kilka
+        ogólnych opcji, opcje specyficzne znajdują się na stronie podręcznika
+        poświęconej systemowi plików.
+      </p>
+      <ul>
+        <li><strong>acl (noacl)</strong> - włącza lub wyłacza możliwość
+          stosowania list kontroli dostępu.</li>
+        <li><strong>auto (noauto)</strong> - włącza lub wyłącza możliwość
+          automatycznego montowania systemu plików podczas uruchamiania
+          systemu (będzie o tym w tym rozdziale).</li>
+        <li><strong>defaults</strong> - zestaw domyślnych opcji pozwalających
+          na pełne wykorzystanie zamontowanego systemu plików.</li>
+        <li><strong>_netdev</strong> - opcja używana dla systemów plików
+          wymagających sieci, co powoduje zestawienie połączenia sieciowego
+          za nim nastąpi monotowanie systemu plików. Przydatne w gdy montujemy
+          udział NFS.</li>
+        <li><strong>x-systemd.requiers=</strong> - opcja pozwala na wskazanie
+          jednostki, której aktywacja jest wymagana do zamontowania systemu
+          plików.</li>
+        <li><strong>remount</strong> - opcja pozwala na montowanie
+          zamontowanego już systemu plików w innym katalogu.</li>
+        <li><strong>ro (rw)</strong> - montuje system plików tylko do odczytu
+          lub w pełnym dostępie.</li>
+      </ul>
+      <p>
+        Poleceniem służącym do odłączania systemu plików jest 
+        <strong>umount</strong>. Najczęściej podaje się mu punkt montowania.
+        Po odmontowaniu system plików staje się niedostępny dla użytkowników
+        oraz programów.
+      </p>
+      <h2 id="15.3.gettinguuid">15.3. Pozyskiwanie identyfikatora UUID systemu plików</h2>
+      <p>
+        Podczas montowania jednym z podawanych argumentów jest nazwa
+        urządzenia. Sprawdza się to podczas szybkiego montowania w trakcie
+        działania systemu. Nazwa urządzenia nie jest jedyną wartością jaką
+        możemy podać poleceniu <em>mount</em> podczas montowania jako wartość
+        wskazującą na urządzenie. Do montowania możemy użyć etykiety, którą
+        ustawiamy podczas formatowania partycji lub specjalnego identyfikatora
+        <strong>UUID</strong> nadawanego po zainstalowaniu systemu plików na
+        partycji.
+      </p>
+      <p>
+        Identyfikator w przypadku systemów plików takich jak <em>EXT</em> oraz
+        <em>XFS</em> ma długość <strong>128</strong> bitów
+        natomiast w przypadku <em>VFAT</em> są to tylko <strong>32</strong>
+        bity, 8 heksadecymalnych znaków. <em>UUID</em> możemy uzyskać za przy 
+        użyciu specyficznego narzędzia dostarczanego wraz system plików lub
+        dwóch programów ogólnych <strong>blkid</strong> lub znanego już
+        wcześniej <strong>lsblk</strong> wraz z opcją <em>-f</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ blkid
+/dev/mapper/rhel-root: UUID="c09cb7eb-2f8e-459e-bb64-21dde92cd7c0" BLOCK_SIZE="512" TYPE="xfs"
+/dev/vda2: UUID="AHWsb0-0mbi-MxDK-0bpS-Q6ib-cz4l-rHQWAr" TYPE="LVM2_member" PARTUUID="45658df6-02"
+
+[user@rhel90 ~]$ lsblk -f /dev/vda
+NAME          FSTYPE    FSVER    LABEL  UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
+vda                                                                                           
+├─vda1        xfs                bootfs fb4c6cf9-8041-42ce-9e75-82026a4a0164    753,1M    26% /boot
+└─vda2        LVM2_memb LVM2 001        AHWsb0-0mbi-MxDK-0bpS-Q6ib-cz4l-rHQWAr                
+  ├─rhel-root xfs                       c09cb7eb-2f8e-459e-bb64-21dde92cd7c0      5,9G    39% /
+  └─rhel-swap swap      1               be58cfe2-c3a6-4731-9b0b-f58604074bd8                 [SWAP]
+</pre>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Alternatywne nazwenictwo jest istotne gdy chcemy utworzyć wpisy
+        automatycznego montowania podczas uruchamiania systemu. Klasyczne
+        nazwy, którymi posługujemy się w systemie przy następnym uruchomieniu
+        mogą już być zupełnie inne dla tych samych urządzeń, a <em>UUID</em> 
+        czy etykieta jest przypisana na stałe do systemu plików, zostanie
+        zmieniona dopiero przez ponowne sformatowanie partycji.
+      </p>
+      <h2 id="15.4.labeling">15.4. Nadawanie etykiet systemom plików</h2>
+      <p>
+        Etykiety są jedną z metod alternatywnego nazewnictwa urządzeń
+        przechowywujących systemy plików. Możemy je nadwać za pomocą narzędzi
+        dostarczanych wraz z systemem plików. Dla systemów <em>EXT</em> jest
+        narzędzie <strong>e2label</strong>, natomiast dla <em>XFS</em> jest
+        polecenie <strong>xfs_admin</strong> wraz z opcją <em>-L</em>. 
+        Przy czym etykiety mają swoje ograniczenia w ilość znaków. Dla 
+        <em>XFS</em> ten limit wynosi 12 znaków, a w przypadku
+        <em>EXT4</em> jest to 16 znaków. Teraz
+        odmontuje system plików zamontowany w <em>/boot</em> a następnie nadam
+        mu etykietę i zamontuje ponownie. Na początku jednak sprawdzam nazwę 
+        urzędzenia partycji oraz zainstalowany na niej system plików.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ lsblk -f
+NAME FSTYPE FSVER LABEL                 UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
+sr0  iso966 Jolie RHEL-9-0-0-BaseOS-x86_64
+                                        2022-04-19-20-42-48-00                       0   100% /mnt
+vda                                                                                           
+├─vda1
+│    xfs                                fb4c6cf9-8041-42ce-9e75-82026a4a0164    753,1M    26% /boot
+└─vda2
+     LVM2_m LVM2                        AHWsb0-0mbi-MxDK-0bpS-Q6ib-cz4l-rHQWAr                
+  ├─rhel-root
+  │  xfs                                c09cb7eb-2f8e-459e-bb64-21dde92cd7c0      5,9G    39% /
+  └─rhel-swap
+     swap   1                           be58cfe2-c3a6-4731-9b0b-f58604074bd8                 [SWAP]
+[user@rhel90 ~]$ sudo umount /boot
+[sudo] hasło użytkownika user: 
+[user@rhel90 ~]$ sudo xfs_admin -L "bootfs" /dev/vda1
+zapisywanie wszystkich superbloków
+nowa etykieta = "bootfs"
+[user@rhel90 ~]$ sudo mount /boot
+[user@rhel90 ~]$ lsblk -f
+NAME FSTYPE FSVER LABEL                 UUID                                   FSAVAIL FSUSE% MOUNTPOINTS
+sr0  iso966 Jolie RHEL-9-0-0-BaseOS-x86_64
+                                        2022-04-19-20-42-48-00                       0   100% /mnt
+vda                                                                                           
+├─vda1
+│    xfs          bootfs                fb4c6cf9-8041-42ce-9e75-82026a4a0164    753,1M    26% /boot
+└─vda2
+     LVM2_m LVM2                        AHWsb0-0mbi-MxDK-0bpS-Q6ib-cz4l-rHQWAr                
+  ├─rhel-root
+  │  xfs                                c09cb7eb-2f8e-459e-bb64-21dde92cd7c0      5,9G    39% /
+  └─rhel-swap
+     swap   1                           be58cfe2-c3a6-4731-9b0b-f58604074bd8                 [SWAP]
+</pre>
+      <p>
+        Jak możemy zauważyć różnice pomiędzy pierwszym wywołaniem <em>lsblk</em>
+        a drugim. Przy drugim wywowałaniu przy partycji zamontowanej
+        w katalogu <code class="code-inline">/boot</code> w kolumnie
+        <code class="code-inline">LABEL</code> widnieje teraz napis
+        <code class="code-inline">bootfs</code>. Tak utworzoną etykietę
+        możemy wykorzystać podczas ustawiania automatycznego montowania.
+      </p>
+      <h2 id="15.5.fstab">15.5. Automatyczne monotowanie systemów plików - /etc/fstab</h2>
+      <p>
+        Katalog główny możemy być rozbity na kilka różnych systemów plików.
+        Plik zawarte w poszczególnych katalogach są potrzebne do rozruchu
+        systemu, dlatego też w katalogu <em>/etc</em> znajduje się
+        plik tekstowy <strong>fstab</strong>, w którym to przechowywane są
+        wpisy systemów plików montowanych podczas uruchamiania systemu. Wpisy
+        poza automatycznym montowaniem, skracają też potrzebę podawania
+        wszystkich argumentów poleceniu <em>mount</em>. Jeśli taki system
+        plików nie jest montowany automatycznie to, żeby go zamontować
+        wystarczy podać albo punkt montowania albo nazwę urządzenia. Raczej
+        będzie to punkt montowania. Poniżej znajduję się kilka wpisów, które
+        posłużą nam do analizy.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo grep -v -e '^#' -e '^$' /etc/fstab 
+/dev/mapper/rhel-root   /                       xfs     defaults        0 0
+UUID=fb4c6cf9-8041-42ce-9e75-82026a4a0164 /boot                   xfs     defaults        0 0
+/dev/mapper/rhel-swap   none                    swap    defaults        0 0
+/dev/sr0       /mnt    iso9660 ro      0       0
+</pre>
+      <p>
+        Aby nieco ułatwić czytelność pozbyłem się komentarzy oraz pustych
+        wierszy. Każdy z wpisów składa się z 6 kolumn, kolumny te kolejno
+        przedstawiają:
+      </p>
+      <ul>
+        <li>Kolumna 1: <strong>nazwa urządzenia</strong>. Zazwyczaj znajdują
+          się tutaj identyfikatory <em>UUID</em> lub etykiety, jednak możliwe 
+          jest kilka
+          wyjątków, otóż: nazwy woluminów logicznych <em>LVM</em> są 
+          unikatowymi
+          identyfikatorami i będą wskazywać to samo urządzenie za każdym razem.
+          Tak samo jest z systemami plików tworzonymi przez usługę 
+          <em>Stratis</em>. Na końcu przykładu znajduje się montowanie płyty.
+          Urządzenie <em>/dev/sr0</em>, zazwyczaj oznacza pierwszy napęd
+          optyczny w systemie. Zatem jeśli w komputerze mamy tylko jeden napęd
+          również możemy tak zapisać automatyczne montowanie</li>
+        <li>Kolumna 2: <strong>punkt montowania</strong>. Ta kolumna wskazuje
+          nazwy katalogów do których należy podłączyć montowane systemy plików.
+          Wyjątkiem jest tutaj przestrzeń wymiany, ponieważ w miejscu
+          montowania wstawia się wartość <em>none</em> lub <em>swap</em>.</li>
+        <li>Kolumna 3: <strong>typ systemu plików</strong></li>
+        <li>Kolumna 4: <strong>opcje montowania</strong></li>
+        <li>Kolunma 5: <strong>Ustawienia programu dump</strong>, ta kolumna ma
+          zastosowanie tylko w przypadku systemów plików <em>EXT</em>. Dla
+          innych jej wartość zawsze wynosi <em>0</em>. Program <em>dump</em>
+          tworzy kopie bezpieczeństwa systemu plików.</li>
+        <li>Kolumna 6: <strong>kolejność partycji do sprawdzenia</strong>, ta
+          opcja również tyczy się systemów plików <em>EXT</em>, jej zadaniem
+          jest wskazanie kolejności sprawdzania systemów plików przez
+          program <em>e2fsck</em>, który skanuje system plików pod kątem błędów
+          i je naprawia. Zazwyczaj definiowane kolejności to 0 - wyłączające
+          sprawdzanie, 1 - przeznaczone dla głównego systemu plików
+          (zawierającego katalog główny) oraz 2 - każdy pozostały system plików
+          jeśli zbierze się więcej niż jeden system plików z tą kolejnością
+          to są one sprawdzane jeden po drugim.</li>
+      </ul>
+      <p>
+        Kolumny 5 oraz 6 nie mają zastosowania dla innych systemów plików niż
+        <em>EXT</em>, dlatego też przy wpisach innych systemów plików wpisuje
+        się 0 (zero).
+      </p>
+      <p>
+        Za pomocą polecenia <em>mount</em> wraz z opcją <em>-a</em> możemy
+        zamontować wszystkie systemy plików, których wpisy znajdują się w tym
+        pliku. Często będziemy korzystać z tego polecenia zatwierdzając zamiany
+        w tym pliku.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Zgubiony lub niepoprawny wpis w pliku <em>/etc/fstab</em> może
+        unieruchomić system. Aby to naprawić należy poprawić wpisy w trybie
+        ratunkowy. Ze względu na to należy zwrócić szczególną uwagę na
+        poprawność umieszczanych w tym pliku wpisów.
+      </p>
+      <h2 id="15.6.df">15.6. Monitorowanie zużycia miejsca w systemie plików</h2>
+      <p>
+        Jednym z zadań administracyjnych na serwerach jest monitorowanie 
+        zużycia
+        miejsca w systemie plików. Jednym z dostępnych narzędzi jest
+        polecenie <strong>df</strong>, które domyślnie wyświetla urządzenie
+        jego rozmiar, ilość zużytego miejsca, ilość dostępnego miejsca,
+        procentowe zużycie miejsca na dysku oraz punkt montowania. Poniżej
+        znajduje się przykład.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ df -h
+System plików         rozm. użyte dost. %uż. zamont. na
+devtmpfs               606M     0  606M   0% /dev
+tmpfs                  636M     0  636M   0% /dev/shm
+tmpfs                  255M  7,4M  247M   3% /run
+/dev/mapper/rhel-root  9,8G  3,9G  6,0G  40% /
+/dev/sr0               8,0G  8,0G     0 100% /mnt
+tmpfs                  1,0M     0  1,0M   0% /run/stratisd/keyfiles
+tmpfs                  128M   52K  128M   1% /run/user/42
+tmpfs                  128M   36K  128M   1% /run/user/1000
+/dev/vda1             1014M  261M  754M  26% /boot
+</pre>
+      <p>
+        Użyłem w przykładzie polecenia wraz z opcją <em>-h</em>, która
+        powoduje skalowanie jednostek. Domyślnie polecenia przedstawia wartości
+        w postaci KB (kilobajtów). Wraz z tą opcją używa się jeszcze kilku
+        innych takich jak:
+      </p>
+      <ul>
+        <li><em>-T</em> - dodaje kolumnę z rodzajem systemu plików.</li>
+        <li><em>-x</em> - wyłącza wyświetlanie określonego systemu plików.</li>
+        <li><em>-t</em> - wyświetla wyłącznie urządzenia sformatowane na
+          określony typ plików.</li>
+        <li><em>-i</em> - wyświeta zużycie systemu plików w wezłąch 
+        <em>i-node</em>.
+      </ul>
+      <h2 id="15.7.du">15.7. Określenie użycia systemu plików</h2>
+      <p>
+        Za pomocą polecenia <em>df</em> mogliśmy ustalić ogólne wartości na 
+        temat zużycia
+        systemu plików. Za pomocą polecenia <strong>du</strong> możemy ustalić
+        i ile miejsca zajmują określone pliki oraz foldery. To polecenie
+        również domyślnie zwraca informacje w KB. Najczęściej wykorzystywanymi
+        opcjami są <em>-s</em> wyświetające podsumowanie oraz <em>-h</em>
+        skalujące jednostki to poziomu czytelnego przez człowieka.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo du -sh /usr
+[sudo] hasło użytkownika user: 
+3,6G   /usr
+</pre>
+      <h2 id="15.8.managingfilesystems">15.8. Zarządzanie systemami plików</h2>
+      <p>
+        Zarządzanie systemami plików wygląda podobnie w wszystkich poznanych
+        tutaj przypadkach (metodach zarządzania pamięcią masową). W tym 
+        podrozdziale skupimy się na najbardziej zaawansowanych przypadkach.
+      </p>
+      <h3 id="15.8.1.createfs">15.8.1. Tworzenie systemów plików</h3>
+      <p>
+        Tworzenie systemów plików, czy też formatowanie partycji wygląda
+        identycznie czy jest to wolumin logiczny czy partycja na dysku. Na
+        poniższym przykładzie zaprezentowałem tworzenie partycji na trzech
+        partycjach podstawowych na każdej z nich zainstalowałem inny system
+        plików:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo mkfs -t vfat /dev/vdb1
+mkfs.fat 4.2 (2021-01-31)
+[user@rhel90 ~]$ sudo mkfs -t ext4 /dev/vdb2
+mke2fs 1.46.5 (30-Dec-2021)
+Tworzenie systemu plików o 78848 blokach 1k oraz 19680 i-węzłach
+UUID systemu plików: d97751fb-dce0-4406-b03b-925dfa64a183
+Kopie zapasowe superbloku zapisane w blokach: 
+       8193, 24577, 40961, 57345, 73729
+
+Przydzielanie tablicy grup: zakończono                      
+Zapis tablicy i-węzłów: zakończono                      
+Tworzenie kroniki (4096 bloków): wykonano
+Zapis superbloków i podsumowania systemu plików: wykonano
+
+[user@rhel90 ~]$ sudo mkfs -t xfs /dev/vdb3
+meta-data=/dev/vdb3              isize=512    agcount=4, agsize=4883 blks
+         =                       sectsz=512   attr=2, projid32bit=1
+         =                       crc=1        finobt=1, sparse=1, rmapbt=0
+         =                       reflink=1    bigtime=1 inobtcount=1
+data     =                       bsize=4096   blocks=19531, imaxpct=25
+         =                       sunit=0      swidth=0 blks
+naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
+log      =log wewnętrzny        bsize=4096   blocks=1368, version=2
+         =                       sectsz=512   sunit=0 blks, lazy-count=1
+realtime =brak                   extsz=4096   blocks=0, rtextents=0
+</pre>
+      <p>
+        W przykładzie użyłem polecenia <strong>mkfs</strong> i za pomocą opcji 
+        <em>-t</em> podałem typ żądanego systemu plików. Równie dobrze możemy
+        podać nazwę polecenia a następnie po kropce typ systemu plików
+        (np. <em>mkfs.ext4</em>). Następnie podaje się urządzenie blokowe, 
+        które ma zostać sformatowane.
+      </p>
+      <p>
+        Tworzenie systemu plików dla woluminu <em>VDO</em> najlepiej jest
+        przeprowadzić z użyciem opcji <em>-E nodiscard</em> dla 
+        <em>EXT4</em> lub opcją <em>-K</em> dla <em>XFS</em> obie wykonują 
+        tę samą czynność i pozwalają zainstalować je szybciej na tego typu
+        pamięciach masowych. 
+      </p>
+      <h3 id="15.8.2.mountumount">15.8.2. Montowanie oraz odłączanie systemu plików</h3>
+      <p>
+        Za pomocą polecenia <em>mount</em> możemy podłączyć systemy plików z
+        poprzedniego podrozdziału do naszego systemu. Polecenie <em>mount</em> 
+        nie wymaga
+        podania rodzaju systemu plików, potrafi ono samo to określić.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo mount /dev/vdb3 /media/
+[sudo] hasło użytkownika user: 
+[user@rhel90 ~]$ sudo mount -t xfs
+/dev/mapper/rhel-root on / type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+/dev/vda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+/dev/vdb3 on /media type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+</pre>
+      <p>
+        Ostatni wiersz dotyczy montowania ze wcześniejszego polecenia.
+      </p>
+      <p>
+        Aby odmontować ten system plików należy wydać poniższe polecenie:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo umount /media
+[user@rhel90 ~]$ sudo mount -t xfs
+/dev/mapper/rhel-root on / type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+/dev/vda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
+</pre>
+      <p>
+        Wiersz dotyczący katalogu <em>/media</em> nie wystąpił po
+        odmontowaniu, tak wiec system plików został odłączony od systemu.
+      </p>
+      <h3 id="15.8.3.automount">15.8.3. Montowanie automatyczne z użyciem pliku /etc/fstab</h3>
+      <p>
+        Tak jak już wcześniej wspomiałem, za pomocą pliku <em>/etc/fstab</em>
+        możemy zdefiniować wpisy z systemami plików, które będą automatycznie
+        montowane podczas uruchamiania systemu lub będzie możliwość ich
+        szybszego montowania, za pomocą polecenia <em>mount</em>. Definiując
+        nowy wpis musimy wypełnić, każdą z kolumn. Należy również dodać, że
+        tworząc wpisy <em>/etc/fstab</em>, należy pisać bardzo uważnie,
+        ponieważ jeden błąd może unieruchomić cały system. 
+      </p>
+      <p>
+        Dodanie wpisów do <em>/etc/fstab</em> można dokonać na wiele sposobów.
+        Ja na przykład przełączyłem się na superużytkownika i za pomocą
+        <em>echo</em> dodawałem kolejne wpisy, co zobrazowałem na poniższym 
+        przykładzie.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ mkdir /{vfat,ext4,xfs}fs1
+
+[user@rhel90 ~]$ lsblk -f /dev/vdb
+NAME   FSTYPE FSVER LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
+vdb                                                                           
+├─vdb1 vfat   FAT16       BA6B-6E4E                                           
+├─vdb2 ext4   1.0         d97751fb-dce0-4406-b03b-925dfa64a183                
+└─vdb3 xfs                37f34709-79da-4adb-aff4-8de1cfafe9c6                
+
+[root@rhel90 user]# echo "UUID=BA6B-6E4E /vfatfs1 vfat defaults 0 0" &gt;&gt; /etc/fstab
+[root@rhel90 user]# echo "UUID=d97751fb-dce0-4406-b03b-925dfa64a183 /ext4fs1 ext4 defaults 0 0" &gt;&gt; /etc/fstab
+[root@rhel90 user]# echo "UUID=37f34709-79da-4adb-aff4-8de1cfafe9c6 /xfsfs1 xfs defaults 0 0" &gt;&gt; /etc/fstab 
+
+[user@rhel90 ~]$ grep -v -e '^#' -e '^$' /etc/fstab
+/dev/mapper/rhel-root   /                       xfs     defaults        0 0
+UUID=fb4c6cf9-8041-42ce-9e75-82026a4a0164 /boot                   xfs     defaults        0 0
+/dev/mapper/rhel-swap   none                    swap    defaults        0 0
+/dev/sr0       /mnt    iso9660 ro      0       0
+UUID=BA6B-6E4E /vfatfs1 vfat defaults 0 0
+UUID=d97751fb-dce0-4406-b03b-925dfa64a183 /ext4fs1 ext4 defaults 0 0
+UUID=37f34709-79da-4adb-aff4-8de1cfafe9c6 /xfsfs1 xfs defaults 0 0
+
+[user@rhel90 ~]$ sudo mount -a
+
+[user@rhel90 ~]$ df -h
+System plików         rozm. użyte dost. %uż. zamont. na
+...
+/dev/vdb1               75M     0   75M   0% /vfatfs1
+/dev/vdb2               67M   14K   62M   1% /ext4fs1
+/dev/vdb3               71M  4,6M   67M   7% /xfsfs1
+</pre>
+      <p>
+        Na początku stworzyłem punkty montowania, trzy podkatalogi w katalogu
+        głównym. Następnie odszukałem w systemie identyfikatory <em>UUID</em>,
+        ponieważ są to zwykłe partycje musiałem ich użyć. Za pomocą
+        przekierowania wyjścia polecenia <em>echo</em> zapisałem wpisy 
+        odpowiednie
+        dla tych partycji, aby to potwierdzić użyłem polecenia
+        <em>mount</em> wraz z opcją <em>-a</em>, żeby zamontować wszystkie 
+        wpisy 
+        w pliku. Polecenie oczywiście te zamontowane pomija, więc spokojnie
+        każdą zmianę w tym pliku możemy potwierdzać za pomocą tego polecenia.
+        Na koniec wyświetliłem sprawdzenie stanu zużycia systemów plików, aby
+        lepiej zaprezentować fakt, iż systemy wcześniej zapisane do pliku
+        <em>/etc/fstab</em> zostały poprawnie podłączone.
+      </p>
+      <p>
+        Wpis do pliku dotyczący <em>LVM</em>, różniłby się tylko tym, że 
+        zamiast
+        <em>UUID</em> mogłaby być ścieżka do woluminu logicznego <em>LVM</em>.
+        Jeśli chodzi o systemy plików tworzone przez <em>Stratis</em> można
+        użyć <em>UUID</em> lub ścieżki urządzenia wyświetlanej na liście
+        systemów plików, jednak <em>Stratis</em> wymaga uruchomienia usługi
+        aby systemy plików były w ogóle widoczne, zatem przed opcją
+        <code class="code-inline">defaults</code> należało by użyć opcji
+        <em>x-systemd.requires=stratisd.service</em>.
+      </p>
+      <h3 id="15.8.4.expandvolumes">15.8.4. Rozszerzanie systemu plików na woluminie logicznym LVM</h3>
+      <p>
+        W systemie posiadam już zamontowane dwa woluminy logiczne z <em>LVM</em>.
+        Chcę rozszerzyć ich wielkość o 100MB. Wszystkie czynności takiej jak
+        związane z <em>LVM</em> zostały już wykonane poza samym rozszerzeniem
+        woluminów. Polecenie <em>lvextend</em> jak i <em>lvresize</em>
+        posiadają opcję <strong>-r</strong>, która pozwala na uruchomienie
+        programu odpowiedzialnego za zmianę rozmiaru systemu plików. W
+        przypadku <em>EXT4</em> uruchamiany jest program 
+        <strong>resize2fs</strong> a w przypadku <em>XFS</em>
+        <strong>xfs_growfs</strong>. Opcję <em>-r</em> możemy pominąć lub o
+        niej zapomnieć, wówczas należy uruchomić te programy z poziomu
+        wiersza polecenia. Poniżej znajdują się przykłady jak można rozszerzyć
+        zamontowane już woluminy logiczne.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo lvextend -L +100M -r /dev/vg-lvm/ext4vol
+  Devices file /dev/vdb is excluded by filter: device is partitioned.
+  Size of logical volume vg-lvm/ext4vol changed from 252,00 MiB (63 extents) to 352,00 MiB (88 extents).
+  Logical volume vg-lvm/ext4vol successfully resized.
+resize2fs 1.46.5 (30-Dec-2021)
+System plików /dev/mapper/vg--lvm-ext4vol jest zamontowany pod /ext4fs2; wymagana zmiana rozmiaru w locie
+old_desc_blocks = 2, new_desc_blocks = 3
+System plików na /dev/mapper/vg--lvm-ext4vol ma teraz 360448 (1k) bloków.
+
+[user@rhel90 ~]$ sudo lvextend -L +100M /dev/vg-lvm/xfsvol
+  Size of logical volume vg-lvm/xfsvol changed from 252,00 MiB (63 extents) to 352,00 MiB (88 extents).
+  Logical volume vg-lvm/xfsvol successfully resized.
+[user@rhel90 ~]$ sudo xfs_growfs /dev/vg-lvm/xfsvol
+meta-data=/dev/mapper/vg--lvm-xfsvol isize=512    agcount=4, agsize=16128 blks
+         =                       sectsz=512   attr=2, projid32bit=1
+         =                       crc=1        finobt=1, sparse=1, rmapbt=0
+         =                       reflink=1    bigtime=1 inobtcount=1
+data     =                       bsize=4096   blocks=64512, imaxpct=25
+         =                       sunit=0      swidth=0 blks
+naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
+log      =log wewnętrzny        bsize=4096   blocks=1368, version=2
+         =                       sectsz=512   sunit=0 blks, lazy-count=1
+realtime =brak                   extsz=4096   blocks=0, rtextents=0
+bloki danych zmienione z 64512 na 90112
+</pre>
+      <h2 id="15.9.swapmanaging">15.9. Zarządzanie przestrzenią wymiany</h2>
+      <p>
+        Na wstępie tego rozdziału omówiliśmy sobie czym jest przestrzeń
+        wymiany. Teraz przejdziemy do jej zarządzania. Poza użyciem
+        specyficznego programu do formatowania partycji jako przestrzeni
+        wymiany ten podrozdział nie będzie różnić się niczym od pozostałych.
+        Nie ma różnicy czy stworzymy naszą przestrzeń wymiany na partycji czy
+        woluminie logicznym. W systemie może być również wiecej niż jedna
+        przestrzeń wymiany, są one wówczas priorytetyzowane. 
+      </p>
+      <h3 id="15.9.1.createswap">15.9.1. Tworzenie przestrzeni wymiany</h3>
+      <p>
+        Do stworzenia przestrzeni wymiany wykorzystamy polecenie
+        <strong>mkswap</strong>. Polecenie to może nadać etykietę partycji,
+        poprzez użycie opcji <em>-L</em>. Do użycia mamy maksymalnie 16
+        znaków. Poniżej znajduje się przykład, w którym utworzyłem przestrzeń
+        wymiany, zdefiniowałem także dla niej etykietę.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo mkswap -L swapvol /dev/vg-lvm/swapvol
+Tworzenie obszaru wymiany w wersji 1, rozmiar = 52 MiB (bajtów: 54521856)
+LABEL=swapvol, UUID=3c99f75a-4559-4f6b-970b-f78cc4333e9b
+</pre>
+      <h3 id="15.9.2.swaponoff">15.9.2. Włączanie i wyłączanie swapu</h3>
+      <p>
+        Utworzony wcześniej <em>swap</em> jeszcze nie działa. Wymagane jest
+        jego włączenie za pomocą polecenia <strong>swapon</strong>.
+        To polecenie potrafi również wyświetlić wszystkie dostępne w systemie
+        przestrzeni wymiany. Ręczne włączenie wymaga podania nazwy urządzenia. 
+        Poniżej znajduje się przykład:
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo swapon /dev/vg-lvm/swapvol
+[sudo] hasło użytkownika user: 
+[user@rhel90 ~]$ sudo swapon
+NAME      TYPE      SIZE USED PRIO
+/dev/dm-1 partition 1,2G   7M   -2
+/dev/dm-7 partition  52M   0B   -3
+</pre>
+      <p>
+        Po włączeniu przestrzeni wymiany uruchomiłem jeszcze raz polecenie
+        <em>swapon</em> bez żadnych argumentów aby wyświetlić wszystkie
+        <em>swapy</em> dostępne w systemie. W dystrybucjach Linuksa może być
+        ich 32. Dezaktywacji <em>swapu</em> dokonujemy za pomocą polecenia
+        <strong>swapoff</strong> podając jako argument nazwę urządzenia.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo swapoff /dev/vg-lvm/swapvol
+[sudo] hasło użytkownika user: 
+[user@rhel90 ~]$ sudo swapon
+NAME      TYPE      SIZE USED PRIO
+/dev/dm-1 partition 1,2G 6,8M   -2
+</pre>
+      <p>
+        Po wyłączeniu swapu widzimy, że nie jest on już dostępny w systemie.
+      </p>
+      <h3 id="15.9.3.autoswapon">15.9.3. Automatyczne włączanie przetrzeni wymiany - /etc/fstab</h3>
+      <p>
+        Przestrzeń wymiany tak jak inne systemy plików może być włączana
+        automatycznie podczas uruchamiania systemu operacyjnego. Poniżej
+        znajduje się przykład, który obrazuje dodawanie przestrzeni wymiany do
+        pliku <em>/etc/fstab</em> oraz jej automatyczne włączanie nie tylko
+        poprzez ponowne uruchomienie systemu.
+      </p>
+<pre class="code-block">
+[root@rhel90 user]# echo "LABEL=swapvol none swap defaults 0 0" &gt;&gt; /etc/fstab
+
+[user@rhel90 ~]$ sudo swapon -a
+[user@rhel90 ~]$ swapon
+NAME      TYPE      SIZE USED PRIO
+/dev/dm-1 partition 1,2G 6,8M   -2
+/dev/dm-7 partition  52M   0B   -3
+</pre>
+      <p>
+        Tym razem zamiast nazwy urządzenia użyłem etykiety. Polecenie
+        <em>swapon</em> wraz z opcją <em>-a</em>, ma takie samo działanie dla
+        przestrzeni wymiany jak <em>mount -a</em> dla zwykłych systemów plików.
+      </p>
+      <h3 id="15.9.4.swapmonitoring">15.9.4. Monitorowanie zużycia przestrzeni wymiany</h3>
+      <p>
+        Do kontrolowania z użycia przestrzeni wymiany możemy wykorzystać
+        proste polecenie, które zwraca nam informacje o ilości wykorzystywanej
+        w systemie pamięci operacyjnej. Do tego służy polecenie
+        <strong>free</strong>. Pod czas korzystania z tego narzędzia najlepiej
+        od razu przeskalować jednostki za pomocą polecenia <em>-h</em>. 
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ free -h
+               total        used        free      shared  buff/cache   available
+Mem:           1,2Gi       930Mi       104Mi       8,0Mi       236Mi       179Mi
+Swap:          1,3Gi       6,0Mi       1,2Gi
+</pre>
+      <p>
+        Druga linia zawiera informacje na temat przestrzeni wymiany. Prócz
+        tego polecenia możemy wykorzystać dowolne polecenie monitorujące
+        zasoby komputera, np. <em>top</em>.
+      </p>
+      <h3 id="exec15.1">Ćwiczenie 1: Tworzenie systemów plików oraz dodawanie wpisów do /etc/fstab</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em>. Na jednym z 250MB dysków utwórz
+        tablicę partycji w schemacie <em>MBR</em>. Utwórz 3 partycje po 70MB
+        na każdej z nich utwórz inny system plików. Utworz adekwatne dla nich
+        punkty montowania. Zamontuj je ręcznie. Określ ich <em>UUID</em> a 
+        następnie
+        dodaj wpisy montowania do pliku <em>/etc/fstab</em>. Ręcznie odłącz
+        zamontowane wcześniej partycje, następnie zamontuj je automatycznie i
+        potwierdź to za pomocą polecenia <em>df -h</em>.
+      </p>
+      <h3 id="exec15.2">Ćwiczenie 2: Wolumin VDO z XFS</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em>. Utwórz wolumin logiczny VDO o
+        rozmiarze wirtualnym 50GB, sformatuj go pod <em>XFS</em>, dodaj do
+        <em>/etc/fstab</em>, następnie zamontuj automatycznie potwierdź to
+        przy użyciu polecenia <em>df -h</em>. 
+      </p>
+      <h3 id="exec15.3">Ćwiczenie 3: Zarządzanie systemami plików z LVM</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em>. Utwórz dwa woluminy logiczne jeden
+        o wielkości 100MB a drugi 120MB, utworz na nich systemy plików 
+        <em>EXT4</em> na pierwszym, a drugim <em>XFS</em>. Zamontuj je w 
+        systemie. Dodaj drugi dysk
+        do grupy, następnie rozszerz woluminy logiczne o 100MB przyczym użyj
+        opcji <em>-r</em> podczas rozszerzenia woluminiu z <em>XFS</em>, a 
+        przy rozszerzaniu woluminu z <em>EXT4</em> pomiń tę opcję i ręczenie
+        rozszerz system plików. Zweryfikuj wykonane czynności.
+      </p>
+      <h3 id="exec15.4">Ćwiczenie 4: Montowanie automatyczne woluminu Stratis</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em>. Użyj jednego z 1GB dysków do
+        stworzenia systemu plików <em>Stratis</em>. Dodaj wpis z systemem do
+        pliku <em>/etc/fstab</em>. Uruchom system ponownie. Sprawdź czy system
+        plików został zamontowany za pomocą polecenia <em>df -h</em>. Co
+        mozemy zaobserować z wyników działania tego polecenia? Jaką pojemność
+        ma zamontowany system plików <em>Stratis</em>?
+      </p>
+      <h3 id="exec15.5">Ćwiczenie 5: Przestrzeń wymiany</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server2</em>. Na pozostałych z trzeciego ćwiczenia 
+        ekstentach, utwórz kolejny wolumin o nazwie <em>swap</em>. Stwórz z 
+        niego przestrzeń wymiany. Dodaj wpis tej przestrzeni do pliku
+        <em>/etc/fstab</em>. Aktywują ją automatycznie, następnie wyświetl
+        wszystkie dostępne przestrzenie wymiany w systemie oraz wyświetl 
+        łaczną pojemność <em>swapu</em> w systemie.
+      </p>
+      <h2 id="ch15summary">Podsumowanie</h2>
+      <p>
+        Tym rozdziałem zakończyliśmy naukę zarządzania pamięciami masowymi w
+        <em>RHEL</em>.
+        Poznaliśmy systemy plików oraz mechanizmy z nimi związane. Nauczyliśmy
+        się instalować systemy plików na partycjach oraz woluminach logicznych.
+        Dowiedzieliśmy się w jaki sposób montowane są automatycznie dostępne
+        w systemie operacyjnym systemy plików oraz w jaki sposób poprawnie
+        utworzyć wpis do pliku <em>/etc/fstab</em>. Na koniec poznaliśmy w jaki
+        sposób zarządzać przestrzenią wymiany w <em>RHEL</em>. W następnym 
+        rozdziale zajmiemy się już podstawowymi pojęciami związanymi z siecią.
+      </p>
+      <h1 id="16.networkfundamentals">16. Podstawy sieci w RHEL 9</h1>
+      <p>
+        Potrzeba współdzielenia danych oraz zasobów między komputerami
+        spowodowała, że zaczęto je łączyć w sieci. Na sieć komputerową
+        składają się minimum dwa komputery, połączone ze sobą albo bezpośrednio
+        albo za pomocą urządzenie pośredniczącego np. przełącznika. Aby
+        komunikacja między nimi mogła być możliwa wbudowane w nie urządzenia
+        sieciowe (karty/adaptery sieciowe) muszą zostać odpowiednio 
+        skonfigurowane z użyciem
+        podstawowej wiedzy na temat sieci IP. Poznaną tutaj wiedzę na temat
+        sieci IP, wykorzystamy do tworzenia oraz konfigurowania nowych
+        połączeń sieciowych w systemach klasy <em>enterprise</em>.
+      </p>
+      <h2 id="16.1.fundamentalstermsaboutnetworking">16.1. Podstawowe pojęcia o sieciach komputerowych</h2>
+      <p>
+        Aby poprawnie skonfigurować interfejs sieciowy komputera musimy poznać
+        podstawowe pojęcia związane z sieciami. 
+      </p>
+      <h3 id="16.1.1.ipv4">16.1.1. Adres IPv4</h3>
+      <p>
+        Adres protokołu internetowego w wersji 4, bo tak możemy rozszyfować
+        nazwę tego podrozdziału jest podstawowym identyfikatorem służący to
+        komunikacji w sieci. Każdy z komputerów podłączonych do sieci posiada
+        ten adres przydzielony automatycznie z serwera <em>DHCP</em> lub
+        przypisany ręcznie. Adres <em>IPv4</em> występuje w postaci 4 
+        oddzielonych
+        kropką oktetów, każdy z oktetów może przyjąć wartości od 0 do 255.
+        Adres <em>IPv4</em> możemy sprawdzić za pomocą polecenia
+        <strong>ip</strong> z podpoleceniem <em>addr</em>
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ip addr
+1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host 
+       valid_lft forever preferred_lft forever
+2: enp1s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 52:54:00:55:b7:60 brd ff:ff:ff:ff:ff:ff
+    inet 192.168.122.6/24 brd 192.168.122.255 scope global noprefixroute enp1s0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::5054:ff:fe55:b760/64 scope link noprefixroute 
+       valid_lft forever preferred_lft forever
+</pre>
+      <p>
+        Polecenie to wyświetla informacje na temat dostępnych w systemie
+        <strong>połączeń sieciowych</strong> (<em>interfejsów</em>). Jednym
+        z nich jest połączenie o nazwie <code class="code-inline">enp1s0</code>
+        posiadające adres <strong>192.168.122.6</strong>. Drugie połączenie
+        sieciowe, to specjalny interfejs systemowy tzw.
+        <strong>pętla zwrotna</strong>, pozwala ona na komunikację z usługami
+        sieciowym w tym systemie. Adresem pętli zwrotnej jest zawsze
+        <em>127.0.0.1</em>.
+      </p>
+      <p>
+        Komputery podłączone do tej samej sieci posiadają identyczne, niektóre
+        z częsci adresu <em>IPv4</em>. Część wspólna nazywana jest częścią 
+        sieciową, pozostała część (część hosta) jest ustatalna indywidualnie
+        dla każdego hosta i tylko jemu przypisywana. Które części adresu
+        są częścią hosta, a które są częscią sieci jest ustatalne w trakcie jej
+        konfiguracji na podstawie <strong>klas adresowych</strong>. Klasy
+        adresowe możemy podzielić na trzy klasy:
+      </p>
+      <ul>
+        <li><strong>Klasę A</strong> - W klasie A, część sieciowa obejmuje
+          tylko jeden oktet przez co możemy utworzyć do 126 sieci po
+          16 777 214 hostów w każdej z nich. W klasie A pierwszy oktet 
+          przyjmuje wartości od 0 do 126, z wyłączeniem 10.</li>
+        <li><strong>Klasę B</strong> - W klasie B za część sieciową odpowiadają
+          dwa oktety co daje większą ilość mniejszych sieci to i taki liczby
+          potrafią zaskakiwać, ponieważ w tej klasie można utworzyć 16384 sieci
+          po 65534 hosty. Klasa B w pierwszym oktecie stosuje wartości
+          od 128 do 191.</li>
+        <li><strong>Klasę C</strong> - W klasie C za część sieciową odpowiadają
+          aż trzy oktety, dzięki czemu możemy stworzyć dużą ilość małych sieci,
+          a konkretnie 2 097 152 sieci po 254 hosty każda. Klasa C w pierwszym
+          oktecie stosuje wartości od 192 do 223.</li>
+      </ul>
+      <p>
+        Poza tymi klasami w specyfikacji wyróżnia się takie klasy jak 
+        <em>D</em> oraz <em>E</em>, jednak mają one specjalne przeznaczenie.
+      </p>
+      <p>
+        Tak duże klasy adresów są dzielone na mniejsze części, aby łatwiej
+        zarządzać
+        takimi sieciami, zwiększyć ich wydajność oraz zapewnić oporność na
+        na awarie czy odsepraować je od siebie. Po podziale każda z takich
+        sieci posiada logicznie wytyczone granice. Te granice są wskazywane
+        przez <strong>maskę podsieci</strong>, której zadaniem jest zaznaczenie
+        części sieciowej adresu <em>IPv4</em> oraz części przeznaczonej dla
+        komputerów w sieci. Oktety maski podsieci mogą posiadać wartości takie
+        jak <strong>255</strong>, <strong>0</strong> oraz inne przy czym
+        wartości większe od 0 nie mogą znajdować się przed oktetami
+        zawierającymi 255 lub wartości inne niż 0. Z czego to wynika? Otóż
+        z podstaw adresacji <em>IPv4</em>. Każdy adres składa się z 4 oktetów.
+        Co to tak naprawdę oznacza? Każdy adres <em>IPv4</em> możemy rozpisać
+        za pomocą systemu binarnego (0 i 1), oktet o poprostu 8 bitów (bit -
+        najmniejsza ilość informacji, przestawia pojedyńczy stan 0 lub 1), 8
+        zer lub jedynek. Na masce podsieci jedynki określają bity, które są
+        częścią sieciową adresów, a zera tą część która pozostaje do
+        adresowania hostów, dlatego też zera nie mogą występować między
+        jedynkami. Poniżej znajduje się przykład. Mój serwer ma adres
+        <em>192.168.122.7</em> oraz maskę podsieci: <em>255.255.255.0</em>.
+        Poniżej znajduje się zapis tych parametrów w postaci binarnej:
+      </p>
+<pre class="code-block">
+11000000.10101000.01111010.00000111 = 192.168.122.7
+11111111.11111111.11111111.00000000 = 255.255.255.0
+====================================================
+11000000.10101000.01111010. | 00000111 
+        192.168.122.              7
+    Część sieciowa adresu     Część hosta 
+</pre>
+      <p>
+        Maskę możemy zapisać w innej postaci niż dziesiętna (255.255.255.0).
+        Jest to zapis w którym do określenia maski używa się ilości jedynek.
+        Zatem maska z poprzedniego przykładu <em>255.255.255.0</em> wynosiła
+        by <strong>24</strong>. Kombinację adresu <em>IPv4</em> hosta wraz
+        z maską w takim zapisie oddzieloną ukośnikiem (<strong>/</strong>)
+        nazywa się <strong>notacją CIDR</strong> i jest to obecnie
+        najpopularnieszy sposób nadawania adresów <em>IPv4</em> interfejsom
+        sieciowym.
+      </p>
+      <p>
+        Maska podsieci może mieć maksymalną wartość 32 bitów, pozwalając
+        na istnienie jednego adresu w sieci (najczęciej jest wskazanie na
+        konkretny adres) lub minimalną wartość jaką jest 0, alokując tym samym
+        wszystkie możliwe adresy, ok. 4,3 miliarda.
+      </p>
+      <h3 id="16.1.2.privateaddreses">16.1.2. Adresy prywatne</h3>
+      <p>
+        Upowszechnienie się łącz szerokopasmowych dało możliwość budowania w
+        sieci lokalnych, w których systemy są konfigurowane przez centralny
+        serwer (<em>router</em> lub <em>bramę</em>). Tego typu sieci posługują
+        się wenętrzną adresacją zawaną także 
+        <strong>prywatnymi klasami adresów</strong>. Tak jak w klasach
+        publicznych, ogólno dostępne są trzy klasy:
+      </p>
+      <ul>
+        <li><strong>Klasa A</strong>: 10.0.0.0 - 10.255.255.255; maska 8 bitów
+          (255.0.0.0) = 16 777 214 hostów.</li>
+        <li><strong>Klasa B</strong>: 172.16.0.0 - 172.31.255.255; maska 12 
+          bitów (255.240.0.0) = 983010 hostów.</li>
+        <li><strong>Klasa C</strong>: 192.168.0.0 - 192.168.255.255; maska 16
+          bitów (255.255.0.0) = 65534 hostów.</li>
+      </ul>
+      <p>
+        Te klasy są ustalane w standardzie dotyczącym klas prywatnych, jednak
+        administratorzy wolą używać mniejszych klas. Dlatego też klasa 
+        <em>A</em>
+        pozostaje bez zmian, ale w klasie <em>B</em> używa się maski 16 
+        bitowej, a w klasie <em>C</em> maski 24 bitowej.
+      </p>
+      <h3 id="16.1.3.protocols">16.1.3. Protokoły</h3>
+      <p>
+        Protokoły definiują standardy komunikacyjne, które umożliwiają
+        wymianę informacji przez sieć. Protokoły działają na niższych
+        warstwach niż usługi. Do protokołów możemy zaliczyć np. protokół
+        <em>IP</em>, którego adresacji poświęciliśmy cały poprzedni
+        podrozdział. W <em>RHEL</em> oraz w innych dystrybucjach w katalogu 
+        <em>/etc</em> w pliku <em>protocols</em> znajduje się zestawienie
+        protokółów. Poniżej znajduje się fragment tego pliku.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /etc/protocols 
+...
+ip     0       IP              # internet protocol, pseudo protocol number
+hopopt 0       HOPOPT          # hop-by-hop options for ipv6
+icmp   1       ICMP            # internet control message protocol
+igmp   2       IGMP            # internet group management protocol
+ggp    3       GGP             # gateway-gateway protocol
+ipv4   4       IPv4            # IPv4 encapsulation
+st     5       ST              # ST datagram mode
+tcp    6       TCP             # transmission control protocol
+...
+</pre>
+      <h3 id="16.1.4.tcpudp">16.1.4. Protokoły TCP i UDP</h3>
+      <p>
+        Z pośród wcześniejszego zestawienia protokołów, za transmisję danych
+        w sieciach opartych na protokole <em>IP</em>
+        odpowiedzialne są dwa protokoły <strong>TCP</strong> oraz
+        <strong>UDP</strong>.
+      </p>
+      <p>
+        Protokół <em>TCP</em> stosowany w przypadku usług, w których liczy
+        się jakość danych. Ten protokół zestawia połączenie w swojej wartstwie
+        między klient oraz serwerem. Wówczas następuje sekwencjonowana
+        transmisja danych, strony potwierdzają otrzymanie pakietu danych przez
+        to w przypadku zaginięcia pakietu jest on przesyłany ponownie. 
+        Większość usług w internecie opiera się o ten protokół, gdyż pozwala 
+        on na rzetelną wymianę informacji.
+      </p>
+      <p>
+        Innym również często wykorzysywanym protokołem jest <em>UDP</em>.
+        Protokół ten nie zestawia połączenia i poprostu pusza swoje pakiety
+        prawdopodbnie licząc na niezawodność protokołów warstwy niższej jak
+        <em>IP</em>. Nie dokonują on retransmisji gdy pakiety zostaną zgubione.
+        Jednak jest on znacznie szybszy niż <em>TCP</em> dlatego też jest
+        on wykorzystywany do przesyłania danych w czasie rzeczywistym. 
+      </p>
+      <p>
+        Protokoły <em>TCP</em> oraz <em>UDP</em> w wprowadzają pojecie
+        <strong>portu</strong> czyli numeru <em>połączenia</em>,
+        wykorzystywanego do komunikacji. Dane są przesyłane z 
+        <strong>portu prywatnego</strong> 
+        (portu klienta, port wysoki &gt; 10000) do 
+        <strong>portu publicznego</strong> usługi. Do portów publicznych możemy
+        zaliczyć: <em>HTTP</em> - <strong>80/TCP</strong>, 
+        <em>HTTPS</em> - <strong>443/TCP</strong> czy
+        <em>SSH</em> - <strong>22/TCP</strong>. Rodzaj transmisji został podany
+        po ukośniku. Więcej portów publicznych znajduje się w pliku
+        <em>/etc/services</em>, fragment zawartości tego pliku znajduje się
+        poniżej:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ head -100 /etc/services
+...
+ftp             21/tcp
+ftp             21/udp          fsp fspd
+ssh             22/tcp                          # The Secure Shell (SSH) Protocol
+ssh             22/udp                          # The Secure Shell (SSH) Protocol
+telnet          23/tcp
+telnet          23/udp
+# 24 - private mail system
+lmtp            24/tcp                          # LMTP Mail Delivery
+lmtp            24/udp                          # LMTP Mail Delivery
+smtp            25/tcp          mail
+smtp            25/udp          mail
+time            37/tcp          timserver
+...
+</pre>
+      <h3 id="16.1.5.icmp">16.1.5. Protokół ICMP</h3>
+      <p>
+        Protokół <strong>ICMP</strong> jest protokołem diagnostycznym, a jego
+        zadaniem jest sprawdzenie możliwości połaczenia z podanym komputerem.
+        Narzędziem korzystającym z tego protokołu jest <strong>ping</strong>.
+        Zadaniem tego narzędzia jest wysłanie do komputera pakietu i otrzymanie
+        odpowiedzi. Na podstawie otrzymanych (lub nie) danych polecenie
+        rejestruje każdą odpowiedź lub jej brak oraz pod koniec działania 
+        wyświetla statystkę.
+      </p> 
+<pre class="code-block">
+[user@server10 ~]$ ping -c4 192.168.122.7
+PING 192.168.122.7 (192.168.122.7) 56(84) bytes of data.
+64 bytes from 192.168.122.7: icmp_seq=1 ttl=64 time=0.354 ms
+64 bytes from 192.168.122.7: icmp_seq=2 ttl=64 time=0.344 ms
+64 bytes from 192.168.122.7: icmp_seq=3 ttl=64 time=0.517 ms
+64 bytes from 192.168.122.7: icmp_seq=4 ttl=64 time=0.573 ms
+
+--- 192.168.122.7 ping statistics ---
+4 packets transmitted, 4 received, 0% packet loss, time 3086ms
+rtt min/avg/max/mdev = 0.344/0.447/0.573/0.100 ms
+</pre>
+      <p>
+        Przy dużej i w pełni działającej sieci odpowiedzi powinny nie
+        przekraczać 2, 3 ms (milisekund). Czasy tutaj są poniżej 1 ms, ponieważ
+        to sieć wirtualna w wewnątrz tego samego komputera.
+      </p>
+      <h3 id="16.1.6.mac">16.1.6. Adres fizyczny</h3>
+      <p>
+        Każdy z interfejsów posiada swój adres fizyczny. Jest on wykorzystywany
+        do transmisji danych w najniżej warstwie logicznej. Każdy z pakietów,
+        które opuściły komputer źródłówy są opatrzone właśnie tym adresami.
+        Aby poznać adres naszej karty sieciowej należy wydać poniższe polecenie:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ip addr | grep 'ether'
+    link/ether 52:54:00:55:b7:60 brd ff:ff:ff:ff:ff:ff
+</pre>
+      <p>
+        Adres mojej karty to: <code class="code-inline">52:54:00:55:b7:60</code>.
+        Protokół <em>IP</em> ściśle współpracuje z adresem fizycznym. Istnieje
+        nawet protokół <strong>ARP</strong>, który umożliwia zamianę adresów
+        <em>IP</em> na adresy fizyczne.
+      </p>
+      <h3 id="16.1.7.ipv6">16.1.7. Adres IPv6</h3>
+      <p>
+        Ze względu na dość szybką ekspansję internetu, okazało sie że pula
+        adresów <em>IPv4</em> jest na wyczerpaniu. Czego się dziwić, jeśli
+        mamy 8 miliardów ludzi na świecie, a tylko 4,3 miliarda adresów. Nie
+        pomogła również adresacja prywatna. Zatem była potrzeba nowego
+        rozwiązania. I w ten sposób narodził się 
+        <em>Protokół internetowy w wersji 6</em>. Jest on dostępny w 
+        <em>RHEL</em> od wersji 8. Zamiast 32-bitowego adresu wprowadza on
+        128-bitowy adres, który pozwoli zaadresować praktycznie nieosiągalną
+        liczbę hostów (bo aż 340 i 36 zer). Adres ten składa się z 8
+        oddzielonych dwu kropkiem grupy, w której znajdują po cztery liczby
+        heksadecymalne (0 - F). 
+      </p>
+      <p>
+        Protokół <em>IPv6</em>, korzysta z protokołu <em>NDP</em>
+        (ang. <em>Neighbor Discover Protocol</em>), do przeszukiwania sieci
+        i odnajwydwania innych urządzeń sieciowych skonfigurowanych za pomocą
+        tego protokołu. Rozszerza on również funkcjonalność
+        <em>IPv4</em> o diagnostykę problemów związanych z połączniem,
+        powtarzalność adresów oraz routing. Za pomocą poniższego polecenia
+        wyświetliłem adres <em>IPv6</em> interfejsu na swoim komputerze.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ip addr | grep 'inet6'
+    inet6 fe80::5054:ff:fe55:b760/64 scope link noprefixroute 
+</pre>
+      <h3 id="16.1.8.hostname">16.1.8. Nazwa hosta</h3>
+      <p>
+        Każdy system operacyjny ma swoją nazwę, aby ułatwić jego identyfikację
+        w sieci. Nazwa hosta występuje w przypadku dystrybucji Linuksa w
+        symbolu zachęty chociaż możemy ją poznać na kilka róznych sposób.
+        Na przykład:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ hostname
+server10.example.com
+[user@server10 ~]$ hostnamectl --static
+server10.example.com
+[user@server10 ~]$ uname -n
+server10.example.com
+[user@server10 ~]$ nmcli general hostname 
+server10.example.com
+[user@server10 ~]$ cat /etc/hostname
+server10.example.com
+</pre>
+      <p>
+        Natomiast najlepszym i najszybszym sposóbem aby zmienić taką nazwę
+        jest zmiana jej w pliku użytym w ostatnim poleceniu przykładu:
+        <em>/etc/hostname</em>. Po zmianie pliku musimy jeszcze zrestartować
+        usługę <em>systemd-hostnamed.service</em>.
+      </p>
+      <h2 id="16.2.networkdevsandcons">16.2. Urządzenia sieciowe i połączenia</h2>
+      <p>
+        Teraz kiedy mamy solidną porcę wiedzy teoretycznej możemy przejść do 
+        konfiguracji połączeń sieciowych w <em>RHEL</em> 9.
+      </p>
+      <h3 id="16.2.1.networkdevsnaming">16.2.1. Nazewnictwo urządzeń sieciowych w systemie</h3>
+      <p>
+        Do pewnego czasu nazwy urządzeń sieciowych, tj. interfejsów sieciowych
+        były łatwe do zapamiętania, przez co upraszczały zadania
+        administracyjne z nimi związane. Wywodziły się one od takich słów jak
+        <em>Ethernet</em> czy <em>wireless lan</em> i były numerowane od 0 
+        kolejno w takiej samej kolejności w jakiej zostały odnalezione w
+        momencie uruchomienia systemu. Jednak jak to bywa z takimi
+        rozwiązaniami, w przypadku dużej ilość interfejsów po ponownym
+        uruchomieniu systemu ich nazwy mogły być już zupełnie inne. Co
+        prowadziło do problemów konfiguracji. Podobnie jest z dyskami.
+      </p>
+      <p>
+        Obecnie nazwy interfejsów są ustalane za pomocą zasad demona
+        <em>udevd</em>, przez co wprowadza się do systemu spójne oraz
+        przewidywalne nazwenictwo bez wcześniej wspomnianego problemu.
+      </p>
+      <p>
+        Teraz zamiast <em>eth0</em> interfejs może widnieć po nazwą np.
+        <em>enp7s0</em> lub <em>ens160</em>.
+      </p>
+      <h3 id="16.2.2.connectionprofiles">16.2.2. Profile połączeń sieciowych</h3>
+      <p>
+        Do <em>RHEL</em> 9 każe połączenie sieciowe miało swój profil
+        (plik konfiguracyjny) w katalogu <em>/etc/sysconfig/network-scripts</em>
+        Obecnie zrezygnowano z tej metody na rzecz tworzenia plików
+        <em>key-file</em> dla podsystemu sieciowego 
+        <strong>NetworkManager</strong>. Sens profili został w nowych plikach
+        zachowany ponieważ koniec, końców chodzi o konfigurację sieciową
+        interfejsu. Jako jedno z zalet plików <em>key-file</em> jest to iż są
+        prostsze i łatwiejsze do utworzenia. Poniżej znajduje się pliki
+        <em>key-file</em> głównego połączenia sieciowego na mojej maszynie.
+      </p>
+<pre class="code-block">
+[connection]
+id=enp1s0
+uuid=eb849d6a-d642-32e9-9219-9496570c1d45
+type=ethernet
+autoconnect-priority=-999
+interface-name=enp1s0
+timestamp=1658937868
+
+[ethernet]
+
+[ipv4]
+address1=192.168.122.6/24,192.168.122.1
+dns=192.168.122.1;
+method=manual
+
+[ipv6]
+addr-gen-mode=eui64
+method=auto
+
+[proxy]
+
+</pre>
+      <p>
+        Posługiwanie się plikami <em>key-file</em>
+        <strong>jest najlepszym rozwiązaniem jeśli definiujemy dodatkowy interfejs w systemie</strong>.
+        Wówczas do dyspozycji mamy już gotowy plik i na jego podstawie możemy
+        zbudować nasz plik. Poniżej zamieściłem plik, który utworzyłem na
+        potrzeby drugiego połączenia na mojej maszynie.
+        Ten plik zawiera minimalną ilość informacji potrzebną do prawidłowego
+        połączenia sieciowego. To połączenie nie posiada definicji adresu
+        bramy domyślniej (tam kierowane są pakiety jeśli ich adres, jest poza
+        naszą siecią lokalną - adres <em>routera</em> lub bramy) oraz adresów
+        serwerów <em>DNS</em> (serwery <em>DNS</em> zmieniają nazwy domenowe
+        na adresy <em>IP</em>).       
+      </p>
+<pre class="code-block">
+[connection]
+id=enp7s0
+uuid=13e3cf57-9a36-4cb3-a4e0-c1b2411bf984
+type=ethernet
+interface-name=enp7s0
+
+[ethernet]
+
+[ipv4]
+address1=192.168.100.6/24
+method=manual
+
+[ipv6]
+addr-gen-mode=eui64
+method=auto
+
+[proxy]
+
+</pre>
+      <p>
+        Usunąłem z sekcji <code clas="code-inline">[connection]</code> takie 
+        dyrektywy jak
+        <code class="code-inline">autoconnect-priority=-999</code>, oraz
+        <code class="code-inline">timestamp</code>. Z tego względu iż moje
+        połączenie jest w sieci wewnętrznej, usunąłem drugi adres po
+        przecinku w dyrektywie <code class="code-inline">address1</code> oraz
+        dyrektywę <code class="code-inline">dns</code>, z sekcji
+        <code class="code-inline">[ipv4]</code>. Ten plik od pliku bazowego
+        różni się również wartością w dyrektywie
+        <code class="code-inline">uuid</code>, wartość UUID możemy uzyskać za
+        pomocą polecenia <strong>uuidgen</strong>, podając
+        jako argument nazwę interfejsu. Tak stworzony plik należy
+        przenieść do katalogu <em>/etc/NetworkManager/system-connections</em>
+        a następnie załadować za pomocą polecenia
+        <code class="code-inline">nmcli connection load</code> podając
+        ścieżkę do pliku jako argument. Po załadowaniu go, możemy aktywować
+        połączenie za pomocą polecenia
+        <code class="code-inline">nmcli connection up filename</code> i w tym
+        poleceniu również należy podać ścieżkę pliku <em>profilu</em>.
+      </p>
+      <p>
+        Po aktywowaniu tego pliku w systemie pojawi się nowe połączenie:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ip addr
+1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+       valid_lft forever preferred_lft forever
+    inet6 ::1/128 scope host 
+       valid_lft forever preferred_lft forever
+2: enp1s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 52:54:00:55:b7:60 brd ff:ff:ff:ff:ff:ff
+    inet 192.168.122.6/24 brd 192.168.122.255 scope global noprefixroute enp1s0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::5054:ff:fe55:b760/64 scope link noprefixroute 
+       valid_lft forever preferred_lft forever
+3: enp7s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
+    link/ether 52:54:00:ef:9f:e0 brd ff:ff:ff:ff:ff:ff
+    inet 192.168.100.6/24 brd 192.168.100.255 scope global noprefixroute enp7s0
+       valid_lft forever preferred_lft forever
+    inet6 fe80::5054:ff:feef:9fe0/64 scope link noprefixroute 
+       valid_lft forever preferred_lft forever
+</pre>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Jak będziemy mogli zauważyć większość konfiguracji sieciowej obecnie
+        w <em>RHEL</em> kręci się wokół podsystemu <em>NetworkManager</em>.
+        Wystarczy, że będziemy znać jeden ze sposób na konfigurację połączenia
+        sieciowego w systemie.
+      </p>
+      <h3 id="16.2.3.nmcli">16.2.3. Zarządzanie połączeniami sieciowym za pomocą podsystemu NetworkManager</h3>
+      <p>
+        Podsystem <strong>NetworkManager</strong>, to potężne narzędzie, które
+        potrafi ułatwić zarządzanie połączeniami sieciowymi. Za pomocą
+        polecenia <em>nmtui</em>, może zarządzać połączeniami za pomocą
+        prostego interfejsu okien w trybie tekstowym (pakiety dialog, whiptail).
+        Innym narzędziem jest polecenie <strong>nmcli</strong>, którego
+        działanie opiera się na kategoriach objektów. W tym materiale skupimy
+        się wyłącznie na połączeniach - <em>connection</em> oraz urządzeniach
+        - <em>device</em>. Dostęp do czynności możliwych do wykonania otrzymamy
+        gdy podamy po poleceniu nazwę kategorii obiektu i naciśniemy klawisz
+        <em>Tab</em>. Na przykład: 
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ nmcli connection 
+add      delete   edit     help     load     monitor  show     
+clone    down     export   import   modify   reload   up       
+</pre>
+      <p>
+        Jeśli wydamy polecenie <code class="code-inline">nmcli connection</code>
+        bez żadnej akcji wówczas polecenie zwróci nam listę dostępnych
+        w systemie połączeń.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ nmcli connection
+NAME    UUID                                  TYPE      DEVICE 
+enp1s0  eb849d6a-d642-32e9-9219-9496570c1d45  ethernet  enp1s0 
+enp7s0  13e3cf57-9a36-4cb3-a4e0-c1b2411bf984  ethernet  enp7s0 
+</pre>
+      <p>
+        Poniżej znajduje się lista czynności związana z połączeniami:
+      </p>
+      <ul>
+        <li><strong>show</strong> - Wyświetla listę dostępnych połaczeń.</li>
+        <li><strong>up / down</strong> - Aktywuje/dezaktywuje połączenie.</li>
+        <li><strong>add</strong> - Dodaje połączenie.</li>
+        <li><strong>edit</strong> - Zmienia obecnie istniejące połączenie lub
+          dodaje nowe.</li>
+        <li><strong>modify</strong> - Modyfikuje jedno z parametrów połączenia.</li>
+        <li><strong>delete</strong> - Usuwa połączenie.</li>
+        <li><strong>reload</strong> - Nakazuje <em>NetworkManager</em> aby
+          ponownie załadował wszystkie profile połączeń.</li>
+        <li><strong>load</strong> - Nakazuje <em>NetworkManager</em> aby
+          załadował profil połączenia.</li>
+      </ul>
+      <p>
+        Lista czynności związana z urządzeniami.
+      </p>
+      <ul>
+        <li><strong>status</strong> - Pokazuje status urządzenia.</li>
+        <li><strong>show</strong> - Wyświetla informacje na temat wszystkich
+          lub określonych interfejsów sieciowych.
+      </ul>
+      <p>
+        Nazwy kategorii obiektów oraz niektórych czynności możemy zapisać za
+        pomocą jedno literowych skrótów. Na przykład chcąc wyświetlić
+        dostępne w systemie połączenia możemy wydać następujące polecenie:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo nmcli c s
+[sudo] hasło użytkownika user: 
+NAME    UUID                                  TYPE      DEVICE 
+enp1s0  eb849d6a-d642-32e9-9219-9496570c1d45  ethernet  enp1s0 
+enp7s0  13e3cf57-9a36-4cb3-a4e0-c1b2411bf984  ethernet  enp7s0 
+</pre>
+      <p>
+        W powyższym przykładzie użyłem skrótu 
+        <code class="code-inline">c</code> od kategorii <em>connection</em>
+        oraz skrótu <code class="code-inline">s</code> od czynności 
+        <em>show</em>. Więcej skrótów znajdziemy na stronie podręcznika.
+      </p>
+      <h3 id="16.2.4.nmcliaddconnection">16.2.4. Tworzenie nowych połączeń sieciowych za pomocą nmcli</h3>
+      <p>
+        Jak moglismy wynioskować na podstawie czynność z poprzedniego
+        podrozdziału, możemy wykorzystać polecenie <strong>nmcli</strong> do
+        tworzenia nowych połączeń. Dodawanie połączenia rozpoczniemy od
+        sprawdzenia dostępnych w systemie interfejsów sieciowych.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo nmcli d s
+[sudo] hasło użytkownika user: 
+DEVICE  TYPE      STATE          CONNECTION 
+enp1s0  ethernet  połączono      enp1s0     
+enp7s0  ethernet  połączono      enp7s0     
+enp8s0  ethernet  rozłączono     --         
+lo      loopback  niezarządzane  --         
+</pre>
+      <p>
+        Jeden z interfejsów znajduje się w stanie
+        <code class="code-inline">rozłączono</code>. Ten interfejs posłuży nam
+        do stworzenia nowego połączenia. Za pomocą czynności <em>add</em>
+        tworzmy nowe połączenie sieciowe.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo nmcli c add type Ethernet ifname enp8s0 con-name enp8s0 ip4 192.168.100.8/24 gw4 192.168.100.1
+[sudo] hasło użytkownika user: 
+Pomyślnie dodano połączenie „enp8s0” (ff0d4164-b179-4d03-804d-ff08f8f4da31).
+</pre>
+      <p>
+        Na powyższym przykładzie dodałem nowe połączenie
+        (<code class="code-inline">c add</code>) typu <em>Ethernet</em>
+        (<code class="code-inline">type Ethernet</code>), użyłem do tego
+        interfejsu <em>enp8s0</em> 
+        (<code class="code-inline">ifname enp8s0</code>). Nadałem nazwę
+        połączeniu od nazwy interfejsu - <em>enp8s0</em>
+        (<code class="code-inline">con-name enp8s0</code>), na końcu ustawiłem
+        adres <em>IPv4</em> z 24 bitową maską
+        (<code class="code-inline">ip4 192.168.100.8/24</code>) oraz adres
+        bramy domyślnej (<code class="code-inline">gw4 192.168.100.1</code>).
+      </p>
+      <p>
+        Tak utworzone połączenie nie wymaga już żadnej czynności, od razu jest
+        ono gotowe do pracy, o czym może świadczyć lista połączeń na poniższym
+        przykładzie.
+      </p>
+      <p>
+        Połączenia zarządzane za pomocą <em>NetworkManager</em> możemy wyłączać
+        oraz włączać.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo nmcli c s
+[sudo] hasło użytkownika user: 
+NAME    UUID                                  TYPE      DEVICE 
+enp1s0  eb849d6a-d642-32e9-9219-9496570c1d45  ethernet  enp1s0 
+enp7s0  13e3cf57-9a36-4cb3-a4e0-c1b2411bf984  ethernet  enp7s0 
+enp8s0  ff0d4164-b179-4d03-804d-ff08f8f4da31  ethernet  enp8s0 
+</pre>
+      <p>
+        Połączenia zarządzane za pomocą <em>NetworkManager</em> możemy wyłączać
+        oraz włączać.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo nmcli c down enp8s0
+Pomyślnie dezaktywowano połączenie „enp8s0” (ścieżka aktywacji D-Bus: /org/freedesktop/NetworkManager/ActiveConnection/3)
+[user@server10 ~]$ sudo nmcli c s
+NAME    UUID                                  TYPE      DEVICE 
+enp1s0  eb849d6a-d642-32e9-9219-9496570c1d45  ethernet  enp1s0 
+enp7s0  13e3cf57-9a36-4cb3-a4e0-c1b2411bf984  ethernet  enp7s0 
+enp8s0  ff0d4164-b179-4d03-804d-ff08f8f4da31  ethernet  --     
+
+[user@server10 ~]$ sudo nmcli c up enp8s0
+Pomyślnie aktywowano połączenie (ścieżka aktywacji D-Bus: /org/freedesktop/NetworkManager/ActiveConnection/4)
+[user@server10 ~]$ sudo nmcli c s
+NAME    UUID                                  TYPE      DEVICE 
+enp1s0  eb849d6a-d642-32e9-9219-9496570c1d45  ethernet  enp1s0 
+enp7s0  13e3cf57-9a36-4cb3-a4e0-c1b2411bf984  ethernet  enp7s0 
+enp8s0  ff0d4164-b179-4d03-804d-ff08f8f4da31  ethernet  enp8s0 
+</pre>
+      <h3 id="16.2.5.hostsfile">16.2.5. Plik /etc/hosts</h3>
+      <p>
+        Za pomocą pliku <em>/etc/hosts</em> możemy zbudować wewnątrz systemu
+        mapowanie nazw domenowych na adresy <em>IP</em>, dzięki czemu będziemy
+        mogli posługiwać się prostymi nazwami zamiast adresami <em>IP</em>.
+        Każdy z wpisów w pliku składa się z trzech kolumn: adresu <em>IP</em>,
+        nazwy domenowej oraz aliasu (krótkiej dodatkowej nazwy, której możemy
+        używać zamiast nazwy domenowej, jeśli ta okaże się dość długa).
+        Najczęściej w aliasie zapisywana jest nazwa hosta bez sufiksu
+        domenowego. Na poniższym przykładzie znajduje się zawartość pliku
+        <em>/etc/hosts</em> z mojego serwera.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /etc/hosts
+127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
+::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
+192.168.122.6 server10.example.com server10
+192.168.122.7 server20.example.com server20
+192.168.100.6 server10s7.example.com server10s7
+192.168.100.7 server20s7.example.com server20s7
+</pre>
+      <p>
+        Pierwsze dwa wpisy dotyczą tego aby odwołanie się do
+        <code class="code-inline">localhost</code> zwracało adres pętli
+        zwrotnej. Wpisy poniżej to mapowania adresów na nazwy maszyn
+        wykorzystywanych do ćwiczeń w tym materiale. Zwróćmy uwagę na to, iż
+        w pierwszych wierszach zdefiniowano więcej niż jeden alias.
+      </p>
+      <h3 id="16.2.6.connectivitytest">16.2.6. Testowanie łączności</h3>
+      <p>
+        A przetestować możliwość połączenia między klietem a serwera lub
+        między serwerami możemy skorzystać z jednego z narzędzi potokołu
+        <em>ICMP</em>, a mianowicie narzędzia <strong>ping</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ping -c4 server20s7.example.com 
+PING server20s7.example.com (192.168.100.7) 56(84) bytes of data.
+64 bytes from server20s7.example.com (192.168.100.7): icmp_seq=1 ttl=64 time=0.497 ms
+64 bytes from server20s7.example.com (192.168.100.7): icmp_seq=2 ttl=64 time=0.335 ms
+64 bytes from server20s7.example.com (192.168.100.7): icmp_seq=3 ttl=64 time=0.483 ms
+64 bytes from server20s7.example.com (192.168.100.7): icmp_seq=4 ttl=64 time=0.302 ms
+
+--- server20s7.example.com ping statistics ---
+4 packets transmitted, 4 received, 0% packet loss, time 3096ms
+rtt min/avg/max/mdev = 0.302/0.404/0.497/0.086 ms
+</pre>
+      <p>
+        Za pomocą poniższego polecenia wysłałem cztery pakiety diagnostyczne
+        (<code class="code-inline">-c4</code>) przy użyciu sieci wewnętrznej
+        do drugiej maszyny w laboratorium.
+      </p>
+      <h3 id="exec16.1">Ćwiczenie 1: Zmiana nazwy hosta</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej <em>server1</em> oraz <em>server2</em> zmień nazwę hosta
+        z <em>server1</em> na <em>server10</em> oraz z <em>server2</em> na
+        Przy użyciu wykorzystywanego przez ciebie sposóbu wirtualizacji,
+        stwórz sieć wewnętrzną. Następnie dodaj do każdej z maszyn dodatkowy
+        interfejs sieciowy. Jak użytkownik z możliwością podniesienia uprawnień
+        za pomocą dowolnej metody dodaj i skonfiguruj połączenia sieciowe na
+        obu maszynach. Następnie dodaj wpisy wskazujące na maszyny do
+        pliku <em>/etc/hosts</em> na każdej znich. Wykonanie tych czynności
+        potwierdź sprawdzeniem połączenia.
+      </p>
+      <h2 id="ch16summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale zapoznaliśmy się z fundamentalnymi pojęciami 
+        związanymi z siecią. Poznalimśmy adresy <em>IPv4</em>, klasy adresów,
+        adresy <em>IPv6</em> oraz kilka protokołów. Dowiedzieliśmy się jak
+        zarządzać połączeniami sieciowym w <em>RHEL</em> 9. Poznaliśmy
+        prosty system, który umożliwi nam pisanie nazw hostów zamiast adresów
+        <em>IP</em> oraz sposób na testowanie łączności. W następnym rozdziale
+        zajmiemy się sieciowym systemem plików.
+      </p>
+      <h1 id="17.nfs">17. Network File System</h1>
+      <p>
+        Niektóre z mechanizmów współdzielenia dostępnych na <em>Red Hat
+        Enterprise Linux</em> pozwalają na korzystanie z udostępnionych plików,
+        tak
+        jakby były by one lokalnie dostępne. Jednym z takich mechanizmów jest
+        <strong>NFS</strong>, jego obsługa na docelowym systemie sprowadza się
+        do wydania pojedynczego polecenia <em>mount</em>, a z dodatkowym
+        demonem <strong>AutoFS</strong> tak na prawdę wystarczy próba dostępu
+        do katalogu w którym powinny znajdować się dane aby były one dostępne
+        na naszym komputerze.
+      </p>
+      <p>
+        <em>NFS</em> czyli (ang. <em>Network File System</em>) sieciowy
+        system plików jest usługą sieciową pozwalającą na współdzielenie
+        zasobów plikowych. <em>NFS</em> działa w architekturze klient-serwer. 
+        Co oznacza,
+        że jeden z komputerów udostępnia pliki, na których drugi komputer 
+        po podłączeniu jest w stanie pracować. <em>NFS</em> udostępnia
+        foldery, a każdy taki folder nazwany jest <strong>udziałem</strong>.
+        Natomiast sam proces udostępniania folderu (udziału) nazywany
+        jest <strong>eksportem</strong>. Przyczym eksport może być dokonany w
+        kierunku <strong>okreslonego/określonych</strong> klienta/klientów.
+        Klient chcąc skorzystać z udziału <em>NFS</em> dokonuje jego montowania
+        tak jakby podłączał dodatkowy system plików do swojego systemu,
+        podając oczywiście odpowiednie parametry.
+      </p>
+      <p>
+        Za stosowaniem <em>NFS</em> płynie wiele korzyści o takich jak
+        wieloplatformowość, wieloużytkowość, redukcja kosztów administracyjnych
+        oraz związanych z zakupem kolejnych dysków. Po zastosowaniu mechanizmów
+        <em>AutoFS</em> będziemy w stanie zapewnić użytkownikom zdalne 
+        katalogi domowe.
+      </p>
+      <p>
+        Dostępnych jest wiele wersji <em>NFS</em>. W <em>RHEL</em> od wersji 8
+        domyślną wersją <em>NFS</em> jest wersja 4.2, która daje możliwość
+        wykorzystania wyłącznie protokołu <em>TCP</em> zapisu
+        asynchronicznego oraz obsługuje pliki powyżej 2GB. Po za tym pozwala 
+        ona
+        na połączenia przez <em>firewall</em> oraz internet. Wersja ta
+        usprawnia kilka zabezpieczeń, wspiera szyfrowanie transmisji oraz
+        możliwość użycia <em>ACL</em>.
+      </p>
+      <h2 id="17.1.nfsconfig">17.1. Konfiguracja serwera oraz klienta NFS</h2>
+      <p>
+        Na początku zadań praktycznych skonfigurujemy sobie prosty udział, aby
+        mniej więcej wiedzieć jak skonfigurować serwer <em>NFS</em>.
+      </p>
+      <h3 id="17.1.1.nfsserverconfig">17.1.1. Konfiguracja serwera <em>NFS</em></h3>
+      <p>
+        Konfigurację zaczynamy od serwera i tam na początku instalujemy
+        niezbędne oprogramowanie. 
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ sudo dnf install nfs-utils
+[sudo] hasło użytkownika user: 
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 1:05:53 temu w dniu pią, 29 lip 2022, 15:59:59.
+Pakiet nfs-utils-1:2.5.4-10.el9.x86_64 jest już zainstalowany.
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+</pre>
+      <p>
+        Następnie tworzymy katalog który będzie udziałem. Nadajemy mu
+        odpowiednie uprawnienia, aby każdy klient mógł zapisywać w nim swoje
+        pliki.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ sudo mkdir /nfstest
+[sudo] hasło użytkownika user: 
+[user@server20 ~]$ sudo chmod 777 /nfstest
+</pre>
+      <p>
+        Następnie w pliku <em>/etc/exports</em>, definiuje eksport udziału do
+        klienta. Eksport pozwala również na zdefiniowanie dodatkowych opcji
+        dotyczących udziału, w naszym przypadku będzie przypisanie klientowi
+        możliwości zapisu oraz odczytu.
+      </p>
+<pre class="code-block">
+/nfstest server10(rw)
+</pre>
+      <p>
+        Po zdefiniowaniu eksportu możemy przejść do uruchomienia demona NFS.
+        Następnie otworzymy port na zaporze sieciowej pozwalający na 
+        swobodną komunikację klienta z serwerem. 
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ sudo systemctl enable --now nfs-server.service
+Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /usr/lib/systemd/system/nfs-server.service.
+[user@server20 ~]$ sudo firewall-cmd --permanent --add-service nfs
+success
+[user@server20 ~]$ sudo firewall-cmd --reload 
+success
+</pre>
+      <p>
+        Teraz wystarczy tylko zmusić demona <em>NFS</em>, aby dokonał eksportu.
+        A możemy to zrobić za pomocą poniższego polecenia.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ sudo exportfs -av
+exporting server10.example.com:/nfstest
+</pre>
+      <p>
+        Opcja <code class="code-inline">-a</code> nakazuje eksport wszystkich
+        udziałów zapisanych w pliku <em>/etc/exports</em>, natomiast opcją
+        <code class="code-inline">-v</code> włącza bardziej szczegółowe
+        wyświetlanie komunikatów diagnostycznych. Bez tej opcji polecenie nie
+        zwróci nic. Konfigurację serwera możemy uznać za zakończoną. Teraz
+        przejdziemy do konfiguracji klienta.
+      </p>
+      <h3 id="17.1.2.nfsclientconfig">17.1.2. Konfiguracja klienta NFS</h3>
+      <p>
+        Konfigurację klienta tak jak serwera musimy rozpocząć od zainstalowania
+        niezbędnego oprogramowania, ponieważ obsługa <em>NFS</em> nie jest
+        natywnie wbudowana.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo dnf install nfs-utils
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:24:05 temu w dniu pią, 29 lip 2022, 17:16:50.
+Pakiet nfs-utils-1:2.5.4-10.el9.x86_64 jest już zainstalowany.
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+</pre>
+      <p> 
+        Podłączanie się do serwera <em>NFS</em> wygląda jak zwykłe montowanie
+        systemu plików w systemie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo mount server20:/nfstest /media
+</pre>
+      <p>
+        Nie musimy podawać nawet typu systemu plików. Aby nie musieć podłączać
+        się za każdym razem możemy dopisać poniższy wiersz do pliku
+        <em>/etc/fstab</em>.
+      </p>
+<pre class="code-block">
+server20:/nfstest /local nfs _netdev 0 0
+</pre>
+      <p>
+        Na powyższym przykładzie użyłem opcji 
+        <code class="code-inline">_netdev</code>, ponieważ do realizacji tego
+        montowania potrzebna jest działająca na systemie sieć.
+      </p>
+      <h2 id="17.2.autofs">17.2. Konfiguracja udziału NFS za pomocą AutoFS</h2>
+      <p>
+        Dla konfiguracji klienta jest o wiele lepsze rozwiązanie niż ręczne
+        montowanie <em>NFS</em> lub wpis w <em>/etc/fstab</em>. W <em>RHEL</em>
+        jest dostępny demon, który pozwala na zamontowanie udziału <em>NFS</em>
+        w momecie gdy jest on potrzebny. Na przykład gdy chcemy wyświetlić
+        zawartość katalogu, w którym powinny znajdować się udostępnione przez
+        niego pliki. Tym zajmuje się właśnie <strong>AutoFS</strong>. Ten
+        demon, nie tylko montuje na żądanie ale także odłącza go gdy nie ma
+        prób uzyskania dostępu do niego przez okres 5 minut. Główny plik
+        konfiguracyjny znajduje się w katalogu <em>/etc</em> pod nazwą
+        <em>autofs.conf</em>. Poniżej znajduje się jego zawartość:
+      </p>
+<pre class="code-block">
+[ autofs ]
+timeout = 300
+browse_mode = no
+mount_nfs_default_protocol = 4
+[ amd ]
+dismount_interval = 300
+</pre>
+      <p>
+        W tym pliku są ustawiane globalne opcje takie jak czas oczekiwania 
+        na udział (<code class="code-inline">timeout=300</code>) czy czas po
+        którym udział zostanie odłączony 
+        (<code class="code-inline">dismount_interval=300</code>). Jednak ten
+        plik nie służy do definicji automatycznego montowania.
+      </p>
+      <p>
+        Wszelkiego rozdzaju montowanie bo nie tylko udziałów definiowane jest w 
+        pliku <em>/etc/auto.master</em>. Poniżej znajduje się jego zawartość 
+        bez komentarzy oraz pustych linii.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ grep -v -e '^#' -e '^$' /etc/auto.master
+/misc  /etc/auto.misc
+/net   -hosts
++dir:/etc/auto.master.d
++auto.master
+</pre>
+      <p>
+        Montowania za pomocą <em>AutoFS</em> nazwane jest 
+        <strong>mapowaniem</strong>. Mapowania możemy dokonać na trzy sposoby:
+        <strong>główny</strong>, <strong>bezpośredni</strong> oraz
+        <strong>pośredni</strong>. Przyczym główny sposób mapowania służy
+        jedynie do określenia czy mapowanie będzie bezpośrednie lub pośrednie.
+        Samych mapowań dokonuje się w plikach użytkowników składowanych w
+        katalogu <em>/etc/auto.master.d</em>. W jednym z takich plików może
+        znajdować się wiele punktów montowania. W pliku <em>/etc/auto.master</em>
+        najczęściej definiuje się zbiorczy punkt montowania oraz rodzaj 
+        mapowania. Natomiast konkretne udziały z wyszczególnionymi punktami
+        montowania 
+        zapisuje się właśnie w plikach użytkowników. Jedno z mapowań jest już 
+        zapisane w pierwszej linii powyższego przykładu.
+      </p>
+      <h3 id="17.2.1.directmap">17.2.1. Mapowanie bezpośrednie</h3>
+      <p>
+        W przypadku mapowania bezpośredniego montowana jest dowolna ilość 
+        niepowiązanych ze sobą punktów montowania. Przyczym o to kilka punktów
+        o których trzeba wiedzieć używając tego rodzaju mapowania. 
+      </p>
+      <ul>
+        <li>Każdy udział montowany bezpośrednio jest widoczny dla użytkowników.</li>
+        <li>Montowanie lokalne oraz bezpośrednio montowane udziały mogą
+          istnieć w tym samym katalogu nadrzędnym.</li>
+        <li>Uzyskanie dostępu do katalogu zawierającego wiele montowanych
+          bezpośrednio udziałów podłączy do systemu je wszystkie.</li>
+      </ul>
+      <p>
+        Każdy udział montowany bezpośrenio będzie mieć osobny wpis w wyniku
+        działania polecenia <em>mount</em> wydanego bez argumentów. Na
+        poniższych przykładach pokazałem jak możemym wykorzystać 
+        <em>AutoFS</em> do bezpośredniego montowania udziału <em>NFS</em> z
+        poprzedniego podrozdziału.
+      </p>
+      <p>
+        W pliku <em>/etc/auto.master</em> zapisuje poniższą linię:
+      </p>
+<pre class="code-block">
+/-  /etc/auto.master.d/auto.direct
+</pre>
+      <p>
+        Oznacza ona mapowanie bezpośrednie. <code class="code-inline">/-</code>
+        onznacza, że punkty montowania w pliku mapowania użytkownika
+        <code class="code-inline">/etc/auto.master.d/auto.direct</code> będą
+        przestawiowe w postaci ścieżek bezwzględnych. W pliku mapowania
+        zapisujemy poniższą linię.
+      </p>
+<pre class="code-block">
+/nfstest  server20:/nfstest
+</pre>
+      <p>
+        Po włączeniu usługi za pomocą polecenia
+        <code class="code-inline">sudo systemctl enable --now autofs.service</code>
+        wystarczy, że wyświetlimy zawartość głównego katalogu i zauważym nowy
+        folder <em>/nfstest</em> z zamontowanym udziałem.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -l /
+razem 26
+dr-xr-xr-x.   2 root root    6 2021-08-10  afs
+drwxr-xr-x.   2 root root    6 07-29 13:11 autodir
+lrwxrwxrwx.   1 root root    7 2021-08-10  bin -&gt; usr/bin
+dr-xr-xr-x.   5 root root 4096 07-16 21:23 boot
+drwxr-xr-x.  21 root root 3280 07-29 12:36 dev
+drwxr-xr-x. 108 root root 8192 07-29 21:46 etc
+drwxr-xr-x.   3 root root   18 07-16 21:25 home
+lrwxrwxrwx.   1 root root    7 2021-08-10  lib -&gt; usr/lib
+lrwxrwxrwx.   1 root root    9 2021-08-10  lib64 -&gt; usr/lib64
+drwxr-xr-x.   2 root root    6 07-29 12:39 local
+drwxr-xr-x.   2 root root    6 2021-08-10  media
+drwxr-xr-x.   2 root root    0 07-29 21:46 misc
+dr-xr-xr-x.   1 root root 2048 04-19 22:42 mnt
+drwxr-xr-x.   2 root root    0 07-29 21:46 net
+drwxr-xr-x.   2 root root    6 07-29 15:14 nfshome
+drwxrwxrwx.   2 root root    6 07-29 17:17 nfstest
+drwxr-xr-x.   2 root root    6 2021-08-10  opt
+dr-xr-xr-x. 199 root root    0 07-29 12:36 proc
+dr-xr-x---.   2 root root  167 07-29 21:46 root
+drwxr-xr-x.  37 root root 1220 07-29 21:46 run
+lrwxrwxrwx.   1 root root    8 2021-08-10  sbin -&gt; usr/sbin
+drwxrwxrwx.   2 root root    6 07-29 15:34 sharenfs
+drwxr-xr-x.   2 root root    6 2021-08-10  srv
+dr-xr-xr-x.  13 root root    0 07-29 12:36 sys
+drwxrwxrwt.   9 root root 4096 07-29 21:46 tmp
+drwxr-xr-x.  12 root root  144 07-16 21:11 usr
+drwxr-xr-x.  20 root root 4096 07-16 21:29 var
+</pre>
+      <p>
+        Poniżej zamieszczam wynik działania polecenia <em>mount</em> bez
+        argumentów:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ mount
+...
+/etc/auto.master.d/auto.direct on /nfstest type autofs (rw,relatime,fd=17,pgrp=1313,timeout=300,
+minproto=5,maxproto=5,direct,pipe_ino=26905)
+server20:/nfstest on /nfstest type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144,
+namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.122.6,local_lock=none,
+addr=192.168.122.7)
+</pre>
+      <h3 id="17.2.2.indirectmap">17.2.2. Mapowanie pośrednie</h3>
+      <p>
+        Mapowanie pośrednie jest wykorzystywane gdy chcemy zamontować
+        wszystkie udziały w jednym wspólnym katalogu nadrzędnym. Oto kilka
+        punktów jakie trzeba znać podczas mapowania pośredniego.
+      </p>
+      <ul>
+        <li>Udziały zamontowane pośrednio są widoczne w momencie uzyskania do 
+          nich dostępu.</li>
+        <li>Montowania lokalne oraz montowania pośrednie nie mogą istnieć w tym
+          samym katalogu nadrzędnym.</li>
+        <li>Każde montowanie pośrednie generuje jeden wpis w pliku
+          <em>/etc/mtab</em> - systemowa tablica montowania (stąd informacje
+          pobiera polecenie <em>mount</em> wydane bez żadnego argumentu).</li>
+        <li>Próba uzyskania dostępu katalogu zawierającego punkty montowania
+          pośredniego pokaże tylko udziały które zostały już zamontowane.</li>
+      </ul>
+      <p>
+        Poniżej przedstawiam w jaki sposób można zamontować udział <em>NFS</em>
+        z poprzedniego podrozdziału za pomocą mapowania pośredniego 
+        <em>AutoFS</em>.
+      </p>
+      <p>
+        Na początęk wyświetlimy zawartość głównego pliku mapowania czyli
+        <em>/etc/auto.master</em>
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ grep -v -e '^#' -e '^$' /etc/auto.master
+/misc  /etc/auto.misc
+/net   -hosts
++dir:/etc/auto.master.d
++auto.master
+</pre>
+      <p>
+        W pierszej linii znajduje się definicja katalogu nadrzędnego
+        przygotowana przez <em>AutoFS</em>. W tej linii znajduje się także
+        ścieżka do pliku, w którym należy zapisać definicje udziałów do
+        mapowania pośredniego. Zapisujemy więc poniższą linię do pliku
+        <code class="code-inline">/etc/auto.misc</code>.
+      </p>
+<pre class="code-block">
+nfstest server20:/nfstest
+</pre>
+      <p>
+        Po zapisaniu zmian w pliku restartujemy usługę. Teraz możemy spróbować
+        uzyskać dostęp do udziału. Udział będzie dostępny jak podkatalog
+        katalogu <em>/misc</em>
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo systemctl restart autofs.service 
+[user@server10 ~]$ ls -l /misc/nfstest
+razem 0
+</pre>
+      <p>
+        Poniżej znajdują się wpisy z systemowego rejestru montowania:
+      </p>
+<pre class="code-block">
+/etc/auto.misc on /misc type autofs (rw,relatime,fd=5,pgrp=1042,timeout=300,minproto=5,maxproto=5,
+indirect,pipe_ino=24514)
+server20:/nfstest on /misc/nfstest type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144,
+namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.122.6,local_lock=none,
+addr=192.168.122.7)
+</pre>
+      <p>
+        Zwróćmy uwagę na to, iż występuje tylko jeden wpisy dotyczący katalogu
+        <em>/misc</em> typu <em>autofs</em>. Gdzie w przypadku montowania
+        bezpośredniego, każdy punkt montowania posiadał własny wpis typu 
+        <em>autofs</em>.
+      </p>
+      <p>
+        Jeśli należałoby wybrać między mapowaniem bezpośrednim oraz pośrednim.
+        To tak naprawdę, nie ma lepszych czy gorszych. Każde z rodzajów
+        mapowań ma swoje cechy kluczowe, które sobie omówiliśmy w listach
+        przed każdym z przykładów. Na podstawie tych cech oraz potrzeb jakie
+        ma spełniać udział należy wybrać odpowiednią dla siebie metodę.
+      </p>
+      <h3 id="17.2.3.homeautomount">17.2.3. Automatyczne montowanie zdalnych katalogów domowych</h3>
+      <p>
+        Przy użyciu <em>AutoFS</em> oraz montowania pośredniego możemy
+        zamontować katalog domowy użytkownika z innego serwera o ile są one
+        udostępnione za pomocą <em>NFS</em>. Aby to zrealizować potrzebne są
+        dwa czynniki:
+      </p>
+      <ol>
+        <li>Katalog <em>/home</em> na serwerze powinien zostać wyeksportowany.</li>
+        <li>Udwzorowanie użytkowników na obu systemach powinno być takie same,
+          tj. najlepiej aby użytkownicy mieli te same <em>UID</em>-y aby
+          uniknąć problemów z prawem własności plików złożonych katalogch
+          domowych.</li> 
+      </ol>
+      <p>
+        Aby przetestować <em>AutoFS</em> w praktyce wykonamy kilka czynności,
+        aby odzworowany użytkownik z jednego serwera na drugim serwerze miał 
+        dostęp do swoich danych.
+      </p>
+      <p>
+        Na początku na <strong>serwerze, który udostępnia katalogi domowe</strong>
+        tworzymy użytkownika. Ja utworzyłem użytkownika
+        <em>user40</em> z UID wynoszącym <em>4040</em> oraz nadałem mu hasło.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ sudo useradd -u 4040 user40
+[sudo] hasło użytkownika user: 
+[user@server20 ~]$ sudo passwd user40
+Zmienianie hasła użytkownika user40.
+Nowe hasło: 
+BŁĘDNE HASŁO: Hasło jest krótsze niż 8 znaków
+Proszę ponownie wpisać nowe hasło: 
+</pre>
+      <p>
+        Następnie dokonujemy eksportu katalogu <em>/home</em> oraz wymuszamy
+        zmianę udziałów <em>NFS</em>.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ cat /etc/exports
+/home  server10(rw)
+[user@server20 ~]$ sudo exportfs -avr
+exporting server10.example.com:/home
+</pre>
+      <p>
+        Tak naprawdę na tym konfiguracja serwera kończy się. Przejdziemy teraz
+        do konfiguracji klienta. W pliku <em>/etc/auto.master</em> utworzymy
+        nową deklaracje katalogu nadrzędnego dla punktów montowania
+        pośredniego.
+      </p> 
+<pre class="code-block">
+[user@server10 ~]$ grep -v -e '^#' -e '^$' /etc/auto.master
+/misc  /etc/auto.misc
+/nfshome       /etc/auto.master.d/auto.home
+/net   -hosts
++dir:/etc/auto.master.d
++auto.master
+</pre>
+      <p>
+        W drugiej linii znajduje się katalog nadrzędny, w którym będą
+        przechowywane katalogi domowe. Musimy go utworzyć.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo mkdir /nfshome
+</pre>
+      <p>
+        Następnie w pliku w którym powinny znajować się definicję punktów
+        montowania zapisujemy poniższą linię:
+      </p>
+<pre class="code-block">
+* -rw server20:/home/&amp;
+</pre>
+      <p>
+        W tym zapisie gwiazdka odnosi się dowolnej nazwy punktu montowania,
+        ponieważ użytkowników może być bardzo dużo i nie sensu ich tu
+        wszystkich wypisywać. Ampersand (<strong>&amp;</strong>) może być
+        odwołaniem do wielu serwerów lub wielu udziałów <em>NFS</em>. W tym
+        przypadku został użyty do wskazania wielu katalogów w udziale.
+        Po zapisaniu zmian w pliku należy zrestartować usługę.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo systemctl restart autofs
+</pre>
+      <p>
+        Teraz wystarczy odwzrować użytkownika i się na niego przełączyć.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo useradd -u 4040 -b /nfshome -M user40
+[user@server10 ~]$ su - user40
+Hasło: 
+[user40@server10 ~]$
+</pre>
+      <p>
+        Podczas odwzorowywania użytkownika nadałem mu <em>UID</em> 4040, taki 
+        sam jak na serwerze (<code class="code-inline">-u 4040</code>),
+        wskazałem mu inny niż <em>/home</em> katalog bazowy dla katalogów
+        domowych (<code class="code-inline">-b /nfshome</code>) w tym przypadku
+        jest katalog nadrzędny dla punktów montowania pośredniego 
+        <em>AutoFS</em>. Użyłem również opcji 
+        <code class="code-inline">-M</code>, aby podczas tworzenia nowego
+        użytkownika nie został utworzony katalog domowy. Po utworzeniu 
+        użytkownika przełączyłem się na niego. Poniżej znajdują się wpisy 
+        z systemowego rejestru montowania, świadczące o tym iż katalog
+        domowy użytkownika <code class="code-inline">user40</code> jest
+        katalogiem zdalnym podłączonym z pomocą <em>NFS</em>.
+      </p>
+<pre class="code-block">
+[user40@server10 ~]$ pwd
+/nfshome/user40
+[user40@server10 ~]$ mount
+...
+/etc/auto.master.d/auto.home on /nfshome type autofs (rw,relatime,fd=11,pgrp=1756,timeout=300,
+minproto=5,maxproto=5,indirect,pipe_ino=28415)
+server20:/home/user40 on /nfshome/user40 type nfs4 (rw,relatime,vers=4.2,rsize=262144,wsize=262144
+,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.122.6,local_lock=none,
+addr=192.168.122.7)
+</pre>
+      <p>
+        W ten sposób mogę utrzymać jeden katalog domowy na zdalnym serwerze 
+        i korzystać z niego na wielu komputerach.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Jednym z zdań egzaminacyjnych może być automatyczne montowanie zdalnych
+        katalogów domowych z wykorzystaniem <em>NFS</em> oraz <em>AutoFS</em>.
+      </p>
+      <h3 id="exec17.1">Ćwiczenie 1: Tworzenie udziału NFS oraz mapowanie bezpośrednie</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server10</em> utwórz udział <em>NFS</em> z katalogu
+        <em>/sharenfs</em> i udostępnij go. Na maszynie <em>server20</em>
+        zainstaluj usługę <em>AutoFS</em>, następnie skonfiguruj automatyczne
+        montowanie wcześniej utworzonego udziału w sposób bezpośredni.
+        Spróbuj uzyskać dostęp do udziału, aby go zamontować. Potwierdź to
+        za pomocą polecenia <em>df -h</em>. 
+      </p>
+      <h3 id="exec17.2">Ćwiczenie 2: Pośrednie mapowanie udziału NFS</h3>
+      <p>
+        Wykorzystując udział z poprzedniego ćwiczenia zmień konfigurację
+        <em>AutoFS</em> aby udział montowany był w sposób pośredni w katalogu
+        nadrzędnym <em>/autoindir</em>. Spróbuj uzyskać dostęp do
+        udostępnionego w ten sposób udziału. Potwierdź to za pomocą polecenia
+        <em>df -h</em>
+      </p>
+      <h2 id="ch17summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale poznaliśmy pierwszą usługę sieciową, która służy do
+        udostępniania plików a jest nią <em>NFS</em>. Nauczyliśmy się
+        konfigurować udziały na serwerze oraz montować je na systemach
+        klienckich. Poznaliśmy usługę <em>AutoFS</em>, która pozwala na
+        za montowanie udziału <em>NFS</em>, kiedy będzie on potrzebny.
+        Poznaliśmy też jej konfiguracje w kilku ciekawych przypadkach.
+        Następny rozdział będzie poświęcony synchronizacji czasu systemowego
+        oraz rozwiązywaniu nazw domenowych.
+      </p>
+      <h1 id="18.ntpanddns">18. Synchronizacja czasu oraz rozwiązywanie nazw w RHEL 9</h1>
+      <p>
+        Wiele komponentów systemowych opiera swoje czynności o poprawność
+        daty i czasu. Jednym z nich, który każdemu przychodzi do głowy jest
+        <em>cron</em> - systemowy harmonogram zadań. Bez ustawień czasu 
+        harmonogram był by najzwyczajniej w świecie bezużyteczny. Nad
+        poprawnością czasu w systemach Uniksowych czuwa protokół
+        <strong>NTP</strong> wraz z jego najnowszą implementacją w postaci
+        programu <strong>chrony</strong>.
+      </p>
+      <p>
+        Aby osoba korzystająca z komputera nie musiała zapamiętać liczb adresu
+        <em>IP</em> chcąc zapmiętać adres strony, wprowadzono
+        prostsze do zapamiętania nazwy domenowe. Mimo
+        tego adres <em>IP</em> dalej jest potrzebny do realizacji połączenia,
+        zatem wraz z nazwami domenowymi pojawiła się usługa 
+        <strong>DNS</strong>, której zadaniem jest zamiana nazw domenowych
+        na adresy <em>IP</em> i vice versa o ile jest to możliwe.
+      </p>
+      <h2 id="18.1.ntp">18.1. Network Time Protocol - synchronizacja czasu</h2>
+      <p>
+        Synchronizacja czasu za pomocą <em>NTP</em> polega na jak
+        najdokładnieszym ustawieniu czasu rzeczywistego na zegarze systemowym
+        za pomocą sieci. Czas na serwerach <em>NTP</em> nie bierze się z nikąd
+        najpopularniejszym sposób na uzyskanie dokładnego czasu są
+        <strong>zegary atomowe</strong> rozlokowane w wielu instytucjach
+        naukowych na całym świecie. Zegary te są podłączone do serwerów,
+        których adresy są dostępne na oficjalnej stronie protokołu:
+        <a href="http://ntp.org">ntp.org</a>, gdzie znajdziemy zbiory serwerów
+        nazywane <strong>pulami</strong>. Pule mogą mieć wiele różnych
+        podziałów, na przykład na poszczególne kraje, a nawet konkretne
+        dystrybucje Linuksa. W przypadku <em>RHEL</em> adres puli <em>NTP</em>
+        to: <em>rhel.pool.ntp.org</em>. W tych pulach, może znajdować się
+        wiele serwerów, które mają określone role. Wśród nich możemy wyróżnić
+        takie jak:
+      </p>
+      <ul>
+        <li><strong>Serwer podstawowy</strong> - ten rodzaj serwera otrzymuje
+          czas bezpośrednio z jego źródła czyli zegara atomowego. Serwery tego
+          typu mogą przekazywać czas do serwerów podrzędnych jaki 
+          synchronizować czas klientów.</li>
+        <li><strong>Serwer podrzędny</strong> - serwery tego typu otrzymują
+          czas od serwera podstawowego, głównie zajmują się synchonizacją
+          czasu klientów, aby zmniejszyć obciążenie serwerów podstawowych.</li>
+        <li><strong>Peer</strong> - jest rodzaj serwera który przekazuje czas
+          innym serwerom na tym samym poziomie. <em>Peer</em>-y mogą występować
+          wśród serwerów podstawowych jak podrzędnych.</li>
+        <li><strong>Klient</strong> - klient nie jest rolą serwera, a raczej
+          hostów, które korzystają z <em>NTP</em>. Klient pobiera czas z
+          jednego z serwerów z puli a następnie ustawia swój zegar na podstawie
+          uzyskanych z serwera <strong>różnic</strong>.</li>
+      </ul>
+      <p>
+        Sieć <em>NTP</em> ma hierachiczną budowę i opiera się ona o poziomy
+        nazywane <strong>Stratum</strong>. Poziomy zaczynają się od poziomu 
+        <strong>0</strong>
+        na tym poziomie znajdują się głownie zegary atomowe lub inne wzorce
+        czasu. Klient <em>NTP</em> nie może uzyskać informacji z tego poziomu.
+        Nie jest on podłączony do sieci. Drugim poziom - 
+        poziom <strong>1</strong> - jest miejscem w hierarchii, który znajdują
+        się głównie serwery podstawowe oraz <em>peer</em>-y.  Na kolejnych
+        poziomach znajdują się serwery podrzędne oraz <em>peer</em>-y tych
+        poziomów. Czas uzyskany z najwyższych poziomów można uznać za
+        najbardziej dokładny i rzetelny. Wszystkich poziomów w hierarchi jest
+        <strong>15</strong>.
+      </p>
+      <p>
+        Klient wybiera serwer na podstawie czasu oczekiwania na odpowiedź,
+        im krótszym tym czas będzie bardziej dokładny.
+      </p>
+      <h3 id="18.1.1.chronyconfig">18.1.1. Konfiguracja demona Chrony</h3>
+      <p>
+        <strong>Chrony</strong> jest najnowszą implementacją demona
+        synchronizacji czasu. Działa on na porcie 123 protokołu UDP. Jego plik
+        konfiguracjny znajduje się bezpośrednio w katalogu <em>/etc</em> pod
+        nazwą <em>chrony.conf</em>. Poniżej znajduje się jego zawartość. 
+      </p>
+<pre class="code-block">
+pool 2.rhel.pool.ntp.org iburst
+sourcedir /run/chrony-dhcp
+driftfile /var/lib/chrony/drift
+makestep 1.0 3
+rtcsync
+keyfile /etc/chrony.keys
+ntsdumpdir /var/lib/chrony
+leapsectz right/UTC
+logdir /var/log/chrony
+</pre>
+      <p>
+        Z tych przedstawionych na przykładzie na bardziej szczegółowe omówienie
+        zasługuje dyrektywa <code class="code-inline">pool</code> wskazująca na
+        adres puli, dodatkowo atrybut <code class="code-inline">iburst</code>
+        powoduje przyspieszenie uzyskania czasu z serwera <em>NTP</em>. Ma to
+        swój cel głównie podczas uruchamiania systemu. W pliku wskazywanym
+        przez dyrektywę <code class="code-inline">driftfile</code> 
+        przechowywany jest wskaźnik rozbierzności czasu zegara systemowego,
+        informacje przechowywane w tym pliku pomagają w utrzymaniu precyzji
+        zegara. Jeśli mielibyśmy wskazać konkretny serwer czasu, to wówczas
+        należało by użyć dyrektywy <em>server</em>. Dyrektywa
+        <code class="code-inline">logdir</code> przechowuje plik dziennika
+        <code class="code-inline">/var/log/chrony</code>.
+      </p>
+      <p>
+        Demon <em>chrony</em> dostarczany jest wraz z poleceniem
+        <strong>chronyc</strong> za pomocą którego możemy sprawdzić wydajność
+        demona oraz kontrolować jego działanie. Informacje o <em>NTP</em> z 
+        demona możemy uzyskać za
+        pomocą podpoleceń takich jak <em>sources</em> oraz <em>tracking</em>.
+      </p>
+      <p>
+        Aby skonfigurować <em>chrony</em> nic nie trzeba robić. Wystarczy
+        instalacja oraz włączenie jednostki. Domyślna konfiguracja świetnie
+        sprawdza się w podstawowych zastosowaniach. Konfigurację zaczniemy 
+        zatem od sprawdzenia czy demon jest zainstalowany czy nie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo dnf install chrony
+Updating Subscription Management repositories.
+Unable to read consumer identity
+
+This system is not registered with an entitlement server. You can use subscription-manager to register.
+
+Ostatnio sprawdzono ważność metadanych: 0:31:37 temu w dniu pon, 1 sie 2022, 14:03:11.
+Pakiet chrony-4.1-3.el9.x86_64 jest już zainstalowany.
+Rozwiązano zależności.
+Nie ma nic do zrobienia.
+Ukończono.
+</pre>
+      <p>
+        W przypadku Red Hat Enterprise Linux 9 jest on domyślnie zainstalowany.
+        To pozostaje tylko go włączyć.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo systemctl enable --now chronyd.service 
+Created symlink /etc/systemd/system/multi-user.target.wants/chronyd.service → /usr/lib/systemd/system/chronyd.service.
+[user@server10 ~]$ sudo systemctl status chronyd.service --no-pager
+● chronyd.service - NTP client/server
+     Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
+     Active: active (running) since Mon 2022-08-01 14:37:11 CEST; 23s ago
+       Docs: man:chronyd(8)
+             man:chrony.conf(5)
+    Process: 1968 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
+   Main PID: 1970 (chronyd)
+      Tasks: 1 (limit: 5891)
+     Memory: 824.0K
+        CPU: 18ms
+     CGroup: /system.slice/chronyd.service
+             └─1970 /usr/sbin/chronyd -F 2
+
+sie 01 14:37:11 server10.example.com systemd[1]: Starting NTP client/server...
+sie 01 14:37:11 server10.example.com chronyd[1970]: chronyd version 4.1 starting (+CMDMON +NTP +RE…EBUG)
+sie 01 14:37:11 server10.example.com chronyd[1970]: Frequency -6.706 +/- 0.264 ppm read from /var/…drift
+sie 01 14:37:11 server10.example.com chronyd[1970]: Using right/UTC timezone to obtain leap second data
+sie 01 14:37:11 server10.example.com chronyd[1970]: Loaded seccomp filter (level 2)
+sie 01 14:37:11 server10.example.com systemd[1]: Started NTP client/server.
+sie 01 14:37:16 server10.example.com chronyd[1970]: Selected source 178.215.228.24 (2.rhel.pool.ntp.org)
+sie 01 14:37:16 server10.example.com chronyd[1970]: System clock TAI offset set to 37 seconds
+Hint: Some lines were ellipsized, use -l to show in full.
+</pre>
+      <p>
+        Za pomocą polecenia <em>chronyc</em> wraz z podpoleceniem
+        <strong>sources</strong> możemy podejrzeć z jakim serwerem czasu
+        połączył się nasz klient oraz na jakim poziomie <em>hierarchi</em>
+        się one znajdują.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ chronyc sources
+MS Name/IP address         Stratum Poll Reach LastRx Last sample               
+===============================================================================
+^+ pingless.com                  2   6   377     2  -3517us[-2773us] +/-   27ms
+^+ s.complex.net.pl              2   6   377     1  -2877us[-2877us] +/-   44ms
+^* ntp.ifj.edu.pl                2   6   377     1    +10ms[  +11ms] +/-   33ms
+^+ any.time.nl                   2   6   377    66  -2061us[-1153us] +/-   62ms
+</pre>
+      <p>
+        Gwiazdka w pierwszej kolumnie wiersza oznacza, że to właśnie z tego
+        serwera został pobrany czas. Możemy się upewnić za pomocą drugiego
+        podpolecenia <strong>tracking</strong>. Aby poznać więcej informacji
+        na temat kolumn wyszukajmy sekcji <em>sources</em> na stronie
+        podręcznika polecenia <em>chronyc</em>. Wynik działania podpolecenia
+        <em>tracking</em> znajduje się poniżej:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ chronyc tracking
+Reference ID    : C0560E43 (ntp.ifj.edu.pl)
+Stratum         : 3
+Ref time (UTC)  : Mon Aug 01 12:48:05 2022
+System time     : 0.001653226 seconds slow of NTP time
+Last offset     : -0.001851230 seconds
+RMS offset      : 0.001920320 seconds
+Frequency       : 7.629 ppm slow
+Residual freq   : -0.463 ppm
+Skew            : 4.887 ppm
+Root delay      : 0.042983003 seconds
+Root dispersion : 0.008079479 seconds
+Update interval : 64.8 seconds
+Leap status     : Normal
+</pre>
+      <p>
+        Zwróćmy uwagę na rozbierzność na temat poziomów serwera. W przypadku
+        mojego serwera czas systemowy spóźnia się o wartość zapisaną w wierszu
+        <code class="code-inline">System time</code>.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Podczas egzaminu maszyny egzaminacyjne nie będą mieć dostępu do
+        internetu, więc podczas konfiguracji klienta NTP będzie trzeba 
+        wskazać na serwer w sieci egzaminacyjnej. Ujmujemy w komentarz
+        dyrektywę <em>pool</em> oraz <em>server</em> jeśli występuje,
+        następnie dopisujemy kolejną dyrektywę <em>server</em> z adresem
+        serwera NTP w sieci egzaminacyjnej. 
+      </p>
+      <h3 id="18.1.2.settingdateandtime">18.1.2. Ustawienia daty i czasu</h3>
+      <p>
+        Podczas omawiania synchronizacji czasu nie może zabraknąć ręcznych
+        ustawień. W przypadku <em>RHEL</em> można to
+        zrealizować na dwa sposóby. Pierwszym z nich jest jest polecenie
+        <strong>timedatectl</strong> oraz <strong>date</strong>. Tak prezentują
+        się informacje zwracane przez oba narzędzia uruchomione bez żadnych
+        argumentów:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ timedatectl
+               Local time: pon 2022-08-01 15:34:51 CEST
+           Universal time: pon 2022-08-01 13:34:51 UTC
+                 RTC time: pon 2022-08-01 13:34:51
+                Time zone: Europe/Warsaw (CEST, +0200)
+System clock synchronized: yes
+              NTP service: active
+          RTC in local TZ: no
+
+[user@server10 ~]$ date
+pon, 1 sie 2022, 15:34:55 CEST
+</pre>
+      <p>
+        Aby móc ustawić ręcznie datę oraz czas trzeba wyłączyć możliwość 
+        ustawienia daty oraz czasu z protokołu <em>NTP</em>. Możemy to zrobić
+        za pomocą poniższego polecenia:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo timedatectl set-ntp false
+[user@server10 ~]$ timedatectl
+               Local time: pon 2022-08-01 15:35:58 CEST
+           Universal time: pon 2022-08-01 13:35:58 UTC
+                 RTC time: pon 2022-08-01 13:35:58
+                Time zone: Europe/Warsaw (CEST, +0200)
+System clock synchronized: yes
+              NTP service: inactive
+          RTC in local TZ: no
+</pre>
+      <p>
+        Ustawienie daty oraz czasu następuje w przypadku <em>timedatectl</em>,
+        dokonujemy za pomocą podpolecenia <strong>set-time</strong> następnie
+        podajemy datę oraz godzinę.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo timedatectl set-time "1970-01-01 12:01"
+[user@server10 ~]$ timedatectl 
+               Local time: czw 1970-01-01 12:01:12 CET
+           Universal time: czw 1970-01-01 11:01:12 UTC
+                 RTC time: czw 1970-01-01 11:01:13
+                Time zone: Europe/Warsaw (CET, +0100)
+System clock synchronized: no
+              NTP service: inactive
+          RTC in local TZ: no
+</pre>
+      <p>
+        Natomiast w przypadku polecenia <em>date</em> używa się opcji
+        <strong>--set</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo date --set "1970-01-05 23:59"
+pon, 5 sty 1970, 23:59:00 CET
+[user@server10 ~]$ date
+pon, 5 sty 1970, 23:59:02 CET
+</pre>
+      <p>
+        Aby wszystko wróciło do normy, wystarczy że włączymy obsługę NTP.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo timedatectl set-ntp true
+[sudo] hasło użytkownika user: 
+[user@server10 ~]$ chronyc tracking
+Reference ID    : D4539E53 (dedibox.demongeot.biz)
+Stratum         : 3
+Ref time (UTC)  : Mon Aug 01 13:56:32 2022
+System time     : 0.000497948 seconds slow of NTP time
+Last offset     : -0.000775014 seconds
+RMS offset      : 0.000775014 seconds
+Frequency       : 6.770 ppm slow
+Residual freq   : -57.944 ppm
+Skew            : 0.724 ppm
+Root delay      : 0.065063119 seconds
+Root dispersion : 0.003521844 seconds
+Update interval : 1.5 seconds
+Leap status     : Normal
+[user@server10 ~]$ timedatectl 
+               Local time: pon 2022-08-01 15:57:19 CEST
+           Universal time: pon 2022-08-01 13:57:19 UTC
+                 RTC time: pon 2022-08-01 13:57:19
+                Time zone: Europe/Warsaw (CEST, +0200)
+System clock synchronized: yes
+              NTP service: active
+          RTC in local TZ: no
+</pre>
+      <h2 id="18.2.nameresolving">18.2. Rozwiązywanie nazw domenowych</h2>
+      <p>
+        Za rozwiązywanie nazw domenowych odpowiedzialna jest usługa
+        <strong>DNS</strong>. W tym podrozdziale przyjrzymy się tylko
+        konfiguracji klienta oraz poznamy narzędzia dzięki którym będziemy
+        mogli odpytać serwer w poszukiwaniu adresu <em>IP</em> lub nazwy
+        hosta. Na początek jednak trochę teorii.
+      </p>
+      <p>
+        Przestrzeń nazw domenowych posiada hierahiczną strukturę odwróconego
+        drzewa. Podobnie do katalogu głównego. Podbnie tutaj występuję wezeł
+        główny oznaczonony kropką (<strong>.</strong>). Kropka funkcjonuje
+        również jako separator w nazwach. Po głównym weźle, ktory jest
+        domyślny i nie trzeba do podawać występuje <strong>TLD</strong> czyli
+        domena najwyższego rzędu. Domenami najwyszego rzędu są między innymi
+        <em>.com</em>, <em>.net</em>, <em>.org</em> itd. Domeny geograficzne
+        na przykład <em>.pl</em> również są domenami najwyższego rzędu. Po nich
+        wystepują poddomeny niższego rzędu. Mogą być to domeny takie jak
+        <em>.com</em> itd. o ile w hierarchi poprzedza je na przykład domena
+        geograficzna. W poddomenach niższego rzędu występują już nazwy własne,
+        które się wydzierżawia od dostawcy usług domenowych. Taką nazwą własną
+        mozę być <em>redhat</em> lub <em>github</em>. Po nazwie własnej,
+        występuje nazwa hosta. Ma to miejsce w 80% przypadków, reszta to sieci
+        korporacyjne gdzie między nazwą hosta, a nazwą własną domeny możemy
+        występować jeszcze duża ilość poddomen. Weźmy dla przykładu nazwe
+        domenową tej strony. Jeśli zapiszemy ją zgodnie z hierarchią to będzie
+        wyglądać jak na przykładzie ponizej.
+      </p>
+<pre class="code-block">
+.-↓
+  io.↓
+     github.↓
+            morketsmerke
+.io.github.morketsmerke
+</pre>
+      <p>
+        W taki sposób są rozwiązywane nazwy domenowe na adresy <em>IP</em>
+        przyczym najczęsiej w początkowej fazie, kroka oznaczająca główny
+        węzeł zostaje pominięta, następnie szuka się serwera nazwy 
+        obsługującego <code class="code-inline">github.io</code>. Następnie 
+        otrzymuje się adres, który z hostów w sieci <em>github</em> to
+        <em>morketsmerke</em> (oczywiście w dużym skrócie). Ludzie za to 
+        wpisują adresy do aplikacji w
+        sposób odwrotny do hierarchi: <em>morketsmerke.github.io</em>. I w
+        momencie gdy takie zapytanie trafi do serwera system <em>DNS</em> 
+        zacznie
+        wysłać zapytania do innych serwerów odpowiedzialnych za utrzymanie 
+        poszczególnych części nazwy.
+      </p>
+      <p>
+        Serwery <em>DNS</em> zajmują się utrzymaniem bazy mapowań adresów 
+        domenowych na adresy <em>IP</em>, odpowiadaniem na zapytania klientów
+        oraz synchronizacją tych baz z innymi serwerami. Wpis bazie danych
+        <em>DNS</em> nazywany jest <strong>rekordem</strong>. Serwery
+        <em>DNS</em> dzieli się na <strong>serwery główne</strong> oraz
+        <strong>podrzędne</strong>. Serwery podrzędne wykorzystuje się głównie
+        do równoważenia obciążenia oraz nadmiarowości, ponieważ bazy są
+        przesyłane na serwery podrzędne za każdą aktulizacją wprowadzą w 
+        konfiguracji domeny. 
+      </p>
+      <h3 id="18.2.1.resolv.conf">18.2.1. Plik /etc/resolv.conf</h3>
+      <p>
+        Za pomocą pliku <em>/etc/resolv.conf</em>, narzędzia odpowiedzialne
+        za rozwiązywanie nazw wiedzą w jaki sposób mają tworzyć zapytania oraz
+        gdzie przesyłać je dalej (na przykład, gdy korzystamy z aliasu 
+        zapisanego w pliku <em>/etc/hosts</em>). Plik można edytować jak każdy 
+        inny plik tekstowy. Zazwyczaj zawiera on do trzech dyrektyw. Zawartość 
+        pliku z jednej z moich maszyny prezentuje się na poniższym przykładzie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /etc/resolv.conf 
+# Generated by NetworkManager
+search example.com
+nameserver 192.168.122.1
+</pre>
+      <p>
+        Dyrektywa <code class="code-inline">search</code> zawiera sufiks z
+        nazwą domeny, jest on dodawany do każdej zapisanej nazwy hosta
+        pod czas tworzenia zapytania <em>DNS</em>. W tej dyrektywie może być
+        ich maksymalnie 6, przyczym warto pamiętać o tym aby na początku
+        zawsze znajdowała się domena lokalna. Kolejną dyrektywą jest
+        <code class="code-inline">nameserver</code> zawierająca adresy
+        <em>IP</em> odpytywanych po kolei serwerów <em>DNS</em>. W tej
+        dyrektywie mogą znaleźć się maksymalnie 3 adresy, będą one odpytywane
+        w takiej samej kolejności jak zostały zapisane. Ostatnia dyrektywą
+        jest dyrektywa <em>domain</em>, jednak nie jest ona stosowana jeśli
+        w pliku jest zapisana dyrektywa <code class="code-inline">search</code>.
+      </p>
+      <h3 id="18.2.2.nsswitch.conf">18.2.2. Plik /etc/nsswitch.conf</h3>
+      <p>
+        Inny plikiem wpływającym na działanie rozwiązywania nazw systemach
+        Uniksowych jest <em>/etc/nsswitch.conf</em>. Jego zadaniem jest
+        wybranie odpowiedniego źródła dla żądanych informacji i w tym przypadku
+        nie chodzi tylko o nazwy domenowe. Każdy wpis składa się ze wskazania
+        bazy danych. W przypadku nazw domenowych jest <em>hosts</em>.
+        Następnie wskazywane są źródła. Poniżej znajduje się przykładowy
+        wpis:
+      </p>
+<pre class="code-block">
+hosts:      files dns myhostname
+</pre>
+      <p>
+        Gdzie <code class="code-inline">files</code> jest w tym przypadku
+        plikiem <em>/etc/hosts</em>; <code class="code-inline">dns</code> jest
+        odpytaniem serwerów zapisanych w <em>/etc/resolv.conf</em>.
+      </p>
+      <p>
+        Jeśli program podczas rozwiązywania nazwy nie znajdzie jej w pliku, 
+        przechodzi do kolejego
+        źródła. Plik <em>/etc/nsswitch.conf</em> za pomocą słów kluczowych
+        pozwala na określenie akcji jeśli uzyskano dane lub nie z zapisanych
+        źródeł. Poniżej znajduje się lista słów kluczowych.
+      </p>
+      <ul>
+        <li><strong>success</strong> - Informacje znalezione w źródle.
+          Dostarczone do aplikacji, która ich żądała. Domyślna akcja:
+          <strong>return</strong> (nie szukaj w innych źródłach).</li>
+        <li><strong>notfound</strong> - Nie znalaleziono informacji w źródle.
+          Domyślna akcja: <strong>continue</strong> (szukaj w innym źródle)</li>
+        <li><strong>unavail</strong> - Źródło jest wyłączone, bądź nie 
+          odpowiada. Usługą może być wyłączona lub nie skonfigurowana.
+          Domyślna akcja: <strong>continue</strong> (szukaj w innym źródle)</li>
+        <li><strong>tryagain</strong> - Źródło jest zajęte, spróbuj poźniej.
+          Domyślna akcja: <strong>continue</strong> (szukaj w innym źródle)</li>
+      </ul>
+      <p>
+        Dzięki tym słowom kluczowym, jeśli np. nazwa hosta nie zostanie 
+        odnaleziona w pliku <em>/etc/resolv.conf</em> można przerwać dalsze
+        poszukiwania.
+      </p>
+<pre class="code-block">
+hosts:      files [notfound=return] dns myhostname
+</pre>
+      <h3 id="18.2.3.dnstools">18.2.3. Narzędzia do rozwiązywania nazw domenowych</h3>
+      <p>
+        Czasem może zdarzyć się potrzeba przetestowania rozwiązywania nazw
+        w systemie i do tego mogą posłużyć nam dostępne w systemie narzędzia.
+        Jest ich kilka.        
+      </p>
+      <p>
+        Pierwszym z nich jest <strong>dig</strong>. Bardzo elastyczne i
+        użyteczne narzędzie. Możemy wykorzystać je do wielu czynności. Plusem
+        tego narzędzia jest domyślna ilość zwracanych informacji. Poniżej
+        znajduje się rozwiązanie nazwy <em>redhat.com</em> za pomocą tego
+        narzędzia.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ dig redhat.com
+
+; &lt;&lt;&gt;&gt; DiG 9.16.23-RH &lt;&lt;&gt;&gt; redhat.com
+;; global options: +cmd
+;; Got answer:
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 20452
+;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags:; udp: 512
+;; QUESTION SECTION:
+;redhat.com.                   IN      A
+
+;; ANSWER SECTION:
+redhat.com.            312     IN      A       52.200.142.250
+redhat.com.            312     IN      A       34.235.198.240
+
+;; Query time: 56 msec
+;; SERVER: 192.168.122.1#53(192.168.122.1)
+;; WHEN: Mon Aug 01 17:50:49 CEST 2022
+;; MSG SIZE  rcvd: 71
+</pre>
+      <p>
+        Na samym dole mamy podsumowanie, w którym znajdują się informacje o
+        tym jak długo trwało zapytanie, czy adres odpytywanego serwera.
+        Polecenie to również możemy odpytać podając adres <em>IP</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ dig -x 52.200.142.250
+
+; &lt;&lt;&gt;&gt; DiG 9.16.23-RH &lt;&lt;&gt;&gt; -x 52.200.142.250
+;; global options: +cmd
+;; Got answer:
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 14382
+;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags:; udp: 512
+;; QUESTION SECTION:
+;250.142.200.52.in-addr.arpa.  IN      PTR
+
+;; ANSWER SECTION:
+250.142.200.52.in-addr.arpa. 300 IN    PTR     ec2-52-200-142-250.compute-1.amazonaws.com.
+
+;; Query time: 88 msec
+;; SERVER: 192.168.122.1#53(192.168.122.1)
+;; WHEN: Mon Aug 01 17:55:58 CEST 2022
+;; MSG SIZE  rcvd: 112
+</pre>
+      <p>
+        Użycie opcji <code class="code-inline">-x</code> pozwala na podanie
+        adresu <em>IP</em>.
+      </p>
+      <p>
+        Kolejny narzędziem jest polecenie <strong>host</strong>. Jak argument
+        przyjmuje nazwę domenową i zwraca adres <em>IP</em> serwera oraz
+        pozostałe wpisy w bazie <em>DNS</em> powiązane z tą nazwą. Poniżej
+        znajduje się przykład.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ host redhat.com
+redhat.com has address 34.235.198.240
+redhat.com has address 52.200.142.250
+redhat.com mail is handled by 10 us-smtp-inbound-2.mimecast.com.
+redhat.com mail is handled by 10 us-smtp-inbound-1.mimecast.com.
+</pre>
+      <p>
+        Za pomocą polecenia <em>host</em> możemy uzyskać podobne wyjście jak
+        w przypadku polecenia <em>dig</em>. Służy do tego opcja
+        <strong>-v</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ host -v redhat.com
+Trying "redhat.com"
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 5646
+;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;redhat.com.                   IN      A
+
+;; ANSWER SECTION:
+redhat.com.            247     IN      A       52.200.142.250
+redhat.com.            247     IN      A       34.235.198.240
+
+Received 60 bytes from 192.168.122.1#53 in 4 ms
+Trying "redhat.com"
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 13010
+;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;redhat.com.                   IN      AAAA
+
+;; AUTHORITY SECTION:
+redhat.com.            1037    IN      SOA     a1-68.akam.net. noc.redhat.com. 2022080000 300 180 604800 14400
+
+Received 82 bytes from 192.168.122.1#53 in 51 ms
+Trying "redhat.com"
+;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 56767
+;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;redhat.com.                   IN      MX
+
+;; ANSWER SECTION:
+redhat.com.            314     IN      MX      10 us-smtp-inbound-1.mimecast.com.
+redhat.com.            314     IN      MX      10 us-smtp-inbound-2.mimecast.com.
+
+Received 105 bytes from 192.168.122.1#53 in 50 ms
+</pre>
+      <p>
+        Kolejnym poleceniem jest <strong>nslookup</strong>. Polecenie to jest
+        interaktywne. Pozwala ono na zmianę serwera w bardzo prosty sposób,
+        ponieważ jego adres możemy podać jako argument polecenia lub już
+        po jego uruchomieniu po poleceniu <em>server</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ nslookup
+&gt; server 8.8.8.8 
+Default server: 8.8.8.8
+Address: 8.8.8.8#53
+&gt; redhat.com
+Server:                8.8.8.8
+Address:       8.8.8.8#53
+
+Non-authoritative answer:
+Name:  redhat.com
+Address: 52.200.142.250
+Name:  redhat.com
+Address: 34.235.198.240
+&gt; exit
+</pre>
+      <p>
+        W wyniku polecenia pojawił się taki zapis jak
+        <code class="code-inline">Non-authoritative answer</code>. Oznacza to, 
+        że rozwiązanie nazwy otrzymano od serwera, który nie zarządza tą
+        domeną. Polecenie opuszczamy tylko za pomocą polecenia
+        <code class="code-inline">exit</code>.
+      </p>
+      <p>
+        Ostatnim poleceniem jest <strong>getent</strong>. Polecenie to jest
+        związane z plikiem <em>/etc/nsswitch.conf</em>, dlatego aby uzyskać
+        za jego pomocą adres <em>IP</em> jednej z nazw należy podać jako
+        pierwszy argument bazę danych z jakiej będziemy korzystać.
+        Przypominam, że jest to <em>hosts</em>. Poniżej znajduje się przykład
+        użycia tego polecenia.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ getent hosts redhat.com
+34.235.198.240  redhat.com
+52.200.142.250  redhat.com
+</pre>
+      <h3 id="exec18.1">Ćwiczenie 1: Zmiana daty i czasu</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jak <em>server10</em>, wyświetl obecną datę i godzine za
+        pomocą obu poznanych narzędzi. Za pomocą polecenia <em>timedatectl</em>
+        zmień datę i godzine na dowolną w przyszłość. Za pomocą polecenia
+        <em>date</em> zwiększ godzinę o jedną naprzód. Ponownie wyświetl
+        datę i godzinę za pomocą obu narzędzi. Przyróć datę i godzinę do
+        rzeczywistych wartości.
+      </p>
+      <h3 id="exec18.2">Ćwiczenie 2: Konfiguracja Chrony</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jak <em>server10</em>. Jeśli jest taka potrzeba 
+        zainstaluj <em>Chrony</em>. W pliku konfiguracyjny wyłącz wszystkie
+        dyrektywy (ujmij w komentarz) <em>pool</em> oraz <em>server</em>. 
+        Dodaj nową dyrektywę na <em>server</em> z adresem <em>127.127.1.0</em>.
+        Włącz/zrestartuj usługę. Potwierdź wykonanie zadania za pomocą 
+        wyświetlania źródeł <em>Chrony</em> - polecenie
+        <em>chronyc sources</em>.
+      </p>
+      <h2 id="ch18summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale poznaliśmy sposóby na efektywną i automatyczną
+        synchronizację czasu zegara systemowego. Za poznaliśmy się z
+        najnowszą implementacją protokołu <em>NTP</em> jaką definitywnie jest
+        <em>Chrony</em> poznaliśmy jego konfigurację oraz polecenia służące
+        zarządzania nim. Poza tym poznaliśmy w jaki sposób uzyskiwane są adresy
+        <em>IP</em> w systemie, czym jest <em>DNS</em>, pliki 
+        <em>/etc/resolv.conf</em> czy <em>/etc/nsswitch.conf</em>. Poznaliśmy
+        również kilka narzędzi, dzięki którym możemy przeprowadzić diagnostykę
+        rozwiązywania nazw na naszych systemach. W następnym rozdziale
+        zajmiemy się obsługą bezpiecznego zdalnego logowania do powłoki -
+        usługą <em>SSH</em>.
+      </p>
+      <h1 id="19.ssh">19. Usługa bezpiecznej powłoki</h1>
+      <p>
+        Usługa bezpiecznej powłoki, jest w obecnych czasach jedną z 
+        podstawowych
+        rzeczy bez których nie wyobrażamy sobie pracy z jakimi kolwiek
+        odległymi maszynami. <strong>SSH</strong>
+        pozwala na bezpieczne zarządzania maszynami oraz przesyłanie informacji
+        między nimi przez niezabezpieczone sieci takie jak internet. 
+        <em>SSH</em> pozwala na uwierzytelnienie użytkownika na zdalnym
+        serwerze. Dba ona również o intergralność danych przesyłanych jej
+        kanałami. Ta usługa dostarcza do systemów Uniksowych wielu narzędzi,
+        które wyparły odpowiedniki korzystające ze zwykłych nieszyfrowanych
+        kanałów.
+      </p>
+      <h2 id="19.1.sshtheory">19.1. Podstawy teoretyczne na temat SSH</h2>
+      <p>
+        W wielu Uniksach (w tym i dystrybucjach Linuksa) stosowana jest
+        darmowa oraz wolna implementacja protokołu <em>SSH</em> - 
+        <strong>OpenSSH</strong>, jest ona odpowiednikiem własnościowej wersji.
+        Obecnie najczęściej stoswany jest protokół <em>SSH</em> w wersji 2.
+      </p>
+      <h3 id="19.1.1.sshcryptography">19.1.1. Kryptografia SSH</h3>
+      <p>
+        OpenSSH do zabezpiecznia transmisji danych wykorzystuje metody
+        kryptograficzne zwane <strong>algorytmami</strong>.
+        Są to serie
+        rownań matematycznych mających za zadanie jak najbardziej zamaskować
+        jawne dane aby nie mogły być one odczytane przez osoby nie znające
+        <strong>klucza</strong>, czyli hasła bądź pliku, który za pomocą
+        tych samych algorytmów pozwoli na odczytanie danych przeznaczonych dla
+        ich odbiorców. Wśród metod szyfrowania możemy wymienić:
+      </p>
+      <ul>
+        <li><strong>Algorytmy symetryczne</strong> - w których do szyfrowania
+          i odszyfrowyania danych używa się tego samego klucza ustalanego
+          podczas pierwszego połączenia między stronami transmisji.</li>
+        <li><strong>Algorytmów asymetrycznych</strong> - metody te są nazwane
+          również <strong>algorytmami klucza publicznego</strong>. Każdy z
+          hostów generuje klucz prywatny. Następnie na
+          podstawie tego klucza generowany jest klucz publiczny, który może być
+          jawnie przesyłany przez internet, ponieważ służy on do identyfikacji
+          użytkownika oraz szyfrowania danych. Hosty przesyłają sobie klucze
+          publiczne i rozpoczyna się wymiana danych znanych tylko im. Dane w
+          przypadku tego typu
+          algorytmów mogą być odczytane tylko za pomocą klucza prywatnego.
+          Algorytmy asymetryczne są wykorzystywane do zabezpieczania
+          transmisji oraz uwierzytelniania użytkowników.</li>
+      </ul>
+      <p>
+        <em>OpenSSH</em> wykorzystuje głównie algorytm <strong>RSA</strong>, 
+        ponieważ może za jego pomocą szyfrować dane oraz uwierzytelniać 
+        użytkownika. Do uwierzytleniania możemy wykorzystać takie algorytmy
+        jak <em>DSA</em> oraz <em>ECDSA</em> jednak służą one tylko temu
+        celowi.
+      </p>
+      <h3 id="19.1.2.sshauthmethod">19.1.2. Metody uwierzytelniania OpenSSH</h3>
+      <p>
+        Aby użytkownik mógł pracować na zdalnym serwerze za pomocą
+        <em>SSH</em> musi się uwierzytelnić. Uwierzytelnienia możemy dokonać
+        na kilka różnych sposobów, a wsród nich możemy wyróżnić oparte na:
+      </p>
+      <ul>
+        <li><strong>GSSAPI</strong></li>
+        <li><strong>Hoście</strong></li>
+        <li><strong>Kluczu publicznym</strong></li>
+        <li><strong>Haśle</strong></li>
+        <li><strong>metodzie Challenge-response</strong></li>
+      </ul>
+      <p>
+        W tym materiale jednak skupimy się wyłącznie na domyślnej metodzie jaką
+        jest hasło oraz klucz publiczny.
+      </p>
+      <h3 id="19.1.3.sshprograms">19.1.3. Oprogramowanie OpenSSH</h3>
+      <p>
+        W <em>RHEL</em> usługa <em>SSH</em> w implementacji <em>OpenSSH</em>
+        jest podzielona na trzy pakiety: <strong>openssh</strong> -
+        dostarczający niezbędne biblioteki oraz polecenie 
+        <strong>ssh-keygen</strong>; <strong>openssh-client</strong> -
+        dostarczający takie polecenia jak: <strong>ssh</strong>,
+        <strong>scp</strong> czy <strong>sftp</strong>. Ostatnim pakietem jest
+        <strong>openssh-server</strong> dostarczający demona 
+        <strong>sshd</strong>.
+      </p>
+      <p>
+        Polecenie <em>ssh</em> zastępuje stare polecenia <em>telnet</em> czy
+        <em>rlogin</em>. Z poleceniem <em>telnet</em> możemy się jeszcze
+        kiedyś spotkać. Polecenia <em>scp</em> i <em>sftp</em> zastępują 
+        kolejno <em>rcp</em>
+        oraz <em>ftp</em>. Mimo to <em>ftp</em> jest dalej stosowany, aby
+        umożliwić publiczny dostęp na przykład do repozytoriów oprogramowania.
+      </p>
+      <h2 id="19.2.sshd">19.2. Serwer OpenSSH - sshd</h2>
+      <p>
+        Serwerem <em>OpenSSH</em> jest program <em>sshd</em>. Jego konfiguracja
+        znajduje się w pliku <em>/etc/ssh/sshd_config</em>. Poniżej znajduje
+        się jej fragment:
+      </p>
+<pre class="code-block">
+#Port 22
+#AddressFamily any
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_ecdsa_key
+#HostKey /etc/ssh/ssh_host_ed25519_key
+# Ciphers and keying
+#RekeyLimit default none
+# Logging
+#SyslogFacility AUTH
+#LogLevel INFO
+# Authentication:
+#LoginGraceTime 2m
+#PermitRootLogin prohibit-password
+#StrictModes yes
+#MaxAuthTries 6
+#MaxSessions 10
+#PubkeyAuthentication yes
+# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
+# but this is overridden so installations will only check .ssh/authorized_keys
+AuthorizedKeysFile     .ssh/authorized_keys
+...
+</pre>
+      <p>
+        Zwróćmy uwagę na to, że prawie wszystkie dyrektywy są ujęte w komentarz
+        po za jedną, która wskazuje gdzie należy złożyć wszystkie otrzymane
+        klucz publiczne w celach uwierzytelniania. Demon <em>OpenSSH</em> jest
+        domyślnie dostoswany do największej ilości przypadków jego użycia,
+        więc zmian w plikach konfiguracyjnych najczęściej dokonuje się w 
+        specyficznych przypadkach.
+      </p>
+      <p>
+        Nazwa jednostki w <em>RHEL</em> nosi nazwę <em>sshd.service</em>.
+        Każdą zmianę w tym pliku należy potwierdzić restartując demona. Opisy
+        tych dyrektyw znajdują się na stronie podręcznika.
+      </p>
+      <h2 id="19.3.sshclientconfig">19.3. Konfiguracja klienta - ssh</h2>
+      <p>
+        Na każdej maszynie, na której znajduje się polecenie <em>ssh</em>
+        znajduje się także
+        plik konfiguracyjny <em>/etc/ssh/ssh_config</em>, który reguluje jego
+        zachowanie. Posiada on też kilka dyrektyw sugerujących pewne domyślne
+        ustawienia. Poniżej znajduje się jego fragment pobrany z jednej z
+        moich maszyn.
+      </p>
+<pre class="code-block">
+# Host *
+#   ForwardAgent no
+#   ForwardX11 no
+#   PasswordAuthentication yes
+#   HostbasedAuthentication no
+#   GSSAPIAuthentication no
+#   GSSAPIDelegateCredentials no
+#   GSSAPIKeyExchange no
+#   GSSAPITrustDNS no
+#   BatchMode no
+#   CheckHostIP yes
+#   AddressFamily any
+#   ConnectTimeout 0
+#   StrictHostKeyChecking ask
+#   IdentityFile ~/.ssh/id_rsa
+#   IdentityFile ~/.ssh/id_dsa
+#   IdentityFile ~/.ssh/id_ecdsa
+#   IdentityFile ~/.ssh/id_ed25519
+#   Port 22
+...
+</pre>
+      <p>
+        Konfiguracja klienta została ujęta w ten sam sposób jak w przypadku
+        serwera. Konfiguracja klienta również jest przygotowana do użycia we
+        większości przypadków, dlatego też zmiany w konfiguracją będą wymagane
+        tylko w specyficznych przypadkach.
+      </p>
+      <h2 id="19.4.sshusage">19.4. Obsługa połączeń zdalnych - programy OpenSSH</h2>
+      <p>
+        Na początku tego rozdziału wspomnieliśmy o ilości programów
+        dostarczanych wraz z pakietem <em>OpenSSH</em>. Teraz sobie je
+        przetestujemy. Ten podrozdział został również rozszerzony o jeden
+        program, który korzysta z <em>SSH</em> do przesyłania danych.
+      </p>
+      <h3 id="19.4.1.ssh">19.4. Połączenie ze zdalnym serwerem z pomocą ssh</h3>
+      <p>
+        Połączenie ze zdalnym serwerem wymaga wydania pojedynczego polecenia,
+        w którym podajemy adres serwera, wówczas polecenie spróbuje zalogować 
+        na użytkownika z tą samą nazwą z jakiej korzystamy w lokalnym systemie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh server20
+The authenticity of host 'server20 (192.168.122.7)' can't be established.
+ED25519 key fingerprint is SHA256:ZWgY+ro8oMwFh7vq56bS/Zk9CGpUe2sCrmxaukixr8M.
+This key is not known by any other names
+Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
+Warning: Permanently added 'server20' (ED25519) to the list of known hosts.
+user@server20's password: 
+Activate the web console with: systemctl enable --now cockpit.socket
+
+Register this system with Red Hat Insights: insights-client --register
+Create an account or view all your systems at https://red.ht/insights-dashboard
+Last login: Wed Aug  3 10:59:57 2022 from 192.168.122.6
+[user@server20 ~]$ 
+</pre>
+      <p>
+        Po wydaniu polecenia nastepuje połączenie. Klient nie może zweryfikować
+        autentyczności serwera przedstawiającego się podanym
+        <strong>odciskiem klucza</strong>. Tak dzieje się gdy łączymy się
+        z serwerem po raz pierwszy. Polecenie zapyta nas czy chcemy kontynuować
+        połączenie, wybierając <code class="code-inline">Yes</code> odcisk
+        klucza wraz z adresem serwera zostanie złożony w pliku
+        <em>~/.ssh/known_hosts</em>. Następnie zostaniemy zapytani o hasło.
+        Po jego podaniu jesteśmy podłączeni do serwera.
+      </p>
+      <p>
+        Chcąc podać innego użytkownika podczas połączenia <em>SSH</em> możemy
+        to zrobić na dwa sposób. Na przykład:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh -l user server20
+#lub:
+[user@server10 ~]$ ssh user@server20
+</pre>
+      <h3 id="19.4.2.sshpubkeys">19.4.2. Generowanie, dystrybucja oraz logowanie się za pomocą klucza publicznego</h3>
+      <p>
+        Inną metodą uwierzytelniania stosowaną obok haseł jest uwierzytelnianie
+        za pomocą klucza publicznego. Ma ono klika zalet, otóż możemy logować
+        się bez podawania hasła, wówczas musimy pamiętać aby zabezpieczyć w
+        inny sposób plik klucza. Możemy również nadać jedno hasło -
+        <strong>hasło klucza</strong> i używać jednego hasła do wielu serwerów.
+        W tym materiale zajmiemy się wyłącznie kluczami bez haseł.
+      </p>
+      <p>
+        Na początek zajmiemy się wygenerowaniem klucza. Dokonujemy tego za
+        pomocą polecenia <strong>ssh-keygen</strong> podając kolejno opcję
+        <strong>-N</strong>, przyczym należy pamiętać, że aby nadać puste
+        hasło należy podać puste podwójne apostrofy (<strong>""</strong>) jako
+        wartość tej opcji. Do generowania kluczy użyjemy także opcji
+        <em>-q</em>, która powoduje nie wyświetlanie komunikatów podczas
+        generowania klucza.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh-keygen -N "" -q
+Enter file in which to save the key (/home/user/.ssh/id_rsa): 
+</pre>
+      <p>
+        Polecenie zapyta o ścieżkę oraz nazwę pliku klucza. Tę wartość
+        pozostawiam domyślnie.
+      </p>
+      <p>
+        Następnym etapem będzie przesłanie oraz instalacja klucza na zdalnym
+        serwerze. Wykonamy tę czynność przy użyciu polecenia
+        <strong>ssh-copy-id</strong>, przyjmuje ono takie same argumenty jak
+        polecenie <em>ssh</em>, zatem aby zainstalować klucz na serwerze
+        należy wydać poniższe polecenie. Polecenie to w ramach potwierdzenia
+        naszej tożsamości zażąda hasła do połączenia się ze zdalnym
+        użytkownikiem na serwerze.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh-copy-id user@server20
+/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_rsa.pub"
+/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
+/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
+user@server20's password: 
+
+Number of key(s) added: 1
+
+Now try logging into the machine, with:   "ssh 'user@server20'"
+and check to make sure that only the key(s) you wanted were added.
+</pre>
+      <p>
+        Teraz kiedy klucz jest zainstalowany możemy bez przeszkód logować się
+        na serwer. 
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh user@server20
+Activate the web console with: systemctl enable --now cockpit.socket
+
+Register this system with Red Hat Insights: insights-client --register
+Create an account or view all your systems at https://red.ht/insights-dashboard
+Last login: Wed Aug  3 11:39:18 2022 from 192.168.122.6
+[user@server20 ~]$ 
+</pre>
+      <h3 id="19.4.3.sshexecutioncommand">19.4.3. Wykonywanie pojedyńczych poleceń na zdalnym serwerze</h3>
+      <p>
+        Za pomocą <em>SSH</em> możemy również wykonywać zdalnie pojedyncze
+        polecenia, jeśli nie potrzebujemy dla jednej informacji zestawiać
+        interaktywnej powłoki. Polecenie do wykonania na zdalnym serwerze
+        podajemy po adresie serwera.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ssh user@server20 "whoami; hostname; pwd"
+user
+server20.example.com
+/home/user
+</pre>
+      <p>
+        Najlepiej, jeśli ujmiemy polecenie w podwójne apostrofy. Wówczas mamy
+        pewność, że zostanie ono w pełni przekazane do zdalnego systemu.
+      </p>
+      <h3 id="19.4.4.scp">19.4.4. Bezpieczne kopiowanie plików</h3>
+      <p>
+        Za pomocą polecenia <strong>scp</strong>, możemy kopiować pliki z
+        wykorzystaniem protokołu <em>SSH</em> w obu kierunkach. Tutaj dodatkową
+        rolę odgrywa zainstalowanie klucza bez hasła. Jeśli to zrobimy
+        wówczas będziemy mogli rozwiajać scieżki ze zdalnego systemu za pomocą
+        klawisza <em>Tab</em>. Na poniższym przykładzie skopiuje plik
+        <em>/etc/chrony.conf</em> do katalogu <em>/tmp</em>. 
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ scp server20:/etc/chrony.conf /tmp
+chrony.conf                                   100% 1369     1.5MB/s   00:00    
+[user@server10 ~]$ ls -l /tmp/chrony.conf 
+-rw-r--r--. 1 user user 1369 08-03 11:58 /tmp/chrony.conf
+</pre>
+      <p>
+        Za pomocą opcji <em>-r</em> jesteśmy w stanie skopiować do całe
+        katalogi.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ scp -r /home/user server20:/tmp/test/
+.bash_logout                                  100%   18    40.4KB/s   00:00    
+.bash_profile                                 100%  141   386.3KB/s   00:00    
+.bashrc                                       100%  492     1.2MB/s   00:00    
+.bash_history                                 100% 9742    17.0MB/s   00:00    
+.lesshst                                      100%   93   182.5KB/s   00:00    
+known_hosts                                   100%  822     1.6MB/s   00:00    
+known_hosts.old                               100%   90   154.6KB/s   00:00    
+id_rsa                                        100% 2610     6.2MB/s   00:00    
+id_rsa.pub                                    100%  579     1.4MB/s   00:00    
+gzip                                          100%   94KB  37.9MB/s   00:00    
+.viminfo                                      100%   10KB  13.7MB/s   00:00    
+
+[user@server10 ~]$ ssh user@server20 "ls -al /tmp/test/user"
+razem 136
+drwx------. 3 user user   139 08-03 12:00 .
+drwxrwxr-x. 3 user user    18 08-03 12:00 ..
+-rw-------. 1 user user  9742 08-03 12:00 .bash_history
+-rw-r--r--. 1 user user    18 08-03 12:00 .bash_logout
+-rw-r--r--. 1 user user   141 08-03 12:00 .bash_profile
+-rw-r--r--. 1 user user   492 08-03 12:00 .bashrc
+-rwxr-xr-x. 1 user user 95872 08-03 12:00 gzip
+-rw-------. 1 user user    93 08-03 12:00 .lesshst
+drwx------. 2 user user    80 08-03 12:00 .ssh
+-rw-------. 1 user user 10036 08-03 12:00 .viminfo
+</pre>
+      <h3 id="19.4.5.sftp">19.4.5. Przesyłanie plików za pomocą polecenia sftp</h3>
+      <p>
+        Polecenie <strong>sftp</strong> działa na takiej samej zasadzie co
+        polecenie <em>ftp</em>, jednak wykorzystuje do tego protokół
+        <em>SSH</em> przy tym rozszerzając oraz usprawniając działanie
+        przesyłania plików.  
+      </p>
+      <p>
+        Polecenie to przyjmuje takie same argumenty jak <em>ssh</em>. Przy
+        czym jest ono interaktywne, jak klasyczne <em>ftp</em> za
+        pomocą znaku zapytania (<strong>?</strong>) możemy wyświetlić listę
+        dostępnych poleceń. 
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sftp user@server20
+Connected to server20.
+sftp&gt; ?
+Available commands:
+bye                                Quit sftp
+cd path                            Change remote directory to 'path'
+chgrp [-h] grp path                Change group of file 'path' to 'grp'
+chmod [-h] mode path               Change permissions of file 'path' to 'mode'
+chown [-h] own path                Change owner of file 'path' to 'own'
+df [-hi] [path]                    Display statistics for current directory or
+                                   filesystem containing 'path'
+exit                               Quit sftp
+get [-afpR] remote [local]         Download file
+help                               Display this help text
+lcd path                           Change local directory to 'path'
+lls [ls-options [path]]            Display local directory listing
+lmkdir path                        Create local directory
+ln [-s] oldpath newpath            Link remote file (-s for symlink)
+lpwd                               Print local working directory
+ls [-1afhlnrSt] [path]             Display remote directory listing
+lumask umask                       Set local umask to 'umask'
+mkdir path                         Create remote directory
+progress                           Toggle display of progress meter
+put [-afpR] local [remote]         Upload file
+pwd                                Display remote working directory
+quit                               Quit sftp
+reget [-fpR] remote [local]        Resume download file
+rename oldpath newpath             Rename remote file
+reput [-fpR] local [remote]        Resume upload file
+rm path                            Delete remote file
+rmdir path                         Remove remote directory
+symlink oldpath newpath            Symlink remote file
+version                            Show SFTP version
+!command                           Execute 'command' in local shell
+!                                  Escape to local shell
+?                                  Synonym for help
+</pre>
+      <p>
+        Zwróćmy uwagę to, iż wiele poleceń występuję podwójnie, i są one 
+        poprzedzonych
+        literą <em>l</em>. Aby lepiej zarządzać transferem plików posiadmy
+        polecenia, które odwołują się czynności wykonywanych na lokalnym
+        hoście, dzięki czemu nie musimy się rozłączać aby na przykład stworzyć 
+        katalog
+        specjalnie na dane pobrane z serwera. Pobierzemy teraz plik
+        <em>/etc/fstab</em> do katalogu <em>/tmp</em>.
+      </p>
+<pre class="code-block">
+sftp&gt; lcd /tmp
+sftp&gt;  get /etc/fstab 
+Fetching /etc/fstab to fstab
+fstab                                        100%  608   709.3KB/s   00:00    
+</pre>
+      <p>
+        Za pomocą opcji <em>-r</em> takich poleceń <em>get</em> lub <em>put</em>
+        możemy pobierać oraz przesyłać całe sturktury katalogów:
+      </p>
+<pre class="code-block">
+sftp&gt; cd /tmp/dir_user/
+sftp&gt; put -r /tmp/user/.??*
+Uploading /tmp/user/.bash_history to /tmp/dir_user/.bash_history
+.bash_history                                100% 9742    13.7MB/s   00:00    
+Uploading /tmp/user/.bash_logout to /tmp/dir_user/.bash_logout
+.bash_logout                                 100%   18    54.6KB/s   00:00    
+Uploading /tmp/user/.bash_profile to /tmp/dir_user/.bash_profile
+.bash_profile                                100%  141   443.4KB/s   00:00    
+Uploading /tmp/user/.bashrc to /tmp/dir_user/.bashrc
+.bashrc                                      100%  492     1.7MB/s   00:00    
+Uploading /tmp/user/.lesshst to /tmp/dir_user/.lesshst
+.lesshst                                     100%   93   325.6KB/s   00:00    
+Uploading /tmp/user/.ssh/ to /tmp/dir_user/.ssh
+Entering /tmp/user/.ssh/
+known_hosts                                  100%  822     3.3MB/s   00:00    
+known_hosts.old                              100%   90   351.5KB/s   00:00    
+id_rsa                                       100% 2610     8.2MB/s   00:00    
+id_rsa.pub                                   100%  579     1.9MB/s   00:00    
+Uploading /tmp/user/.viminfo to /tmp/dir_user/.viminfo
+.viminfo                                     100%   10KB  23.3MB/s   00:00    
+</pre>
+      <p>
+        Jak możemy zauważyć na powyższym przykładzie w <em>sftp</em> możemy
+        używać nazw wieloznacznych.
+      </p>
+      <h3 id="19.4.6.rsync">19.4.6. Synchronizacja danych ze zdalnym serwerem</h3>
+      <p>
+        Jednym z programów wykorzystujących protokół <em>SSH</em> jest 
+        <strong>rsync</strong>, służy on do synchronizacji plików. Taka
+        synchronizacja polega na skopiowaniu wszelkich danych znajdujących
+        się na zdalnym serwerze do lokalnego katalogu lub odwrotnie i przy
+        następnych synchronizacjach będą kopiowane tylko te pliki, które
+        uległy zmianie. Na przykład skopiuje katalog domowy jednego z
+        użytkowników na zdalnym serwerze.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ rsync -avrPz server20:/home/user/.??* /tmp/user_server20/
+receiving incremental file list
+.bash_history
+          3,763 100%    3.59MB/s    0:00:00 (xfr#1, to-chk=7/8)
+.bash_logout
+             18 100%   17.58kB/s    0:00:00 (xfr#2, to-chk=6/8)
+.bash_profile
+            141 100%  137.70kB/s    0:00:00 (xfr#3, to-chk=5/8)
+.bashrc
+            492 100%  480.47kB/s    0:00:00 (xfr#4, to-chk=4/8)
+.lesshst
+             20 100%    9.77kB/s    0:00:00 (xfr#5, to-chk=3/8)
+.viminfo
+          2,263 100%    1.08MB/s    0:00:00 (xfr#6, to-chk=2/8)
+.ssh/
+.ssh/authorized_keys
+            579 100%  188.48kB/s    0:00:00 (xfr#7, to-chk=0/8)
+
+sent 165 bytes  received 3,064 bytes  2,152.67 bytes/sec
+total size is 7,276  speedup is 2.25
+</pre>
+      <p>
+        Aby taka synchronizacja miała sens potrzebne jest kilka opcji
+        takich jak <code class="code-inline">-a</code>, powodująca włączenie
+        trybu archiwalnego, przez co pliki zostaną skopiowane wraz ze
+        wszystkimi atrybutami; <code class="code-inline">-v</code> włączająca
+        wyświetlanie komunikatów diagnostycznych; 
+        <code class="code-inline">-r</code> włączająca rekurencje, zostaną
+        skopiowane katalogi wraz z podkatalogami; 
+        <code class="code-inline">-P</code> włączająca zwrócenie statystyk
+        postępu dla każdego przesyłanego pliku; 
+        <code class="code-inline">-z</code> włączająca kompresje. 
+      </p>
+      <p>
+        Jeśli
+        jeszcze raz spróbujemy pobrać te plik. Nic tak nie zostanie przesłane,
+        ponieważ pliki nie uległy zmianie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ rsync -avrPz server20:/home/user/.??* /tmp/user_server20/
+receiving incremental file list
+
+sent 21 bytes  received 228 bytes  498.00 bytes/sec
+total size is 7,276  speedup is 29.22
+</pre>
+      <h3 id="exec19.1">Ćwiczenie 1: Logowanie przez SSH z użyciem klucza</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynach
+        oznaczonych jako <em>server10</em> oraz <em>server20</em> utworz
+        nowego użytkownika <em>user20</em> oraz przypisz mu hasło. Następnie
+        na <em>server10</em>, przełącz się na tego użytkownika oraz wygeneruj
+        klucze <em>SSH</em> bez hasła. Zainstaluj klucz na <em>server20</em>
+        na koncie użytkowika <em>user20</em> i spróbuj się na niego zalogować.
+      </p>
+      <h3 id="exec19.2">Ćwiczenie 2: Działanie dyrektywy PermitRootLogin</h3>
+      <p>
+        Jako użytkownika z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server20</em>. Ustaw wartość dyrektywy
+        <em>PermitRootLogin</em> serwera <em>OpenSSH</em> na <em>no</em>.
+        Następnie z poziomu <em>server10</em> spróbuj się zalogować przez
+        <em>SSH</em> jako <em>root</em>. Następnie zmień wartość tej dyrektywy
+        na <em>yes</em> i spróbuj ponownie.
+      </p>
+      <h2 id="ch19summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale poruszyliśmy temat bezpieczengo zdalnego dostępu do
+        odległych maszyn. Jest on realizowany za pomocą protokołu 
+        <em>SSH</em>, z którego teoretycznymi podstawami zapoznaliśmy się na
+        początku tego rozdziału. Poruszyliśmy także temat plików
+        konfiguracyjnych serwera jak i klienta <em>SSH</em>. Na koniec
+        dowiedzieliśmy się jak korzystać z poleceń dostarczanych wraz z
+        pakietem <em>OpenSSH</em>. W następnym rozdziale poznamy zaporę
+        sieciową w systemie <em>RHEL</em> 9.
+      </p>
+      <h1 id="20.firewall">20. Zapora sieciowa w RHEL 9</h1>
+      <p>
+        Sieci komputerowe pozwalają na swobodną komunikację między komputerami,
+        co w pewnych przypadkach jest niewskazane, ponieważ nie zawsze pożądane
+        jest aby dowolny użytkownik internetu mógł połączyć się z naszym
+        komputerem i wysyłać lub pobierać z niego dane. Swobodę ruchu
+        kontrolują <strong>zapory sieciowe</strong>, które mogą być albo
+        fizycznymi urządzeniam wpiętymi w wyższe segmenty sieci lub
+        oprogramowaniem zainstalowanym na naszym komputerze czuwającym nad
+        ruchem sieciowym skierowanym do niego.
+      </p>
+      <p>
+        Zapora sieciowa ma za zadanie monitorować oraz kontrolować ruch
+        sieciowy. Jest to realizowane przez przeglądanie nagłówków pakietów
+        przesyłanych przez sieć oraz analiza źródłowych adresów <em>IP</em>,
+        używanych protokołów czy portów. W tym materiale skupimy się tylko
+        i wyłącznie na oprogramowaniu <em>firewall</em>-a dostarczonym do 
+        <em>Red Hat Enterprise Linux</em> 9.
+      </p>
+      <h2 id="20.1.firewalldtheory">20.1. Teoria firewalld</h2>
+      <p>
+        Pakiet zapory sieciowej dostarczony do <em>RHEL</em> to 
+        <strong>firewalld</strong>. Zapory dostępne w dystrybucjach
+        Linuks opierają swoją zasadę działania o dwa składniki: moduł jądra
+        <em>netfilter</em> oraz <em>framework</em> służący do klasyfikacji
+        oraz filtrowania pakietów - <em>nftables</em>. Dzięki czemu poza
+        zwykłymi <strong>zasadami</strong> (za pomocą zasad organizuje się 
+        ruch wychodzący oraz przychodzący w systemie) możemy realizować
+        bardziej zaawansowane funkcje takie jak translacja adresów
+        (<em>NAT</em>) umożliwiająca połączenie sieci lokalnej z internetem czy 
+        przekierowanie portów pozwalające na kontrolowaną komunikację między
+        użytkownikami internetu a serwerem wewnątrz sieci lokalnej.
+      </p>
+      <p>
+        <em>Firewalld</em> pozwala na kontrolowanie ruchu sieciowego bez 
+        wpływu na nawiązane już połączenia oraz bez potrzeby restartu żadnych
+        usług. Możemy dodawać, usuwać i modyfikować zasady za pomocą albo
+        specjalnego polecenia, albo za pomocą panelu sterowania <em>RHEL</em>,
+        dostępnym przez przeglądarkę, który jest możliwy włączenia za poprzez 
+        aktywacje jednostki <em>cockpit.service</em>.
+      </p>
+      <p>
+        Zasada działania <em>firewalld</em> opiera się na strefach co pozwala
+        na łatwiejsze oraz transparentne utrzymanie ruchu. 
+        <strong>Strefa</strong> określa poziom zaufania połączeń
+        sieciowych oraz adresów źródłowych. W konfiguracji strefy znajdują się
+        przypisane do nich połączenia sieciowe, przy czym jedno połączenie
+        może być przypisane tylko do jednej strefy w tym samym czasie, ale 
+        jedna strefa może mieć wiele
+        połączeń oraz zasady pozwalające na połączenia z 
+        wybraną usługą czy portem. Strefy definiują także domyślne zachowanie
+        zapory. Kiedy pakiet trafia do zapory, sprawdza ona jego
+        adres źródłowy czy nie występuje w którejś ze stref, jeśli nie ma
+        przypasowania, ten sam pakiet konfrontowany jest podstawie innych
+        kryteriów z regułami zapisanymi w strefie przypisanej do interfejsu
+        sieciowego z którego ten pakiet przybył, jeśli dalej nie ma 
+        przypasowania, wówczas jest ono szukane w domyślnej strefie. Brak
+        przypasowania na ostatnim etapie najczęściej oznacza, że pakiet
+        zostanie zablokowany przez zaporę.
+        W systemie możemy spotkać się z kilkoma predefiniowanym
+        strefami, wypisanymi na poniższej liście: 
+      </p>
+      <ul>
+        <li><strong>trusted</strong> - zezwól na wszystkie połączenia</li>
+        <li><strong>internal</strong> - Ruch przychodzący jest odrzucany, poza
+          jawnie wskazanym. Ta strefa stosowana jest w sieciach wewnętrznych.</li>
+        <li><strong>home</strong> - Ruch przychodzący jest odrzucany, poza
+          jawnie wskazanym. Ta strefa stosowana jest w sieciach domowych.</li>
+        <li><strong>work</strong> - Ruch przychodzący jest odrzucany, poza
+          jawnie wskazanym. Ta strefa jest stoswana w miejscu pracy.</li>
+        <li><strong>dmz</strong> - Ruch przychodzący jest odrzucany, poza
+          jawnie wskazanym. Ta strefa jest stosowana w strefie
+          zdemilitaryzowanej (nie ma ograniczeń w połączeniach miedzy
+          hostami w <em>DMZ</em>. Hosty są osiągalne z poziomu internetu, ale 
+          nie mogą nawiązywać połączeń z innymi komputerami w sieci lokalnej
+          poza strefą).</li>
+        <li><strong>external</strong> - Ruch przychodzą jest odrzucany, poza
+          jawnie wskazanym. W ruchu wychodzącym tej strefy dokonywana jest
+          translacja adresów IP (<em>NAT</em>).</li>
+        <li><strong>public</strong> - Ruch przychodzący jest odrzucany, poza
+          jawnie wskazanym. Ta strefa jest stosowana w miejscah publicznych.
+          Każdy nowy interfejs jest przypisywany do tej strefy.</li>
+        <li><strong>block</strong> - Ruch przychodzący jest odrzucany 
+          ze specjalną wiadmością zwrotną protokołu <em>ICMP</em>.</li>
+        <li><strong>drop</strong> - Ruch przychodzacy jest odrzucany bez żadnej
+          wiadomości zwrotnej.</li>
+      </ul>
+      <p>
+        Strefy na powyższej liście zostały uszeregowane od najbardzej zaufanej
+        do najmniej. Domyślną strefą stosowaną w <em>RHEL</em> jest
+        <em>public</em>. Ostatnie strefy są skierowane do środowisk o
+        podwyższonym poziomie zabezpieczeń. Nie ma ograniczeń w ruchu
+        wychodzącym w każdej ze stref.
+      </p>
+      <p>
+        Strefy z poziomu systemu operacyjnego, to zwykłe pliki tekstowe
+        przechowywane w dwóch lokalizacjach. Pierwszą z nich jest katalog
+        <em>/usr/lib/firewalld/zones</em>, w którym to są przechowywane
+        systemowe pliki stref. Drugim katalogiem jest 
+        <em>/etc/firewalld/zones</em> gdzie przchowywane są pliki stref
+        użytkowników. Jeśli zechcemy zmienić jeden z plików strefy np.
+        za pomocą polecenia, to automatycznie zostanie otworzona jego kopia
+        w katalogu <em>/etc/firewalld/zones</em> i to na niej zostaną
+        zatwierdzone nasze zmiany. Każda ze stref może zostać przez nas 
+        zmieniona. Poniżej znajduje się lista dostępnych
+        stref systemowych:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -l /usr/lib/firewalld/zones
+razem 40
+-rw-r--r--. 1 root root 312 2021-11-23  block.xml
+-rw-r--r--. 1 root root 306 2021-11-23  dmz.xml
+-rw-r--r--. 1 root root 304 2021-11-23  drop.xml
+-rw-r--r--. 1 root root 317 2021-11-23  external.xml
+-rw-r--r--. 1 root root 410 2021-11-23  home.xml
+-rw-r--r--. 1 root root 425 2021-11-23  internal.xml
+-rw-r--r--. 1 root root 729 2022-01-14  nm-shared.xml
+-rw-r--r--. 1 root root 356 2021-11-23  public.xml
+-rw-r--r--. 1 root root 175 2021-11-23  trusted.xml
+-rw-r--r--. 1 root root 352 2021-11-23  work.xml
+</pre>
+      <p>
+        Zawartość takiego pliku strefy prezentuje się w następujący sposób:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /usr/lib/firewalld/zones/public.xml
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;zone&gt;
+  &lt;short&gt;Public&lt;/short&gt;
+  &lt;description&gt;For use in public areas. You do not trust the other 
+computers on networks to not harm your computer. Only selected incoming 
+connections are accepted.&lt;/description&gt;
+  &lt;service name="ssh"/&gt;
+  &lt;service name="dhcpv6-client"/&gt;
+  &lt;service name="cockpit"/&gt;
+  &lt;forward/&gt;
+&lt;/zone&gt;
+</pre>
+      <p>
+        Każde z plików zawiera krótką nazwę, opis oraz deklaracje wskazujące
+        otwarcie ruchu dla wskazanych w dyrektywach
+        <code class="code-inline">services</code> usług. Usługi też w
+        <em>firewalld</em> mają swoje pliki, w których deklarowane są używane
+        przez nie porty oraz protokoły. Lista plików usług znajduje się w
+        katalogu <em>/usr/lib/firewalld/services</em>. Poniżej znajduje się
+        jej fragment. W przypadku usług panuje taka sama zasada jak w przypadku
+        stref.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -l /usr/lib/firewalld/services/
+razem 728
+-rw-r--r--. 1 root root  399 2021-11-23  amanda-client.xml
+-rw-r--r--. 1 root root  427 2021-11-23  amanda-k5-client.xml
+-rw-r--r--. 1 root root  283 2021-11-23  amqps.xml
+-rw-r--r--. 1 root root  273 2021-11-23  amqp.xml
+-rw-r--r--. 1 root root  285 2021-11-23  apcupsd.xml
+-rw-r--r--. 1 root root  301 2021-11-23  audit.xml
+-rw-r--r--. 1 root root  320 2021-11-23  bacula-client.xml
+-rw-r--r--. 1 root root  346 2021-11-23  bacula.xml
+-rw-r--r--. 1 root root  429 2021-11-23  bb.xml
+-rw-r--r--. 1 root root  339 2021-11-23  bgp.xml
+-rw-r--r--. 1 root root  275 2021-11-23  bitcoin-rpc.xml
+-rw-r--r--. 1 root root  307 2021-11-23  bitcoin-testnet-rpc.xml
+-rw-r--r--. 1 root root  281 2021-11-23  bitcoin-testnet.xml
+-rw-r--r--. 1 root root  244 2021-11-23  bitcoin.xml
+-rw-r--r--. 1 root root  410 2021-11-23  bittorrent-lsd.xml
+-rw-r--r--. 1 root root  294 2021-11-23  ceph-mon.xml
+-rw-r--r--. 1 root root  329 2021-11-23  ceph.xml
+-rw-r--r--. 1 root root  168 2021-11-23  cfengine.xml
+</pre>
+      <p>
+        Poniżej znajduje się zawartość przykładowego pliku usługi:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /usr/lib/firewalld/services/nfs.xml
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;service&gt;
+  &lt;short&gt;NFS4&lt;/short&gt;
+  &lt;description&gt;The NFS4 protocol is used to share files via TCP 
+networking. You will need to have the NFS tools installed and properly 
+configure your NFS server for this option to be useful.&lt;/description&gt;
+  &lt;port protocol="tcp" port="2049"/&gt;
+&lt;/service&gt;
+</pre>
+      <h2 id="20.2.firewallmanagement">20.2. Zarządzanie ruchem sieciowym w firewalld</h2>
+      <p>
+        Do zarządzania ruchem sieciowym posłużymy się poleceniem
+        <strong>firewall-cmd</strong>. Wymagana ono uprawnień superużytkownika
+        aby móc coś zmienić w zaporze. To polecenie posiada dużą ilość różnych
+        opcji, jednak nie ma sensu ich tu przytaczać. Poznamy je w trakcie
+        wykonywania przykładów z tego podrozdziału.
+      </p>
+      <h3 id="20.2.1.firewalldstatus">20.2.1. Sprawdzenie status zapory sieciowej</h3>
+      <p>
+        Sprawdzenia statusu zapory sieciowej możemy dokonać na dwa sposóby:
+        mozemy wydać polecenie <em>firewall-cmd</em> z odpowiednią opcją lub
+        sprawdzić status jednostki systemd <em>firewalld.service</em>. Poniżej
+        znajdują się wyniki działania obu tych poleceń:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo systemctl status firewalld.service 
+[sudo] hasło użytkownika user: 
+● firewalld.service - firewalld - dynamic firewall daemon
+     Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
+     Active: active (running) since Thu 2022-08-04 08:47:25 CEST; 2h 55min ago
+       Docs: man:firewalld(1)
+   Main PID: 720 (firewalld)
+      Tasks: 4 (limit: 5891)
+     Memory: 46.3M
+        CPU: 7.278s
+     CGroup: /system.slice/firewalld.service
+             └─720 /usr/bin/python3 -s /usr/sbin/firewalld --nofork --nopid
+
+sie 04 08:47:24 server10.example.com systemd[1]: Starting firewalld - dynamic firewall daemon...
+sie 04 08:47:25 server10.example.com systemd[1]: Started firewalld - dynamic firewall daemon.
+
+[user@server10 ~]$ sudo firewall-cmd --state
+running
+</pre>
+      <h3 id="20.2.2.firewalladd">20.2.2. Dodowanie usług, portów oraz zarządzanie strefami</h3>
+      <p>
+        Zanim jednak zaczniemy dodwać usługi i porty wyświetlimy sobie domyślną
+        strefę, a do tego posłuży opcja <em>--get-default-zone</em> polecenia
+        <em>firewall-cmd</em>:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --get-default-zone 
+[sudo] hasło użytkownika user: 
+public
+</pre>
+      <p>
+        Aby zmiany dokonane w zaporze zostały na stałe, należy każdą zmianę
+        poprzedzić opcją <strong>--permanent</strong>. Usługi możemy dodwać
+        za pomocą opcji <em>--add-service</em>. Podczas zapisywania opcji
+        polecenia <em>firewall-cmd</em> możemy posłużyć się klawiszem <em>Tab</em>
+        w celu autouzupełnienia. W ramach przykładu dodałem usługę <em>http</em>
+        do domyślniej strefy.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --add-service=http
+success
+</pre>
+      <p>
+        Aby ta reguła zadziałała <em>firewalld</em> musi ponownie wczytać plik
+        strefy, aby to wymusić wydajemy polecenie <em>firewall-cmd</em> wraz
+        opcją <em>--reload</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --reload
+[sudo] hasło użytkownika user: 
+success
+</pre>
+      <p>
+        Za pomocą opcji <em>--list-services</em>, możemy wyświetlić reguły
+        skonfigurowane do wskazanych usług:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --list-services
+cockpit dhcpv6-client http ssh
+</pre>
+      <p>
+        Jak możemy zauważyć dodana usługa znajduje się na liście reguł.
+      </p>
+      <p>
+        Dodawanie portów wygląda podobnie do dodawania usług jednak używa się
+        opcji <em>--add-port=</em>. Po podaniu portu należy również wskazać
+        po ukośniku (<strong>/</strong>) protokół <em>TCP</em> czy 
+        <em>UDP</em>. Opcja ta pozwala również na podanie zakresu portów.
+        Za pomocą poniższego polecenia dodałem porty <em>TCP</em> od 
+        5901 do 5910, do strefy (<em>--zone=</em>) <em>internal</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --add-port=5901-5910/tcp --zone=internal
+[sudo] hasło użytkownika user: 
+success
+</pre>
+      <p>
+        Za pomocą opcji <em>--list-ports</em>, możemy wyswietlić zasady
+        skonfigurowane pod konkretne porty. Natomiast za pomocą opcji
+        <em>--zone</em> możemy zarządzać innymi strefami.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --list-ports --zone=internal
+5901-5910/tcp
+</pre>
+      <p>
+        Za pomocą opcji <em>--set-default-zone=</em> możemy ustawić dowolną
+        strefę jako tę domyślną dla naszego systemu:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --set-default-zone=internal
+[sudo] hasło użytkownika user: 
+success
+</pre>
+      <h3 id="20.2.3.firewallremove">20.2.3. Usuwanie portów oraz usług</h3>
+      <p>
+        Aby wycofać wcześniej wykonywane zmiany należy użyć opcji
+        <em>--remove-service=</em> lub <em>--remove-port=</em>. Usunę
+        na początku regułę odpowiedzialną za otworzenie zakresu portów z
+        poprzedniego przykładu.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --remove-port=5901-5910/tcp 
+success
+[user@server10 ~]$ sudo firewall-cmd --reload 
+success
+[user@server10 ~]$ sudo firewall-cmd --list-ports
+</pre>
+      <p>
+        Opcja <em>--remove-port</em> również pozwala na podanie zakresu.
+        Również w tym przypadku wymagane jest podanie protokołu.
+      </p>
+      <p>
+        Teraz usunę również usługę <em>HTTP</em>, którą dodałem na początku,
+        pamiętając o tym, że <em>public</em> to nie jest już moją domyślną
+        strefą.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --remove-service=http --zone=public
+success
+[user@server10 ~]$ sudo firewall-cmd --reload 
+success
+[user@server10 ~]$ sudo firewall-cmd --list-services --zone=public
+cockpit dhcpv6-client ssh
+</pre>
+     <p>
+        Na koniec przywrócę moją domyślną strefę.
+     </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --set-default-zone=public
+success
+[user@server10 ~]$ sudo firewall-cmd --get-default-zone 
+public
+</pre>
+      <h3 id="20.2.4.firewalleffective">20.2.4. Efektywność zapory firewalld</h3>
+      <p>
+        W tym przykładzie sprawdzimy sobie w jaki sposób zapora działa w
+        praktyce. A przetestujemy to sobie usuwając regułę pozwalającą na
+        połączenie się przez SSH na jednej z maszyn.
+      </p>
+      <p>
+        Czynności rozpoczynamy od ustalenia domyślnej strefy oraz czy występuje
+        w niej usługa <em>SSH</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --get-default-zone 
+public
+[user@server10 ~]$ sudo firewall-cmd --list-services 
+cockpit dhcpv6-client ssh
+</pre>
+      <p>
+        Jak widzimy reguła <em>SSH</em> znajduje się na liście usług. Za pomocą
+        opcji <em>--remove-service=</em> możemy usunąć tą regułę.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --remove-service=ssh
+[sudo] hasło użytkownika user: 
+success
+[user@server10 ~]$ sudo firewall-cmd --reload
+success
+[user@server10 ~]$ sudo firewall-cmd --list-services 
+cockpit dhcpv6-client
+</pre>
+      <p>
+        Próba połączenia z tą maszyną z innej nie dochodzi do skutku.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ ssh server10
+ssh: connect to host server10 port 22: No route to host
+</pre>
+      <p>
+        Aby zakończyć to ćwiczenie, ten przykład,  dodajmy z powrotem regułę
+        <em>SSH</em> do domyślnej strefy i spróbujmy się połączyć ponownie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo firewall-cmd --permanent --add-service=ssh
+success
+[user@server10 ~]$ sudo firewall-cmd --reload
+success
+[user@server10 ~]$ sudo firewall-cmd --list-services 
+cockpit dhcpv6-client ssh
+</pre>
+      <p>
+        Tym razem próba kończy się powodzeniem.
+      </p>
+<pre class="code-block">
+[user@server20 ~]$ ssh server10
+user@server10's password: 
+Activate the web console with: systemctl enable --now cockpit.socket
+
+Register this system with Red Hat Insights: insights-client --register
+Create an account or view all your systems at https://red.ht/insights-dashboard
+Last login: Thu Aug  4 09:03:57 2022 from 192.168.122.7
+[user@server10 ~]$ 
+</pre>
+      <h3 id="exec20.1">Ćwiczenie 1: Dodawanie usługi do zapory</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server10</em>, dodaj na stałe regułę dla 
+        usługi <em>HTTPS</em> i aktywuj ją (<em>--reload</em>). Potwierdź
+        wykonanie zadania wyświetlając plik strefy oraz za pomocą odpowiedniej
+        opcji polecenia <em>firewall-cmd</em>.
+      </p>
+      <h3 id="exec20.2">Ćwiczenie 2: Dodawanie zakresu portów do zapory</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień, na maszynie
+        oznaczonej jako <em>server10</em>, dodaj zakres portów 8000-8005 
+        <em>UDP</em> do strefy <em>trusted</em> i aktywuj go 
+        (<em>--reload</em>). Potwierdź
+        wykonanie zadania wyświetlając plik strefy oraz za pomocą odpowiedniej
+        opcji polecenia <em>firewall-cmd</em>.
+      </p> 
+      <h2 id="ch20summary">Podsumowanie</h2>
+      <p>
+        W tym rodziale poruszyliśmy temat zapory sieciowej. Dowiedzieliśmy się
+        jak ona działa oraz co realizuje jej funkcję w <em>RHEL</em> 9.
+        Poznaliśmy podstawy teoretyczne oprogramowania <em>firewalld</em> oraz
+        poznaliśmy najczęściej stosowane polecenia za pomocą pokazanych w tym
+        rozdziale przykładów. W następnym rozdziale zapoznamy się mechanizmem
+        <em>SELinux</em>.
+      </p>
+      <h1 id="21.selinux">21. Security Enchanced Linux</h1>
+      <p>
+        <strong>Security Enchanced Linux (SELinux)</strong> decyduje o tym co
+        kto może zrobić w systemie. Ten mechanizm tworzy kolejną warstwę
+        bezpieczeństwa ponad klasycznymi zabezpieczeniami jakie
+        poznaliśmy do tej pory. Podstawowym celem <em>SELinux</em> jest
+        możliwe jak największe zmniejszenie wpływu na system w momencie
+        wystąpienia w nim nieuprawnionego dostępu.
+      </p>
+      <h2 id="21.1.theoryofselinux">21. Podstawy teoretyczne SELinux</h2>
+      <p>
+        <em>SELinux</em> jest implementacją mechanizmu <strong>MAC</strong>
+        (<em>Mandatory Access Control</em>), który jest zintegrowany z jądrem
+        Linuksa. <em>MAC</em> ogranicza możliwości dostępu 
+        <strong>podmiotu</strong> (użytkownik lub proces) do
+        <strong>obiektu</strong> (pliki, katalogi, systemu plików, urządzenia,
+        połączenia/interfejsy sieciowe, porty, potoki oraz gniazda). Dlatego
+        też w przypadku wykorzystania podatności na przykład na serwerze WWW,
+        atakujący będzie mieć wpływ tylko na pliki, do których miał dostęp ten
+        proces.
+      </p>
+      <p>
+        Do zapewnienia kontroli, mechanizm <em>MAC</em> wykorzystuje zbiory
+        zasad autoryzacyjnych zwanych <strong>polityką</strong> do sprawdzenia
+        atrybutów podmiotu kiedy stara się on o dostęp do obiektu i decyduje
+        czy udzielić tego dostępu. Atrybutu są zapisane w postaci 
+        <strong>kontekstu</strong> (lub <strong>etykiet</strong>) i dotyczą
+        zarówno podmiotów jak i obiektów. Decyzje dokonane przez 
+        <em>SELinux</em> są zapisywane w specjalnym rodzaju pamięci podręcznej
+        nazwanej <strong>AVC</strong> (<em>Access Vector Control</em>). W
+        momencie gdy dochodzić do decyzji <em>SELinux</em> sprawdza tę pamięć
+        podręczną czy nie udzielał już temu podmiotowi dostępu do tego obiektu.
+        Jeśli tak obecną decyzje bazuje na tej podjętej wcześniej przez co nie
+        musi on rozważać wszystkich możliwych zasad polityki wobec tej próby
+        dostępu. 
+      </p>
+      <h3 id="21.1.1.terminology">21.1.1. Pojęcia związane z SELinux</h3>
+      <p>
+        Aby obeznać się chociaż w podstawowym stopniu z <em>SELinux</em>
+        należy poznać kilka pojęć, które będą używane podczas przedstawiania
+        teorii tego mechanizmu ale również przykładów oraz ćwiczeń.
+      </p>
+      <ul>
+        <li><strong>Podmiot</strong> - każdy proces oraz użytkownik, który jest
+          w stanie uzyskać dostęp do obiektu. Na przykład 
+          <strong>system_u</strong> - użytkownik systemu <em>SELinux</em> czy
+          <strong>unconfined_u</strong> stosowany dla podmiotów, które nie są
+          związane z polityką <em>SELinux</em>. Podmiot <em>SELinux</em>
+          znajduje się w pierwszym polu kontekstu.</li>
+        <li><strong>Objekt</strong> - zasób systemowy, od plików po gniazda.
+          Obiekty mogą zostać przestawione jako <strong>object_r</strong> -
+          obiekt ogólny, <strong>system_r</strong> - obiekt systemowy albo
+          <strong>unconfined_r</strong> - obiekt niezwiązny z <em>SELinux</em>.
+        </li>
+        <li><strong>Dostęp</strong> - akcja dokonywana przez podmiot na
+          obiekcie. W ramach dostępu możemy wyróżnić tworzenie, odczyt,
+          modyfikację pliku, wyświetlenie zawartości katalogu czy próba
+          dostępu do portu albo gniazda.</li>
+        <li><strong>Polityka</strong> - Zbiór zasad mający wpływ na cały
+          system. Polityka jest wykorzystywana do analizy atrybutów podmiotów 
+          oraz
+          obiektów. Na podstawie polityki <em>SELinux</em> dokonuje decyzji
+          czy pozwolić podmiotowi na dostęp lub interakcje z obiektem. Jeśli
+          brakuje pasującej zasady, wówczas domyślną decyzją jest odmowa.
+          <em>SELinux</em> dostarczany jest wraz z dwoma standardowymi
+          preconfigurowanymi politykami <strong>targeted</strong> oraz
+          <strong>MLS</strong>, gdzie <em>targeted</em> wskazuje, że każdy
+          ukierunkowany proces uruchamiany jest w ograniczonej
+          <strong>domenie</strong> oraz każdy nieukierunkowany proces
+          uruchomiony jest w nieograniczonej domenie. Na przykład 
+          <em>SELinux</em> umieszcza zalogowanego użytkownika w 
+          nieograniczonej domenie, a proces serwera WWW domyślnie w domenie
+          ograniczonej. Każdy podmiot działający w domenie nieograniczonej
+          jest większym żagrożniem niż ten, który działa w domenie ograniczonej.
+        </li>
+        <li><strong>Kontekst</strong> - lub etykieta, jest to znacznik
+          przechowywujący atrybuty. Każdy element w ujęciu <em>SELinux</em>
+          posiada przypisany kontekst, który składa się z użytkownika
+          <em>SELinux</em>, roli, domeny (czy też typu) oraz poziomu.
+          <em>SELinux</em>, korzysta z konktekstu podczas podejmowania decyzji
+          o przydzieleniu dostępu.
+        </li>
+        <li><strong>Etykietowanie</strong> - mapowanie plików wraz z 
+          kontekstem.</li>
+        <li><strong>Użytkownik SELinux</strong> - predefiniowany w polityce
+          użytkownik <em>SELinux</em> autoryzowany do określonego zbioru reguł.
+          W polityce znajdują się mapowania użytkowników systemu na
+          użytkowników <em>SELinux</em>, aby ograniczać ich możliwości.
+          Użytkownik określa jakie role oraz domeny lub typy mogą zostać 
+          przypisane
+          do procesu lub pliku . Jeśli użytkownik systemu będzie mieć 
+          przypisanego
+          użytkownika <strong>user_u</strong>, nie będzie mógł wówczas
+          uruchomić żadnego programu znajdującego się w swoim katalogu domowym
+          oraz korzystać z takich poleceń jak <em>su</em> czy <em>sudo</em>.
+        </li>
+        <li><strong>Rola</strong> - określa czy podmiot ma możliwość dostępu
+          do domeny. Użytkownicy <em>SELinux</em> są autoryzowani do ról,
+          natomiast role do domen oraz typów. Każdy podmiot ma określoną role 
+          aby
+          odseparować procesy systemowe od procesów użytkowników. Podmioty
+          mogą zmienić swoje role, aby zwiększyć dostęp do innych domen.
+          Przykładowymi rola są: <strong>user_r</strong> - dla zwykłych
+          użytkowników, <strong>sysadm_r</strong> - dla administratorów oraz
+          <strong>system_r</strong>, dla procesów zaincjowanych pod tą rola.
+          Rola zajmuje drugie pole kontekstu.
+        </li>
+        <li><strong>Typ egzekwowania</strong> - identyfikuje oraz ogranicza 
+          możliwość dostępu procesów do domen oraz plików do typów. Odwołuje
+          się do kontekstu podmiotów oraz obiektów.
+        </li>
+        <li><strong>Typ</strong> - grupa obiektów bazująca na jednolitości
+          wymagań bezpieczeństwa. Pliki oraz katalogi na podstawie wspólnych
+          wymagań zabezpieczeń mogą zostać zgrupowane w jeden typ. Na przykład
+          <strong>user_home_t</strong> dla obiektów znajdujących się w
+          katalogach domowych użytkowników, czy <strong>usr_t</strong> dla
+          większości obiektów znajdujących się w katalogach 
+          <strong>/usr</strong>.
+        </li>
+        <li><strong>Domena</strong> - określa dostęp jaki posiada proces.
+          Procesy ze wspólnymi wymogami bezpieczeństwa mogą zostać zgrupowane
+          do jednej określonej domeny, przez co ich działania mogą zostać w
+          niej ograniczone. Dla przykładu proces <em>systemd</em> działa w
+          domenie <strong>unit_t</strong> a <em>firewalld</em> w
+          <strong>firewalld_t</strong>. Typ lub domena znajdują się na trzecim
+          polu kontekstu.
+        </li>
+        <li><strong>Poziom bezpieczeństwa</strong> - poziom bezpieczńswa może
+          być ujęty w dwóch rodzajach <strong>MLS</strong>
+          (<em>Multi-Level Security</em>) lub <strong>MCS</strong>
+          (<em>Multi-Category Security</em>). Poziom ten składa się z dwóch
+          czynników: <strong>wrażliwości</strong> oraz <strong>kategorii</strong>
+          Kategorie mogą być definiowane za pomocą pojedynczych wartości lub
+          zakresów np. <strong>c0.c4</strong> co oznacza kategorie od <em>c0</em>
+          do <em>c4</em>. Od <em>RHEL</em> 8 w polityce ukierunkowanej wymusza
+          użycie rodzaju <em>MCS</em>, który określa tylko jeden poziom
+          wrażliwości jakim jest <strong>s0</strong> oraz 1024 kategorie od
+          <strong>0</strong> do <strong>1023</strong>.
+        </li>
+      </ul>
+      <h3 id="21.1.2.contextofusers">21.1.2. Kontekst SELinux użytkowników</h3> 
+      <p>
+        Za pomocą opcji <strong>-Z</strong> polecenie <em>id</em> możemy
+        poznać kontekst <em>SELinux</em> użytkowników.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ id -Z
+unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
+</pre>
+      <p>
+        W polu użytkownika <em>SELinux</em> jego nazwa to
+        <code class="code-inline">unconfined_u</code> co oznacza, że ma
+        nieograniczone możliwości. Superużytkownik również przypisanego ma
+        tego samego użytkownika. Pomimo tego <em>SELinux</em> dostarcza
+        siedemiu swoich użytkowników ograniczających wpływ
+        zwykłych użytkowników na system. Aby wyświetlić ich nazwy musimy 
+        zainstalować pakiet <em>setools-console</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo seinfo -u
+[sudo] hasło użytkownika user: 
+
+Users: 8
+   guest_u
+   root
+   staff_u
+   sysadm_u
+   system_u
+   unconfined_u
+   user_u
+   xguest_u
+</pre>
+      <p>
+        Jak możemy zauwazyć <code class="code-inline">unconfined_u</code>
+        również jest jednym z użytkowników <em>SELinux</em> dla tego też mówimy
+        o siedmiu. Przypisanie go użytkownikom systemu wynika
+        z mapowania w polityce, a te możemy podejrzeć za pomocą polecenia
+        <strong>semanage</strong> wraz z pod poleceniem <em>login</em> oraz
+        opcją <em>-l</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage login -l
+
+Login                Użytkownik SELinuksa Zakres MLS/MCS       Usługa
+
+__default__          unconfined_u         s0-s0:c0.c1023       *
+root                 unconfined_u         s0-s0:c0.c1023       *
+</pre>
+      <p>
+        W pierwszej kolumnie <code class="code-inline">Login</code> znajdują
+        się nazwy użytkowników systemowych. Wartość 
+        <code class="code-inline">_default_</code> tyczy się wszystkich
+        zwykłych użytkowników.
+      </p>
+      <h3 id="21.1.3.contextofprocess">21.1.3. Kontekst procesów</h3>
+      <p>
+        Za pomocą opcji <strong>-Z</strong> znanego już polecenia <em>ps</em>,
+        możemy wyświetlić kontekst <em>SELinux</em> procesów. Ponizej
+        znajduje się przykład:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ps -eZ
+LABEL                               PID TTY          TIME CMD
+system_u:system_r:init_t:s0           1 ?        00:00:01 systemd
+...
+</pre>
+      <p>
+        W polu <code class="code-inline">LABEL</code> znajduje się kontekst
+        <em>SELinux</em>. Podmiotem w tym przypadku jest użytkownik
+        <em>SELinux</em> <code class="code-inline">system_u</code>
+        (mapowany do superużytkownika), rolą, rola systemowa -
+        <code class="code-inline">system_r</code> z typem ochrony nałożonym
+        przez domenę <code class="code-inline">init_t</code> i poziomem
+        bepzieczeństwa wskazywanym przez <code class="code-inline">s0</code>.
+      </p>
+      <p>
+        Każdy niechroniony proces działa w domenie 
+        <strong>unconfined_t</strong>.
+      </p>
+      <h3 id="21.1.4.contextoffile">21.1.4. Kontekst SELinux plików</h3>
+      <p>
+        Pliki oraz katalogi to obiekty <em>SELinux</em> one również posiadają
+        kontekst, który może zostać wyświetlony za pomocą opcji
+        <strong>-Z</strong> polecenia <em>ls</em>. Poniżej znajdują się
+        atrybuty oraz kontekst dla pliku <em>/etc/passwd</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -lZ /etc/passwd
+-rw-r--r--. 1 root root system_u:object_r:passwd_file_t:s0 1764 08-03 08:46 /etc/passwd
+</pre>
+      <p>
+        Ten plik posiada rolę przeznaczoną dla zwykłych obiektów
+        (<code class="code-inline">object_r</code>) oraz typ o nazwie
+        <code class="code-inline">passwd_file_t</code>. Kontekst wszystkich
+        plików w systemie składowany jest dwóch plikach <em>file_context</em>
+        oraz <em>file_context.local</em> w katalogu
+        <em>/etc/selinux/targeted/context/files</em>. Kontekst może zostać
+        zmieniony za pomocą polecenia <em>semanage</em>.
+      </p>
+      <h3 id="21.1.5.savethecontext">21.1.5. Zachowanie kontekstu SELinux podczas zarządzania plikami</h3>
+      <p>
+        Domyślnie kopiując pliki z jednego katalogu do drugiego kontekst
+        <em>SELinux</em>, zostanie odziedziczony z katalogu nadrzędnego,
+        taka sama zasada tyczy się nadpisywania plików, wówczas plik źródłowy
+        otrzyma kontekst <em>SELinux</em> od pliku, który został nadpisany.
+        Aby zachować kontekst <em>SELinux</em> należy użyć opcji
+        <strong>--preserve</strong> wraz z wartością <strong>context</strong>.
+      </p>
+      <p>
+        Przenoszenie nie ma wpływu na kontekst <em>SELinux</em>. Kontekst
+        pozostaje w nienaruszonym stanie.
+      </p>
+      <p>
+        Jeśli istnieje potrzeba aby zachować kontekst <em>SELinux</em> w 
+        archiwach <em>tar</em> to należy użyć opcji <em>--selinux</em>.
+      </p>
+      <p>
+        Przetestujemy sobie część tych przypadków podczas przykładów.
+      </p>
+      <h3 id="21.1.6.contextofports">21.1.6. Kontekst SELinux portów sieciowych</h3>
+      <p>
+        <em>SELinux</em> definiuje atrybuty bezpieczeństwa dla każdego rozdzaju
+        obiektu w tym i dla portów. Typy (w ujęciu <em>SELinux</em>) dla
+        portów możemy podejrzeć za pomocą polecenia <strong>semanage</strong>
+        wraz z podpoleceniem <em>port</em> oraz opcją <em>-l</em>.
+      </p>
+<pre class="code-block">
+[user@rhel90 ~]$ sudo semanage port -l
+Typ portu SELinuksa            Protokół Numer portu
+ftp_data_port_t                tcp      20
+ftp_port_t                     tcp      21, 989, 990
+ftp_port_t                     udp      989, 990
+http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
+ssh_port_t                     tcp      22
+</pre>
+      <p>
+        Wyjście prezentowane jest kolumnach, w przypadku portów spotykamy się
+        z typem, tak jak w przypadku plików. Domyślnie <em>SELinux</em> 
+        pozwala na nasłuchiwanie usługom tylko na określonych przez typy
+        portach.
+      </p>
+      <h3 id="21.1.7.domaintransitioning">21.1.7. Zmiana domeny SELinux</h3>
+      <p>
+        <em>SELinux</em> pozwala procesom na zmianę domeny, aby mogły uruchomić
+        aplikację, która może działać tylko w jednej określonej domenie. Tego
+        typu zachowanie jest oczywiście poparte regułami w polityce, które
+        wspierają tego typu działania. Zmiana domeny możliwa jest za pomocą
+        uprawnienia <strong>entrypoint</strong>, które kontroluje taką 
+        możliwość. Najprostszym tego przykładem jest zmiana hasła.
+      </p>
+      <p>
+        <em>SELinux</em> w swojej polityce posiada zasady, dzięki którym
+        proces działający w domenie <strong>passwd_t</strong> może
+        modyfikować plik z typem <strong>shadow_t</strong>. W tej polityce
+        istnieje także uprawnienie <em>entrypoint</em> w domenie
+        <strong>passwd_exec_t</strong>. Dzięki czemu polecenie
+        <em>passwd</em> może modyfikować plik <em>/etc/shadow</em>, gdzie
+        tak naprawdę nikt nie ma żadnych klasycznych uprawnień. Poniżej
+        znajdują się atrybut wraz kontekstem zarówno polecenia <em>passwd</em>
+        oraz pliku <em>/etc/shadow</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -lZ /usr/bin/passwd 
+-rwsr-xr-x. 1 root root system_u:object_r:passwd_exec_t:s0 32648 2021-08-10  /usr/bin/passwd
+[user@server10 ~]$ ls -lZ /etc/shadow
+----------. 1 root root system_u:object_r:shadow_t:s0 1368 08-03 08:47 /etc/shadow
+</pre>
+      <h3 id="21.1.8.selinuxbooleans">21.1.8. Wartości logiczne SELinux</h3>
+      <p>
+        Wartości logiczne <em>SELinux</em> są używane jako przełączniki
+        włączające lub wyłączające pozwolenie na wykonanie pewnej akcji.
+        W ujęciu polityki przełączają one zasady bez potrzeby ich pownownego
+        wczytywania. Za pomocą tych wartości możemy pozwolić aby anonimowi
+        użytkownicy <em>FTP</em> mogli zapisywać na serwerze dane. Wszyskie
+        te wartości są złożone w katalogu <em>/sys/fs/selinux/booleans</em>.
+        Poniżej znajduje się fragment listingu tego katalogu, w systemie takim
+        jak <em>RHEL</em> znajduje się wiele tych wartości
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -l /sys/fs/selinux/booleans/ | head 
+razem 0
+-rw-r--r--. 1 root root 0 08-06 09:07 abrt_anon_write
+-rw-r--r--. 1 root root 0 08-06 09:07 abrt_handle_event
+-rw-r--r--. 1 root root 0 08-06 09:07 abrt_upload_watch_anon_write
+-rw-r--r--. 1 root root 0 08-06 09:07 antivirus_can_scan_system
+-rw-r--r--. 1 root root 0 08-06 09:07 antivirus_use_jit
+-rw-r--r--. 1 root root 0 08-06 09:07 auditadm_exec_content
+-rw-r--r--. 1 root root 0 08-06 09:07 authlogin_nsswitch_use_ldap
+-rw-r--r--. 1 root root 0 08-06 09:07 authlogin_radius
+-rw-r--r--. 1 root root 0 08-06 09:07 authlogin_yubikey
+...
+</pre>
+      <p>
+        Nazwa kazdego pliku odpowiada nazwie wartości używanej do zmiany jej
+        stanu.
+        Jeśli na podstawie nazwy nie możemy wywnioskować do czego służy podana
+        wartość, to możemy zainstalować pakiet <em>selinux-policy-doc</em> i
+        wyszukać odpowiednią stronę podręcznika podając nazwę wartości
+        poleceniu <em>man</em> po opcji <em>-K</em>.
+      </p>
+      <p>
+        Możemy przeglądać wartości logiczne i zmieniać ich stan tymczasowo co 
+        nię będzie miało wpływu na politykę lub na stałe, wówczas te będzie
+        musiało mieć już swoje odzwierciedlenie w polityce.
+      </p>
+      <h2 id="21.2.selinuxadministration">21.2. Zarządzanie SELinux</h2>
+      <p>
+        Zarządzanie <em>SELinux</em> to wiele zadań obejmujących aktywację
+        mechanizmu, zmianę jego stanu operacyjnego, aktualizacje kontekstu
+        zarówno podmiotów jak i obiektów oraz przełączanie wartości logicznych.
+        W tym celu w <em>RHEL</em> znajduje się wiele narzędzi, które możemy
+        wykorzystać do tego celu.
+      </p>
+      <h3 id="21.2.1.managingcommands">21.2.1. Polecenia zarządzające</h3>
+      <p>
+        <em>RHEL</em> dostarcza wiele poleceń, dzięki którym możemy realizować
+        nasze zadania związane z <em>SELinux</em>. Wiele z nich odpowiada za
+        konkretne czynności, jednak jedno <strong>semanage</strong> pozwala na
+        zrealizowanie tych zadań dobierając odpowiednie podpolecenie.
+        Innym poleceniem, na które należy zwrócić uwagę jest 
+        <strong>chcon</strong>, które pozwala na zmianę contekstu obiektu oraz
+        <strong>restorcon</strong>, które przywraca kontekst z bazy (plików
+        wymienionych w poprzednim podrozdziale, podczas omawiania kontektu
+        plików). Poniżej znajdują się przykłady, dzięki którym poznamy
+        jak należy zarządzać <em>SELinux</em> w praktyce oraz niezbędne do tego 
+        polecenia.
+      </p>
+      <h3 id="21.2.2.operationalstate">21.2.2. Zmiana stanu operacyjnego SELinux</h3>
+      <p>
+        Stan operacyjny tego mechanizmu możemy zmienić, zmieniając wartość
+        jednej z dyrektyw w pliku konfigracyjny <em>SELinux</em>. W tym pliku
+        możemy również wyłączyć ten mechanizm. Na poniższym przykładzie
+        znajduje się jego zawartość:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat /etc/selinux/config 
+
+# This file controls the state of SELinux on the system.
+# SELINUX= can take one of these three values:
+#     enforcing - SELinux security policy is enforced.
+#     permissive - SELinux prints warnings instead of enforcing.
+#     disabled - No SELinux policy is loaded.
+# See also:
+# https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-selinux/
+#getting-started-with-selinux-selinux-states-and-modes
+#
+# NOTE: In earlier Fedora kernel builds, SELINUX=disabled would also
+# fully disable SELinux during boot. If you need a system with SELinux
+# fully disabled instead of SELinux running with no policy loaded, you
+# need to pass selinux=0 to the kernel command line. You can use grubby
+# to persistently set the bootloader to boot with selinux=0:
+#
+#    grubby --update-kernel ALL --args selinux=0
+#
+# To revert back to SELinux enabled:
+#
+#    grubby --update-kernel ALL --remove-args selinux
+#
+SELINUX=enforcing
+# SELINUXTYPE= can take one of these three values:
+#     targeted - Targeted processes are protected,
+#     minimum - Modification of targeted policy. Only selected processes are protected.
+#     mls - Multi Level Security protection.
+SELINUXTYPE=targeted
+</pre>
+      <p>
+        Zachowanie <em>SELinux</em> możemy kontrolować za pomocą dyrektywy
+        <code class="code-inline">SELINUX</code>. Dyrektwa może przyjmować
+        takie wartości jak:
+      </p>
+      <ul>
+        <li><strong>enforcing</strong> - wymuszając tym samym stosowanie
+          polityki względem podmiotów.</li>
+        <li><strong>permissive</strong> - w tym przypadku <em>SELinux</em>
+          nie będzie wymuszać stosowania polityki, ale jej naruszenia będą
+          rejestrowane.</li>
+        <li><strong>disabled</strong> - wyłączenie ładowania polityki, co
+          powoduje, że działanie <em>SELinux</em> nie będzie mieć wpływu na
+          system.</li>
+      </ul>
+      <p>
+        Inna wartością kontrolujcą ten mechanizm jest dyrektywa
+        <code class="code-inline">SELINUXTYPE</code> wymuszająca typ polityki.
+        Domyślnie stosowaną jest polityka ukierunkowana
+        (<code class="code-inline">targeted</code>). Pozostałe wartości 
+        znajdują się w komentarzu nad dyrektywą.
+      </p>
+      <p>
+        Do uzyskania informacji na temat działania <em>SELinux</em> możemy
+        skorzystać z polecenia <strong>getenforce</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo getenforce
+[sudo] hasło użytkownika user: 
+Enforcing
+</pre>
+      <p>
+        Tymczasem do chwilowej zmiany stanu tego mechanizmu możemy użyć
+        polecenia <strong>setenforce</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo setenforce
+usage:  setenforce [ Enforcing | Permissive | 1 | 0 ]
+[user@server10 ~]$ sudo setenforce 0
+[user@server10 ~]$ sudo getenforce
+Permissive
+</pre>
+      <p>
+        Przy czym do wyboru mamy tylko <code class="code-inline">Enforcing</code>
+        (<code class="code-inline">1</code>) lub
+        <code class="code-inline">Permissive</code>
+        (<code class="code-inline">0</code>).
+      </p>
+      <p>
+        Aby jednak na stałe zmienić stan operacyjny <em>SELinux</em> musimy
+        zmienić to pliku konfiguracyjnym a następnie uruchomić ponownie
+        system.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu</strong><br />
+        Jeśli zajdzie taka potrzeba możemy przełączać się między stanami
+        operacyjnymi, aby na przykład rozwiązać problem z usługą.
+        Po rozwiązaniu problemów, możemy powrócić do normalnego stanu.
+      </p>
+      <h3 id="21.2.3.querying">21.2.3. Sprawdzanie stanu SELinux</h3>
+      <p>
+        Z pomocą polecenia <strong>sestats</strong>, mozemy sprawdzić stan
+        mechanizmu <em>SELinux</em> oraz wyświetlić kilka dodatkowych
+        informacji na jego temat.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sestatus
+SELinux status:                 enabled
+SELinuxfs mount:                /sys/fs/selinux
+SELinux root directory:         /etc/selinux
+Loaded policy name:             targeted
+Current mode:                   enforcing
+Mode from config file:          enforcing
+Policy MLS status:              enabled
+Policy deny_unknown status:     allowed
+Memory protection checking:     actual (secure)
+Max kernel policy version:      33
+</pre>
+      <p>
+        Z informacji zwracanych przez to polecenie możemy wywnioskować w jakim
+        trybie działa <em>SELinux</em> 
+        (<code class="code-inline">Current mode:</code>) oraz rodzaj używanej
+        polityki (<code class-"code-inline">Loaded policy name:</code>).
+      </p>
+      <p>
+        Używając opcji <em>-v</em> możemy wyświetlić kontekst, niektórych
+        plików oraz procesów. Są one zapisane w pliku <em>/etc/sestatus.conf</em>.
+      </p>
+      <h3 id="21.2.4.modifyselinuxcontent">21.2.4. Modyfikowanie kontekstu SELinux plików</h3>
+      <p>
+        Do modyfikowania kontekstu słuzy polecenie <strong>chcon</strong>.
+        Chcąc zmienić użytkownika <em>SELinux</em> używamy opcji 
+        <em>-u</em>, do zmiany typu wykorzystujemy opcję <em>-t</em>. Jeśli
+        zmiany mają być rekurencyjne wówczas należy uzyć opcji <em>-R</em>.
+        Na poniższym przykładzie zobrazowałem to zmieniając kontekst
+        katalogu <em>/tmp/testsedir1</em> w którym znajdował się plik
+        <em>testsefile2</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -ldZ /tmp/testsedir1/
+drwxr-xr-x. 2 user user unconfined_u:object_r:user_tmp_t:s0 25 08-06 12:34 /tmp/testsedir1/
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user unconfined_u:object_r:user_tmp_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+
+[user@server10 ~]$ sudo chcon -v -u user_u -t public_content_t /tmp/testsedir1 -R
+[sudo] hasło użytkownika user: 
+zmiana kontekstu bezpieczeństwa '/tmp/testsedir1/testsefile2'
+zmiana kontekstu bezpieczeństwa '/tmp/testsedir1'
+
+[user@server10 ~]$ ls -ldZ /tmp/testsedir1/
+drwxr-xr-x. 2 user user user_u:object_r:public_content_t:s0 25 08-06 12:34 /tmp/testsedir1/
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user user_u:object_r:public_content_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+</pre>
+      <p>
+        Jak możemy zauważyć na powyższym przykładzie zmieniliśmy typ oraz
+        użytkownika <em>SELinux</em>.
+      </p>
+      <h3 id="21.2.5.addandapplyfilecontext">21.2.5. Dodwanie oraz zatwierdzanie kontekstu plików SELinux</h3>
+      <p>
+        Aby zatwierdzić zmieniony kontekst plików należy dodać go do bazy
+        kontekstów. Do tego posłużymy się poleceniem <strong>semanage</strong>
+        wraz z podpoleceniem <em>fcontext</em>, za pomocą opcji <em>-a</em>
+        wskazujemy akcje dodania nowego kontekstu, opcja <em>-s</em> wskazuje
+        na użytkownika <em>SELinux</em>, opcja <em>-t</em> wskazuje na typ
+        w tym przypadku. Na końcu podajemy ścieżkę do pliku lub katalogu.
+        Jeśli zmiany mają obejmować katalog wraz z jego zawartością to wówczas
+        należy użyć wyrażenia regularnego: <strong>(/.*)?</strong> w ścieżce
+        katalogu. Teraz dodam zmiany z wcześniejszego podrozdziału do bazy.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage fcontext -a -s user_u -t public_content_t '/tmp/testsedir1(/.*)?'
+[sudo] hasło użytkownika user: 
+
+[user@server10 ~]$ sudo semanage fcontext -Cl
+fcontext SELinuksa       typ                Kontekst
+
+/tmp/testsedir1(/.*)?    all files          user_u:object_r:public_content_t:s0 
+</pre>
+      <p>
+        Za pomocą opcji <em>-Cl</em> wyświetliłem ostatnie zmiany w bazie 
+        kontekstów plików <em>SELinux</em>. Teraz jeśli zmienimy kontekst
+        tego katalogu lub któregoś z zawartych w nim plików to będziemy mogli 
+        powrócić do poprzedniego stanu za pomocą
+        polecenia <strong>restorecon</strong> bazując na wpisie w bazie
+        danych, który dodaliśmy we wcześniejszym przykładzie. Aby to
+        za prezentować zmienię teraz kontekst zarówno katalogu jak i jego
+        zawartości.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -ldZ /tmp/testsedir1/
+drwxr-xr-x. 2 user user user_u:object_r:public_content_t:s0 25 08-06 12:34 /tmp/testsedir1/
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user user_u:object_r:public_content_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+
+[user@server10 ~]$ sudo chcon -v -u user_u -t usr_t /tmp/testsedir1 -R
+zmiana kontekstu bezpieczeństwa '/tmp/testsedir1/testsefile2'
+zmiana kontekstu bezpieczeństwa '/tmp/testsedir1'
+
+[user@server10 ~]$ ls -ldZ /tmp/testsedir1/
+drwxr-xr-x. 2 user user user_u:object_r:usr_t:s0 25 08-06 12:34 /tmp/testsedir1/
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user user_u:object_r:usr_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+
+[user@server10 ~]$ sudo restorecon -Rv /tmp/testsedir1/
+Relabeled /tmp/testsedir1 from user_u:object_r:usr_t:s0 to user_u:object_r:public_content_t:s0
+Relabeled /tmp/testsedir1/testsefile2 from user_u:object_r:usr_t:s0 to user_u:object_r:public_content_t:s0
+
+[user@server10 ~]$ ls -ldZ /tmp/testsedir1/
+drwxr-xr-x. 2 user user user_u:object_r:public_content_t:s0 25 08-06 12:34 /tmp/testsedir1/
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user user_u:object_r:public_content_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+</pre>
+      <p>
+        Opcja <code class="code-inline">-R</code> polecenia <em>restorecon</em>
+        włącza rekurencję, natomiast <code class="code-inline">-v</code>
+        włącza wyświetlanie komunikatów diagnostycznych.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Podczas zmiany kontekstu plików oraz katalogów warto korzystać z
+        polecenia <em>semanage</em> oraz <em>restorecon</em> aby dodawać
+        kontekst do bazy a następnie przywrócić go na pliku. Przez co
+        będziemy mieć pewność że zmiany z pewnością przetrwają ponowne
+        uruchomienie serwera.
+      </p>
+      <h3 id="21.2.6.addanddeletenetworkport">21.2.6. Dodawanie i usuwanie portów sieciowych w ujęciu SELinux</h3>
+      <p>
+        Jak mogliśmy się dowiedzieć domyślnie <em>SELinux</em> pozwala na
+        nasłuchiwanie tylko na określonych typami portach więc jeśli nasza 
+        usługa
+        musi nasłuchiwać na inny niż te w określonym type musimy dodać ten port
+        do mechanizmu <em>SELinux</em>.
+      </p>
+      <p>
+        Dodawnie portów możemy zrealizować za pomocą polecenia <em>semanage</em>,
+        ale na początku określimy typ portu SELinux. Za pomocą podpolecenia
+        <em>port</em> wraz z opcją <em>-l</em> możemy wylistować wszystkie
+        porty wraz z protokołami oraz typami portów. Załóżmy, że chcę dodać
+        port do usługi <em>http</em>, wówczas możemy wyszukać portów 
+        powiązanych z tą usługą za pomocą polecenie <em>grep</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage port -l | grep 'http'
+[sudo] hasło użytkownika user: 
+http_cache_port_t              tcp      8080, 8118, 8123, 10001-10010
+http_cache_port_t              udp      3130
+http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
+pegasus_http_port_t            tcp      5988
+pegasus_https_port_t           tcp      5989
+</pre>
+      <p>
+        Potrzebny port dodam do typu 
+        <code class="code-inline">http_port_t</code>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage port -at http_port_t -p tcp 8010
+[user@server10 ~]$ sudo semanage port -l | grep 'http_port_t'
+http_port_t                    tcp      8010, 80, 81, 443, 488, 8008, 8009, 8443, 9000
+</pre>
+      <p>
+        Aby dodać port użyłem podpolecenia 
+        <code class="code-inline">port</code> wraz z opcjami 
+        <code class="code-inline">-at</code>, które
+        nakazują dodanie portu oraz wskaznie na typ portu <em>SELinux</em>.
+        Następnie po opcji <em>-p</em> podałem protokół oraz numer portu.
+        Na koniec wyświetliłem jeszce ten typ portu, aby sprawdzić czy zmiany
+        zostały zatwierdzone. 
+      </p>
+      <p>
+        Jeśli port przestanie nam być potrzebny możemy go usunąć, za pomocą
+        opcji <em>-d</em> oraz opcji <em>-p</em> po której podajemy protokół
+        i numer portu. Teraz usunę ten port, który wcześniej dodałem.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage port -d -p tcp 8010
+[sudo] hasło użytkownika user: 
+[user@server10 ~]$ sudo semanage port -l | grep 'http_port_t'
+http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
+</pre>
+      <p>
+        Jak możemy zauważyć nie ma już portu 8010 na początku listy
+        przydzielonej do typu <code class="code-inline">http_port_t</code>.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu</strong><br />
+        Aby korzystać z niestandarowych portów dla usług należy dodać je do
+        typów tych usług w <em>SELinux</em>.
+      </p>
+      <h3 id="21.2.7.preservingcontext">21.2.7. Zachowanie kontekstu SELinux podczas kopiowania</h3>
+      <p>
+        Aby zachować kontekst <em>SELinux</em> dla kopiowanych plików, należy
+        użyć opcji <em>--preserve=context</em>  polecenia <em>cp</em>. W tym
+        podrozdziale sobie to zobrazujemy. Nasz plik testowy w katalogu
+        <em>/tmp/testsedir1</em> prezentuje się z następującymi atrybutami:
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -lZ /tmp/testsedir1/testsefile2 
+-rw-r--r--. 1 user user user_u:object_r:public_content_t:s0 0 08-06 12:34 /tmp/testsedir1/testsefile2
+</pre>
+      <p>
+        Teraz jeśli przekopiuje go z pomocą polecenia <em>cp</em> do katalogu
+        <em>/var/local</em> jego atrybuty będą prezentować się w następujący
+        sposób.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -ldZ /var/local/testsefile2 
+-rw-r--r--. 1 root root unconfined_u:object_r:var_t:s0 0 08-06 14:36 /var/local/testsefile2
+</pre>
+      <p>
+        Jak widzimy kontekst uległ zmianie. Jeśli jest to dla nas ważne z
+        pewnych względów, to aby temu zapobiec należy używać opcji
+        <em>--preserve=context</em>. Teraz usunę wcześniej skopiowany plik
+        następnie skopiuje go jeszcze raz tym raz wykorzystując do tego
+        wspomnianą opcję.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo cp --preserve=context /tmp/testsedir1/testsefile2 /var/local/
+[user@server10 ~]$ ls -ldZ /var/local/testsefile2 
+-rw-r--r--. 1 root root user_u:object_r:public_content_t:s0 0 08-06 14:40 /var/local/testsefile2
+</pre>
+      <p>
+        Jak widzimy, w tym przypadku kontekst nie uległ zmianie. Ta opcja tyczy
+        się wyłącznie kopiowania, ponieważ przenoszenie nie zmienia kontekstu.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo mv /tmp/testsedir1/testsefile2 /var/local/
+[user@server10 ~]$ ls -ldZ /var/local/testsefile2
+-rw-r--r--. 1 user user user_u:object_r:public_content_t:s0 0 08-06 12:34 /var/local/testsefile2
+</pre>
+      <h3 id="21.2.8.changebooleans">21.2.8. Zmiana wartości logicznych SELinux</h3>
+      <p>
+        Zabierając się za zmianę wartości logicznych <em>SELinux</em> warto,
+        na początku upewnić się jaki stan mają wartości. Możemy to zrobić
+        za pomocą trzech różnych narzędzi. Na potrzeby przykładu wybrałem 
+        wartość <em>use_nfs_home_dirs</em>. Poniżej znajdują się trzy możliwe
+        sposoby na sprawdzenie stanu tej wartości.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo semanage boolean -l | grep 'use_nfs_home_dirs'
+use_nfs_home_dirs              (wyłączone,wyłączone)  Allow use to nfs home dirs
+[user@server10 ~]$ sudo getsebool -a | grep 'use_nfs_home_dirs'
+use_nfs_home_dirs --&gt; off
+[user@server10 ~]$ sudo sestatus -b | grep 'use_nfs_home_dirs'
+use_nfs_home_dirs                           off
+</pre>
+      <p>
+        Najlepszym sposóbem wydaje mi się, że jest użycie pierwszego polecenia,
+        gdyż domyślnie zwraca więcej informacji. W nawiasie wyjścia tego 
+        polecenia
+        możemy zauważyć dwa stany pierwszy z nich to stan obecny,
+        natomiast drugi to stan pobrany z polityki.
+      </p>
+      <p>
+        Aby zmienić stan wartości logicznej należy użyć polecenia
+        <strong>setsebool</strong>, jako argument to polecenie przyjmuje
+        nazwę wartości oraz stan, w tym przypadku 0 lub 1.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo setsebool use_nfs_home_dirs 1
+[sudo] hasło użytkownika user: 
+[user@server10 ~]$ sudo semanage boolean -l | grep 'use_nfs_home_dirs'
+use_nfs_home_dirs              (włączone,wyłączone)  Allow use to nfs home dirs
+</pre>
+      <p>
+        Teraz ta wartość jest włączona, ale jeśli uruchomie komputer ponownie,
+        to wartość wróci do stanu określonego w polityce. Jeśli chcemy aby,
+        zmiany były trwałe 
+        należy dodać do wcześniej użytego polecenia opcję <em>-P</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo setsebool -P use_nfs_home_dirs 1
+[user@server10 ~]$ sudo semanage boolean -l | grep 'use_nfs_home_dirs'
+use_nfs_home_dirs              (włączone,włączone)  Allow use to nfs home dirs
+</pre>
+      <p>
+        Teraz stan wartości został ustawiony na stałe. 
+      </p>
+      <h3 id="21.2.9.selinuxmonitoring">21.2.9. Monitorowanie naruszeń SELinux</h3>
+      <p>
+        Nie zależnie od trybu działania <em>SELinux</em>, generuje ostrzeżenia
+        i zapisuje je za pomocą demona <em>auditd</em> do pliku
+        <em>/var/log/audit/audit.log</em> lub przy użyciu <em>rsyslog</em> 
+        do pliku <em>/var/log/messages</em>
+        jeśli demon <em>audit</em> jest niedostępny. Ostrzeżenia generowane są
+        podczas odmowy dostępu i zapisywane wraz z odpowiednimi informacjami
+        w wyżej wymienionych plikach. <em>SELinux</em> analizuje te ostrzeżenia
+        w celach identyfikacji powodu odmowy dostępu. Wyniki tych analiz są
+        zapisywane wraz z możliwymi rekomendacjami jak naprawić napotkamy
+        problem.
+      </p>
+      <p>
+        Za pomocą polecenia <em>sealert</em> wraz z opcją <em>-a</em> możemy
+        sprawdzić podany plik pod kątem występowania ostrzeżeń. Jeśli takowe 
+        wstąpią zostanie nam zwrócony na ten temat raport.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo sealert -a /var/log/audit/audit.log
+100% done
+found 0 alerts in /var/log/audit/audit.log
+</pre>
+      <p>
+        W moim systemie niestety brak alertów.
+      </p>
+      <h3 id="exec21.1">Ćwiczenie 1: Zmiana trybu operacyjnego SELinux</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em> wyłącz <em>SELinux</em> z poziomu
+        pliku konfiguracyjnego, następnie uruchom ponownie komputer i sprawdź
+        stan operacyjny <em>SELinux</em>. Następnie przywróć go z powrotem do
+        trybu <em>enforcing</em> i znów uruchom ponownie komputer. Potwierdź 
+        zmianę trybu za pomocą odpowiedniego polecenia.
+      </p>
+      <h3 id="exec21.2">Ćwiczenie 2: Modyfikacja kontekstu plików</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em>. Utwórz w katalogu <em>/tmp</em>
+        katalog <em>d1</em> zawierający podkatalog <em>d2</em>. Następnie zmień
+        rekurencyjnie kontekst katalogu <em>/tmp/d1</em> ustawiając
+        typ <em>SELinux</em> <em>etc_t</em>. Potwierdź to następnie dodaj
+        zmiany bazy kontekstów.
+      </p>
+      <h3 id="exec21.3">Ćwiczenie 3: Dodawanie portów</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em>, dodaj port 8010 do typu 
+        <em>SELinux</em> dla
+        usługi <em>HTTP</em>. Potwierdź wykonanie tej czynności.
+      </p>
+      <h3 id="exec21.4">Ćwiczenie 4: Kopiowanie plików z zachowaniem kontekstu</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em>, utworz plik o nazwie <em>sef2</em> w
+        katalogu <em>/tmp</em>, wyświetl jego kontekst. Skopiuj go do katalogu
+        <em>/usr</em> z zachowaniem kontekstu, ponownie wyświetl kontekst
+        pliku w katalogu <em>/usr</em> aby upewnić się, że kontekst
+        rzeczywiście się nie zmienił.
+      </p>
+      <h3 id="exec21.5">Ćwiczenia 5: Zmiana stanu wartości logicznej SELinux</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server1</em>, wyświetl stan wartości logicznej
+        <em>ssh_use_tcpd</em> za pomocą polecenia <em>getsebool</em> oraz
+        <em>sestatus</em>. Użyj odpowiedniego polecenia aby zmienić jej stan.
+        Potwierdź to, wyświetlając go na wszystkie trzy sposoby.
+      </p>
+      <h2 id="ch21summary">Podsumowanie</h2>
+      <p>
+        Ten rozdział został poswięcony w pełni podstawom znajomości oraz
+        obsługi mechanizmu <em>SELinux</em>. Poznaliśmy podstawy teoretyczne
+        łącznie wymaganą do rozeznania w temacie terminologią. W dalszej
+        części rozdzialu zapoznaliśmy się w jaki sposób możemy manipulować
+        elementami tego mechanizmu w praktyce. Na koniec poznaliśmy metodę na
+        monitorowanie ostrzeżeń generowanych przez <em>SELinux</em>.
+        W następnym rozdziale zapoznamy się z podstawami tworzenia skryptów
+        powłoki. 
+      </p>
+      <h1 id="22.shellscripts">22. Skrypty powłoki</h1>
+      <p>
+        Skrypty powłoki są to listy poleceń zapisywane w jednym pliku
+        tekstowym. Polecenia zapisane w skryptach są najzwyklejszymi 
+        poleceniami, tak jakbyśmy chcieli wykonać je z poziomu wiersza 
+        polecenia.
+        Skrypty służą głównie automatyzacji nudnych oraz powtarzalnych zadań, 
+        na przykład w systemie należy utworzyć konta dla 100 użytkowników.
+        Skrypty składają się z trzech głownych składników: poleceń/instrukcji,
+        konstrukcji kontroli (tj. konstrukcji warunkowych oraz pętli) i
+        komentarzy, które służą wyłącznie opisowi tego co się dzieje w skrypcie
+        i nie biorą udziału w jego interpretacji. Skrypt powłoki są 
+        <strong>interpretowane</strong> przez powłokę, która jest uruchamiana
+        wraz uruchomieniem skryptu. Rozwijane są użyte w skryptach wyrażania a
+        polecenia są uruchamiane po kolei, jedno po drugim tak jak
+        wpisywalibyśmy je ręczenie. W przypadku błędów powłoka zwróci
+        odpowiedni komunikat oraz numer linii, w której ten błąd wystąpił. 
+      </p>
+      <h2 id="22.1.basicsofshellscripts">22.1. Podstawy skryptów powłoki</h2>
+      <p>
+        Jeśli spytamy się kogo kolwiek jak jest najlepsza metoda nauki jakiegoś
+        języka programowania, zapewne usłyszymy kilka zdań, które można 
+        streścić
+        do: czytaj, zrozum, pisz, powtórz. Tak może być i w tym przypadku.
+        Obecnie skrypty powłoki <em>BASH</em> uznawane są branży <em>IT</em>
+        jako podstawowe narzędzie do automatyzacji i konstrukcje używane do
+        budowy skryptów uznaje się za język programowania. Zatem zaczniemy od
+        czegoś prostego, skryptu który wpisze nam podstawowe informacje o 
+        systemie.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/sys_info.sh
+     1 #!/bin/bash
+     2 
+     3 # Ten skrypt ma nazwe sys_info.sh i został napisany przez xf0r3m 8 sierpnia 2022
+     4 # Ten skrypt powinien znajdować się w katalogu /usr/local/bin
+     5 # Ten skrypt wyświetla podstawowe informacje o systemie:
+     6 
+     7 echo "Podstawowe informacje o systemie:";
+     8 echo "================================";
+     9 echo;
+    10 echo "Nazwa komputera, informacje o sprzęcie oraz systemie operacyjnym:";
+    11 /usr/bin/hostnamectl;
+    12 echo;
+    13 echo "Obecnie w systemie zalogowani są następujący użytkownicy:";
+    14 /usr/bin/who;
+</pre>
+      <p>
+        Na początku każdego skryptu znajduje się nagłówek, w którym jest
+        ścieżka, wskazująca na program interpretera zawartości skryptu.
+        Nagłówek zaczyna się od specjalnego typu kometarza jakim jest
+        <strong>shebang</strong> (<strong>#!</strong>). W tym przypadku jest
+        wskazaniem na program <code class="code-inline">bash</code> w katalogu
+        <code class="code-inline">/bin</code>. W ten sposób wskazujemy, że
+        zawartością tego pliku będzie skrypt powłoki <em>BASH</em>. Kolejnymi
+        elementami skryptu są komentarze (zwykłe). Komentarz poprzedzony jest
+        tylko i wyłącznie krzyżykiem (<strong>#</strong>), w komentarzach
+        najczęściej umieszczane są wyjaśnienia bardziej skomplikowanych 
+        konstrukcji lub toku myślenia programisty. Na początku skryptu
+        umieszcza się bardziej informacyjne treści jak nazwę skryptu, imię,
+        nazwisko, bądź pseudomnim autora; date jego wytworzenia; domyślną
+        lokalizacje; krótki opis co on robi oraz przykłady użycia. W dalszej
+        części przykładu znajdują się już właściwe polecenia. Polecenie
+        <code class="code-inline">echo</code> służy do wypisywania na
+        <em>stdout</em> tego co zostanie podane jako argument polecenia. W
+        skryptach to polecenie służy do wyświetlania informacji w terminalu.
+        Później znajdują się polecenia, które odpowiadają za czynności, do
+        których skrypt został stworzony. Zwrócimy uwagę na to, że
+        są one zapisane w postaci plików, które rzeczywiście z tego polecenia
+        są odpowiedzialne. Ten zapis zapewnia, że napewno zostanie uruchmiony
+        ten program, a nie np. jakiś alias lub polecenie wbudowane. 
+      </p>
+      <p>
+        <code class="code-inline">hostnamectl</code> uruchomiony bez żadnych
+        argumentów, zwróci podsumowanie na temat używanego sprzętu oraz
+        systemu operacyjnego. Natomiast polecenie
+        <code class="code-inline">who</code> wyświetla zalogowanych 
+        użytkowników.
+      </p>
+      <p>
+        Dobrym miejscem na nasze skrypty jest katalog <em>/usr/local/bin</em>.
+        Prze co będzie nam łatwiej je uruchamiać, ponieważ ten katalog znajduje
+        się w ścieżce wyszukiwania poleceń każdego użytkownika. Niestety zapis 
+        do tego katalogu wymaga podniesienia uprawnień.
+        Po zapisaniu takie skryptu jeśli zwrócimy uwagę na jego atrybuty,
+        brakuje w nich bitu wykonania a on jest niezbędny aby można było taki
+        program uruchomić.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ ls -l /usr/local/bin/sys_info.sh
+-rw-r--r--. 1 root root 494 08-08 08:38 /usr/local/bin/sys_info.sh
+</pre>
+      <p>
+        Bit nadamy każdej z grupie, żebyśmy mogli uruchomić go jako zwykły
+        użytkownik. Do nadania bitu użyjemy polecenie <em>chmod</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sudo chmod +x /usr/local/bin/sys_info.sh
+[user@server10 ~]$ ls -l /usr/local/bin/sys_info.sh
+-rwxr-xr-x. 1 root root 494 08-08 08:38 /usr/local/bin/sys_info.sh
+</pre>
+      <p>
+        Teraz wszyscy mogą uruchomić ten plik, a z racji tego iż znajduje się
+        on na ścieżce wyszukiwania poleceń wystarczy, że podamy w wierszu
+        polecenia nazwę pliku.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ sys_info.sh 
+Podstawowe informacje o systemie:
+================================
+
+Nazwa komputera, informacje o sprzęcie oraz systemie operacyjnym:
+ Static hostname: server10.example.com
+       Icon name: computer-vm
+         Chassis: vm 🖴
+      Machine ID: 301347671a7c47a5934351c451479d32
+         Boot ID: bb68cbe389874bebaa4cf60693187c89
+  Virtualization: kvm
+Operating System: Red Hat Enterprise Linux 9.0 (Plow)     
+     CPE OS Name: cpe:/o:redhat:enterprise_linux:9::baseos
+          Kernel: Linux 5.14.0-70.13.1.el9_0.x86_64
+    Architecture: x86-64
+ Hardware Vendor: Red Hat
+  Hardware Model: KVM
+
+Obecnie w systemie zalogowani są następujący użytkownicy:
+user     pts/0        2022-08-08 08:28 (192.168.122.1)
+</pre>
+      <h3 id="22.1.1.scriptdebuging">22.1.1. Debugowanie skryptu</h3>
+      <p>
+        Jeśli w skrypcie występuje jakiś problem możemy uruchomić go w trybie
+        debugowania. Taki tryb dostępny jest albo poprzez dodanie do nagłówka
+        skryptu opcji <em>-x</em> lub uruchomienia skryptu za pomocą polecenia
+        <strong>bash</strong> wraz z opcją <em>-x</em>. W tym trybie będą 
+        wyświetlane wykonywane koleno polecenia wraz z rozwinięciami wyrażeń,
+        czy przypisywane wartości zmiennym. Osobiście jako, że <em>BASH</em> 
+        jest
+        moim podstawowym językiem to uważam, że ta opcja jest szczególnie
+        przydatna oczywiście w bardziej zaawansowanych skryptach. Poniżej
+        znajduje się wcześniej analizowany skrypt uruchomiony w trybie
+        debugowania.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ bash -x /usr/local/bin/sys_info.sh
++ echo 'Podstawowe informacje o systemie:'
+Podstawowe informacje o systemie:
++ echo ================================
+================================
++ echo
+
++ echo 'Nazwa komputera, informacje o sprzęcie oraz systemie operacyjnym:'
+Nazwa komputera, informacje o sprzęcie oraz systemie operacyjnym:
++ /usr/bin/hostnamectl
+ Static hostname: server10.example.com
+       Icon name: computer-vm
+         Chassis: vm 🖴
+      Machine ID: 301347671a7c47a5934351c451479d32
+         Boot ID: bb68cbe389874bebaa4cf60693187c89
+  Virtualization: kvm
+Operating System: Red Hat Enterprise Linux 9.0 (Plow)     
+     CPE OS Name: cpe:/o:redhat:enterprise_linux:9::baseos
+          Kernel: Linux 5.14.0-70.13.1.el9_0.x86_64
+    Architecture: x86-64
+ Hardware Vendor: Red Hat
+  Hardware Model: KVM
++ echo
+
++ echo 'Obecnie w systemie zalogowani są następujący użytkownicy:'
+Obecnie w systemie zalogowani są następujący użytkownicy:
++ /usr/bin/who
+user     pts/0        2022-08-08 08:28 (192.168.122.1)
+</pre>
+      <p>
+        Linie oznaczone plusem, są poleceniami zapisanymi w skrypcie. Pod nimi
+        znajduje się wynik działania tego polecenia.
+      </p>
+      <h3 id="22.1.2.scriptsvariables">22.1.2. Zmienne</h3>
+      <p>
+        Jak pamiętamy albo nie z rozdziału o powłoce <em>BASH</em>, dostępne są
+        dwa rodzaje zmiennych. Zmienne powłoki nazywane także zmiennymi 
+        prywatnymi lub lokalnymi, mogą być wykorzystywane w skryptach, nie
+        tylko w obsłudze wiersza polecenia. W skryptach możemy również uzyskać
+        dostęp do zmiennych środowiskowych.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/use_var.sh
+     1 #!/bin/bash
+     2 
+     3 echo "Ustawienie zmiennej powłoki";
+     4 echo "===========================";
+     5 SYSNAME="server10.example.com";
+     6 echo "Nazwa komputera tej maszyny to: $SYSNAME";
+</pre>
+      <p>
+        W powyższym skrypcie utworzyłem jedną zmienną której nadałem
+        przedstawioną wartość a następnie odwołałem się do niej w poleceniu
+        <em>echo</em>. Warto tutaj też wspomnieć o tym, że każdy skrypt
+        uruchamiany jest jako oddzielny proces powłoki <em>BASH</em> -
+        uruchamiany jest w podpowłoce. Zmienne zdefiniowane w skrypcie nie
+        będą dostępne, kiedy skończy on swoje działanie (chyba że do wykonania
+        skryptu użyjemy polecenia <strong>source</strong>).
+      </p>
+      <p>
+        Dostęp do zmiennych środowiskowych wymaga jedynie odwołnia się do nich.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/pre_env.sh 
+     1 #!/bin/bash
+     2 
+     3 echo "Lokalizacja mojej powłoki znajduje się: ";
+     4 echo $SHELL;
+     5 echo "Jestem zalogowany w systemie jako: $LOGNAME";
+</pre>
+      <p>
+        W bardziej zaawansowanych skryptach pożądane jest aby przechować wynik
+        działania jakiegoś polecenia lub polecenia potokowego w zmiennej, żeby
+        można było go użyć do różnych celów. Wynik działania tego polecenia
+        może trafić do zmiennej za sprawą 
+        <strong>podstawienia polecenia</strong>. Poniżej
+        znajduje się skrypt, w którym pokazano dwa sposoby na podstawienie
+        polecenia do zmiennej.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/cmd_out.sh 
+     1 #!/bin/bash
+     2 
+     3 SYSNAME=$(hostname);
+     4 KERNVER=`uname -r`;
+     5 
+     6 echo "Nazwa komputera to: $SYSNAME";
+     7 echo "Wersja jądra to: $KERNVER";
+</pre>
+      <p>
+        Jak widzimy podstawienie polecenia możemy dokonać na dwa sposoby
+        za pomocą nawiasów poprzedzonych znakiem dolara (<strong>$()</strong>)
+        lub za pomocą ukośnego apostrofu (<strong>``</strong>).  Ten skrypt
+        przechowuje w nazwę komputera w zmiennej
+        <code class="code-inline">SYSNAME</code> oraz wersję jądra w zmiennej
+        <code class="code-inline">KERNVER</code>. Te informacje zostały
+        zdefiniowane w zmiennych za pomocą mecanizmu podstawienia polecenia,
+        następnie zostały on wyświetlone przy użyciu polecenia <em>echo</em>.
+      </p>
+      <h3 id="22.1.3.shellparameters">22.1.3. Parametry powłoki</h3>
+      <p>
+        Chcąc przekazać jakieś informacje do skryptu z zewnątrz, możemy
+        wykorzystać mechanizm <strong>parametrów powłoki</strong>. Wywołując 
+        jakieś polecenie
+        w wierszu polecenia, zazwyczaj zapisujemy jego nazwę. To jest parametr
+        powłoki. Wśrod parametrów powłoki możemy wyróżnić takie rzeczy jak
+        zmienne, parametry specjalne oraz parametry pozycjne. Na potrzeby tego
+        materiału zajmiemy się tylko parametrami pozycyjnymi oraz obsługującymi
+        je parametrami specjalnymi. Nazwa polecenia lub skryptu jest
+        pierwszym parametrem pozycyjnym. Każdy kolejny argument 
+        zapisany po nazwie polecenia to kolejny parametr pozycyjny. Parametry 
+        pozycyjne są liczone od zera. Możemy odwołać się do nich podając po 
+        znaku dolara numer parametru. Parametrów
+        pozycyjnych może być wiele. Przy czym, aby odwołać się do parametru
+        powyżej 9 należy umieść numer parametru w nawiasach klamrowych np.
+        (<strong>${11}</strong>). Poniżej znajduje się skrypt oraz jego
+        wywołanie, który obrazuje przekazanie parametrów do skryptu.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/cmd_line_arg.sh 
+     1 #!/bin/bash
+     2 
+     3 echo "Do skryptu wprowadzono $# argumenty pozycyjne";
+     4 echo "Są nimi kolejno: $*";
+     5 echo "Pierwszym argument jest: $1";
+     6 echo "Identyfikator powłoki uruchamiającej ten skrypt to: $$";
+
+[user@server10 ~]$ /usr/local/bin/cmd_line_arg.sh test test2 test3 1 2 3 4 5 6 7 8 9 0
+Do skryptu wprowadzono 13 argumenty pozycyjne
+Są nimi kolejno: test test2 test3 1 2 3 4 5 6 7 8 9 0
+Pierwszym argument jest: test
+Identyfikator powłoki uruchamiającej ten skrypt to: 1874
+</pre>
+      <p>
+        W skrypcie odwołano się do drugiego parametru pozycjnego, czyli do
+        argumentu o numerze 1 (linia: 5). W skrypcie
+        użyto parametrów specjalnych takich jak: liczba przekazanych argumentów
+        pozycyjnych - (<strong>$#</strong>); wszystkie przekazane argumenty -
+        (<strong>$*</strong>) oraz numer <em>PID</em> podpowłoki, która
+        jest odpowiedzialna za wykonanie tego skryptu - (<strong>$$</strong>).
+      </p>
+      <p>
+        Chcąc używać po kolei parametrów pozycyjnych, musimy tak też je zapisać
+        w skrypcie, a co jeśli ilość tych zmiennych nie będzie nam
+        znana. W tym przypadku wówczas możemy przesuwać wszystkie parametry
+        o jeden w lewo. Jeśli użyjemy wartość drugiego parametru pozycjnego
+        (<em>$1</em>) i nie będzie nam już ona potrzebna, możemy użyć
+        polecenia <strong>shift</strong>, które przesunie wszystkie parametry
+        o jeden w lewo (domyślnie, ponieważ polecenie to przyjmuje argument w postaci
+        liczby, o ile wartości przesunąć parametry). Dlatego też wartość
+        trzeciego parametru przejdzie na drugą pozycję, czwartego na trzecią
+        itd. Po użyciu tego polecenia oryginalna wartość drugie parametru
+        zostanie utracona. Poniżej znajduje się skrypt, w którym zobrazowano
+        działanie tego polecenia.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/cmd_line_arg_shift.sh
+     1 #!/bin/bash
+     2 
+     3 echo "Do skryptu wprowadzono $# argumenty pozycyjne";
+     4 echo "Są nimi kolejno: $*";
+     5 echo "Pierwszym argument jest: $1";
+     6 echo "Identyfikator powłoki uruchamiającej ten skrypt to: $$";
+     7 shift;
+     8 echo "Nowym pierszym argumentem po pierwszym przesunięciu jest: $1";
+     9 shift;
+    10 echo "Nowym pierwszy argumentem po drugim przesunięciu jest: $1";
+</pre>
+      <p>
+        Jak widzimy przy użyciu polecenia <code class="code-inline">shift</code>
+        nie musimy używać innych odwołań do parametrów poza odwołaniem do
+        drugiego (parametr o numerze 1).
+      </p>
+      <h2 id="22.2.logicalconstructs">22.2. Konstrukcje logiczne w skryptach powłoki</h2>
+      <p>
+        Konstrukcje logiczne nie tylko w skryptach powłoki mają za zadanie
+        warunkować na podstawie wyrażeń logicznych wykonanie pewnych bloków
+        kodu. Konstrukcje logiczne kontolują przepływ wykonania poleceń w
+        skryptach. W <em>BASH</em> możemy spotkać z dwoma kontrukcjami
+        logicznymi: konstrukcją <strong>if-then-fi</strong> oraz konstrukcją
+        <em>case</em>. Omawianie konstrukcji <em>case</em> wychodzi poza ramy
+        tego materiału, wiec skupimy się tylko <strong>if-then-fi</strong> i
+        jej rozszerzeniach, ale najpierw zaczniemy od przedstawienia czym są
+        <strong>kody wyjściowe</strong> oraz <strong>wyrażenia warunkowe</strong>.
+      </p>
+      <h3 id="22.2.1.exitcodes">22.2.1. Kody wyjściowe</h3>
+      <p>
+        Każde polecenie uruchomione w powłoce po zakończeniu pracy, nie ważne
+        czy pomyślnie, czy nie zwraca do powłoki tzw. <strong>exit code</strong>
+        - kod wyjściowy. Możemy użyć tych kodów w wyrażeniach warunkowych aby
+        mieć pewność, że działanie polecenia uruchomionego w poprzedniej linii
+        zakończyło się sukcesem i można kontynuować wykonywanie przez skrypt
+        kolejnych zadań. Kod wyjściowy poprzedniego polecenia znajduje się 
+        w specjalnym parametrze powłoki <strong>$?</strong>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ pwd
+/home/user
+[user@server10 ~]$ echo $?
+0
+[user@server10 ~]$ man
+Jakiej strony podręcznika potrzebujesz?
+For example, try 'man man'.
+[user@server10 ~]$ echo $?
+1
+</pre>
+      <p>
+        Pierwsze polecenie, którego wykonanie zakończyło sie sukcesem zwróciło
+        kod wyjściowy <code class="code-inline">0</code>. Natomiast w przypadku
+        polecenia <code class="code-inline">man</code> przy którym zapomniałem
+        o podaniu argumentu zwróciło wartość <code class="code-inline">1</code>.
+        W przypadku zastrzeżeń co do poprawnego wykonania zwracanym kodem 
+        wyjściowym jest najczęściej wartość niezerowa, nie zawsze jest to 1. 
+        Te wartości mogą być różne i zależne od programu.
+      </p>
+      <p>
+        Dlaczego mówie o kodach wyjściowych w przypadku konstrukcji logicznych,
+        otóż powody są dwa. Można użyć kodów wyjściowych do budowania
+        warunków, oraz konstrukcja <em>if-then-fi</em> podejmuje decyzje na
+        podstawie kodu wyjściowego wyrażenia warunkowego. Zatem jeśli wyrażenie
+        zwróci 0, to wówczas wykona się blok kodu zapisany po instrukcji
+        <em>then</em>.
+      </p>
+      <h3 id="22.2.2.conditionalexpressions">22.2.2. Wyrażenia warunkowe</h3>
+      <p>
+        Zadaniem wyrażenia warunkowego jest obliczenie równania logicznego.
+        Na przykład czy: 3 &lt; 4. Wynikiem takiego równia jest 1, czyli 
+        <strong>prawda</strong>, jeśli odwrócimy operandy równiania wówczas
+        wówczas otrzymamy 0 czyli <strong>fałsz</strong>. Kiedy wyrażenie
+        warunkowe obliczy prawdę wówczas zwraca kod wyjścia równy 0, a w
+        przeciwnym wypadku jest 1. Elementami powłoki odpowiedzialnymi za 
+        wyrażenia warukowe jest polecenie <em>test</em> oraz rozszerzenie
+        nawiasu kwadratowego (<strong>[]</strong>) i to tego rozszerzenia
+        będziemy używać w konstrukcjach warunkowych. 
+        Na stronie podręcznika polecenia <em>BASH</em> w sekcji
+        <em>CONDITIONAL EXPRESSIONS</em> znajdują się wszystkie dostępne 
+        operatory wyrażeń warunkowych jakie możemy użyć w skryptach. 
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu</strong><br />
+        Bardzo ważna jest dobra znajomość instrukcji logicznych oraz ich
+        operatorów.
+      </p>
+      <h3 id="22.2.3.ifthenfi">22.2.3. Konstrukcja if-then-fi</h3>
+      <p>
+        Za pomocą konstrukcji <strong>if-then-fi</strong> możemy warunkować
+        na podstawie kodu wyjściowego wykonanie poleceń zapisanych w
+        konstrukcji. Poniżej znajduje się przykładowy skrypt zawierający
+        tę konstrukcję.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/if_then_fi.sh
+     1 #!/bin/bash
+     2 
+     3 if [ $# -ne 2 ]; then 
+     4         echo "Błąd. Nie poprawna liczba podanych argumentów";
+     5         echo "Użycie $0 plik_zrodlowy plik docelowy";
+     6         exit 2;
+     7 fi
+     8 echo "Skrypt zakończył swoje działanie";
+</pre>
+      <p>
+        Konstrukcję rozpocznamy od słowa kluczowego <strong>if</strong>
+        następnie podajemy polecenie lub wyrażenie warunkowe, którego kod
+        wyjściowy będzie decydować czy wykonać polecenia zawarte po słowie
+        klczowym <strong>then</strong> na przykładzie są to linie od 4 do 6.
+        Konstrukcja kończy się słowem kluczowym <strong>fi</strong>, które
+        musi być zawarte inaczej próba uruchomienia takiego skryptu zakończy 
+        się błędem. Jako 
+        ciekawostkę podam, że blok zawarty po słowie <em>then</em> konczy się
+        poleceniem <strong>exit</strong>, dzięki któremu możemy zakończyć
+        działanie skryptu z określonym kodem wyjściowym.
+      </p>
+      <p>
+        Na zamieszczonym przykładzie użyłem do przedstawienia warunku 
+        rozszerzenia nawiasu kwadratowego, w ktorym sprawdzam czy podano
+        dokładnie dwa paramentry pozycjne, operator którego użyłem
+        <code class="code-inline">-ne</code>, który sprawdza czy lewy operand
+        jest nierówny prawemu. Jeśli tak, to kod wyjściowy warunku będzie
+        równy 0 i dojdzie do wykonania poleceń, co tym przypadku oznacza, że
+        podaliśmy jeden lub więcej niż dwa parametry pozycyjne podczas
+        uruchamiania tego skryptu.
+      </p>
+      <h3 id="22.2.4.ifthenelsefi">22.2.4. Konstrukcja if-then-else-fi</h3>
+      <p>
+        Ta konstrukcja jest rozszerzeniem standardowej konstrukcji <em>if</em>.
+        Zawiera ona dodatkowy blok <strong>else</strong>, który będzie
+        wykonywany w momencie gdy
+        kod wyjściowy warunku/polecenia będzie niezerowy.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/if_then_else_fi.sh
+     1 #!/bin/bash
+     2 
+     3 if [ $1 -gt 0 ]; then
+     4         echo "$1 jest wartością dodatnią";
+     5 else
+     6         echo "$1 jest wartością ujemną";
+     7 fi
+</pre>
+      <p>
+        W tym przypadku warunek w postaci rozszerzenia nawiasów kwadartowych
+        (najpopularniejsza forma warunków w skryptach powłoki) sprawdza czy
+        wartość podana jako drugi parametr pozycyjny jest większa od 0. Jeśli
+        tak, to wykonane zostanie polecenie znajdujące się w po słowie
+        <code class="code-inline">then</code> a jeśli nie to polecenie po
+        słowie kluczowym <code class="code-inline">else</code>.
+      </p>
+      <h3 id="22.2.5.iftheneliffi">22.2.5. Konstrukcja if-then-elif-fi</h3>
+      <p>
+        Rozszerzenie konstrukcji <em>if</em> o słowo kluczowe 
+        <strong>elif</strong> pozwala na zdefiniowane kolejnego warunku. W
+        przypadku konstrukcji <strong>if-then-elif-fi</strong>, warunków
+        możebyć nieskończeniei wiele i dodatkowo możemy zakończyć całą
+        konstrukcję blokiem <em>else</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/if_then_elif_fi.sh 
+     1 #!/bin/bash
+     2 
+     3 if [ $1 -gt 0 ]; then
+     4         echo "$1 jest dodatnią wartością.";
+     5 elif [ $1 -lt 0 ]; then
+     6         echo "$1 jest ujemną wartością.";
+     7 elif [ $1 -eq 0 ]; then
+     8         echo "Podana wartość to 0.";
+     9 else
+    10         echo "Podano wartość, która nie jest cyfrą";
+    11 fi
+</pre>
+      <p>
+        Na powyższym przykładzie drugi parametr pozycyjny poddawany jest wielu
+        warunkom. Początkowy warunek sprawdza czy jest on większy od 0 
+        (operator <strong>-gt</strong>), następnie czy może jest mniejszy od
+        0 (operator <strong>-lt</strong>) i ostatni czy jest on równy 0
+        (operator <strong>-eq</strong>). W bloku <em>else</em> znajduje się
+        komunikat mówiący, że podana wartość nie jest liczbą, będzie on
+        wykonywany gdy jako argument podamy literę lub znak specjalny.
+        Podczas uruchomienia tego skryptu wraz z literowym argumentem możemy
+        zauważyć błąd. Ten błąd jest generowany z tego względu, iż wymienione
+        wyżej operatory są przeznaczone dla liczb całkowitych, a litera jest
+        znakiem.
+      </p>
+      <h2 id="22.3.loop">22.3. Konstrukcje pętli</h2>
+      <p>
+        Za pomocą konstrukcji pętli możemy wykonywać ten sam blok poleceń dla
+        określonych, zmienianych w trakcie działania bloku pętli zmiennych.
+        Zmienne w trakcie działania pętli najczęściej są 
+        <strong>iterowane</strong> - ich wartość zmienia się o jeden lub o
+        jakąś stałą określoną wartość. W <em>BASH</em>-u dostępne są trzy
+        rodzaje pętli: <strong>for-do-done</strong>, <em>while-do-done</em> 
+        oraz <em>until-do-done</em>. W tym materiale skupimy się tylko na
+        pętli <em>for-do-done</em>.
+      </p>
+      <h3 id="22.3.1.forloop">22.3.1. Konstrukcja pętli for-do-done</h3>
+      <p>
+        Pętla <em>for</em> jest inną pętlą niż te dwie pozostałe, gdyż działa
+        ona na określonej liście wartości, które są kolejno przypisywane
+        zmiennej pętli. Pętla działa do momentu, aż wyczerpią się wszystkie
+        elementy na liście. Poniżej znajduje się przykład skryptu w którym
+        użyłem pętli <em>for</em>.
+      </p>
+<pre class="code-block">
+[user@server10 ~]$ cat -n /usr/local/bin/for_do_done.sh 
+     1 #!/bin/bash
+     2 
+     3 count=0;
+     4 for LETTER in {A..Z}; do
+     5         count=$((count + 1));
+     6         echo "$count literą alfabetu jest [${LETTER}]";
+     7 done
+</pre>
+      <p>
+        Pętla zaczyna się od słowa kluczowego 
+        <code class="code-inline">for</code> następnie zapisywana jest zmienna
+        pętli (<code class="code-inline">LETTER</code>) po słowie kluczowym
+        <code class="code-inline">in</code> występuje lista elementów, na
+        której operuje pętla (<code class="code-inline">{A..Z}</code>) zwróćmy
+        uwagę na to, iż możemy definiować tutaj zakresy co pokazano na
+        przykładzie. Dla celów tego skryptu jeszcze przed pętlą utworono
+        zmienną, która jest w tym przypadku jej licznikiem. Jest ona bowiem
+        iterowana na początku bloku pętli, za pomocą wyrażenia arytmetycznego
+        (<strong>$(())</strong>), w tym wyrażeniu nie odwołujemy się do
+        zmiennej tylko podajemy jej nazwę. Odwołanie nastąpi automatycznie
+        podczas interpretacji tego wyrażenia. Następnie wyświetlany jest
+        komunikat, zawierający licznik oraz zmienną pętli. Pętla wypisze
+        wszystkie litery alfabetu łacińskiego, poprzedzając je numerem w
+        kolejności.
+      </p>
+      <p>
+        Aby lepiej zobrazować sobie działanie pętli możemy uruchomić ten
+        skrypt w trybie debugowania.
+      </p>
+      <h3 id="exec22.1">Ćwiczenie 1: Poprawienie skryptu</h3>
+      <p>
+        Jako użytkownik z możliwością podniesienia uprawnień na maszynie
+        oznaczonej jako <em>server10</em>. Popraw skrypt z podrozdziału
+        o konstrukcji <em>if-then-elif-fi</em>, tak aby nie wyświetlał błędu.
+        Możesz posłużyć się stroną podręcznika powłoki <em>BASH</em> oraz
+        trybem debugowania.
+      </p>
+      <h2 id="ch22summary">Podsumowanie</h2>
+      <p>
+        W tym rozdziale poznaliśmy podstawy tworzenie skryptów powłoki.
+        Dowiedziliśmy się jaką budowę ma skrypt powłoki oraz poznaliśmy ich
+        podstawowe elementy. Poznaliśmy konstrukcje warunkowe oraz prostą
+        konstrukcję pętli jąką jest pętla <em>for</em>. Jeśli domyślnie nie
+        korzystamy z powłoki <em>BASH</em> przestawione tutaj przykłady po
+        drobnych przeróbkach będą działać na pozostałych powłokach Uniksa.
+        W następnym już ostatnim rozdziale zapoznamy się z mechanizmem
+        konteneryzacji dostępnym w <em>RHEL</em>.
+      </p>
+      <h1 id="23.containers">23. Kontenery</h1>
+      <p>
+        <strong>Kontener</strong> to sposób na uruchomienie aplikacji w
+        odrębnym środowisku dzięki czemu, może ona działać i wykonywać swoje
+        zadania bez wpływu na inne procesy przy zachowaniu jak największej
+        oszczędności zasobów systemu. Kontenery dostarczają do systemu
+        właściwą aplikację wraz cały środowiskiem niezbędnym do jej działania,
+        wygląda ona tak samo jakby była zainstalowana na fizycznym serwerze.
+        Aplikacja uruchamiana w kontenerze nazywana jest
+        <strong>aplikacją konteneryzowaną</strong>.
+      </p>
+      <p>
+        Kontenery do swojego działania wykorzystują funkcje jądra Linux,
+        takie jak <strong>grupy kontrolne</strong> (przydzielanie zasobów
+        procesom), <strong>przestrzeń nazw</strong> (udostępnienie zasobów
+        systemowych takich jak interfejsy sieciowe) oraz moduł
+        <strong>seccomp</strong> i <strong>SELinux</strong>, które odpowiadają
+        za kontrolowanie dostępu procesów. Wykorzystując te komponenty 
+        kontenery 
+        zapewniają w pełni kontrolowane środowisko o wysokim stopniu
+        bezpieczeństwa.
+      </p>
+      <p>
+        Korzystanie z kontenerów przynosi ze sobą wiele korzyści takich jak
+        izolacja aplikacji w kontenerach, małe powiązanie z system w którym
+        kontener działa, niezależność kontenerów wobec siebie czy
+        mniejsze obciążenie systemu. Korzyści jest naprawdę bardzo dużo,
+        dlatego też konterneryzacja wypiera wirtualizację, ale oczywiście to
+        wszystko zależy od konkretnego przypadku.
+      </p>
+      <p>
+        Przy wyborze miejsca docelowego dla konternerów możemy zastanawiać się
+        nad fizycznym serwerem albo maszyną wirtualna. Korzystanie z maszyn
+        wirtualnych wprowadza dodatkową warstwę <em>hipernadzorcy</em>, który
+        je kontroluje. W przypadku jeśli kontenery mają swiadczyć usługi, mogą
+        on spokojnie rezydować na fizycznym serwerze, bez dodatkowych
+        komplikacji. Więc wybór wydaje się dość łatwy.
+      </p>
+      <p>
+        Kontenery są rozprowadzane na zasadzie <strong>obrazów</strong>
+        (ang. <em>images</em>) zawierających całe środowisko określonej
+        aplikacji, dzięki czemu może poprawnie pracować w izolowanym
+        środowisku. Mechnizmy konteneryzacji dostarczane wraz z
+        <em>RHEL</em>, przestrzegają zasad <em>Inicjatywy Otwartych
+        Kontenerów - OCI</em>, dzięki czemu użytkownicy mogą tworzyć obrazy o
+        przemysłowych standardach. Do zarządzania obrazami <em>OCI</em>
+        wykorzystywane są takie narzędzia <em>Docker</em> oraz dostarczany
+        wraz z <em>Red Hat</em> <strong>podman</strong>. Obrazy <em>OCI</em>
+        korzystają z kontroli wersji, tak więc możemy skorzystać z
+        niekoniecznie najnowszej wersji, a pobrany obraz może być
+        wykorzystywany w więcej niż jednym kontenerze.
+      </p>
+      <p>
+        Obrazy konternerów przechowywane są w <strong>rejestrach</strong>.
+        Rejestry mogą być <strong>prywatne</strong> i aby pobrać obraz należy 
+        się zalgować lub mogą być ogólno dostępne, <strong>publiczne</strong>
+        i każdy może pobierać z nich obrazy. W internecie dostępnych jest kilka
+        rejestrów, z czego tylko trzy z nich wykorzystuje się w 
+        <em>RHEL</em>: <em>Red Hat Container Catalog</em> występujący w dwóch
+        różnych rejestrach
+        oraz <em>Docker Hub</em>. Przyczym tylko <em>Docker Hub</em> jest
+        rejestrem publicznym. Obrazy posiadają swoje nazewnictwo, nazwane
+        <strong>FQIN</strong> (ang. <em>Full Qualified Image Name</em>). Ta
+        nazwa składa się czterech części:
+      </p>
+      <ol>
+        <li><strong>Nazwy rejestru</strong></li>
+        <li><strong>Nazwy właściciela/Nazwy organizacji</strong></li>
+        <li><strong>Nazwy repozytorium</strong></li>
+        <li><strong>Wersji</strong> (opcjonalnie)</li>
+      </ol>
+      <p>
+        Po złożeniu tych elementów ścieżka może wyglądać w następujący sposób:
+        <em>nazwa_rejestru/nazwa_organizacji/nazwa_repozytorium:wersja</em>.
+      </p>
+      <p>
+        Kontenery mogą być uruchamiane za równo przez superużytkownika - 
+        mowimy wtedy o kontenerach <strong>uprzywilejowanych</strong> oraz 
+        przez zwykłych użytkowników - wówczas mówi o kontenerach
+        <strong>nieuprzywilejowanych</strong>. Główną różnicą jest brak
+        możlwości mapowania portów (przekierowania) poniżej portu
+        <strong>1024</strong>. Warto dodać, że uruchamianie kontenerów 
+        uprzywilejowanych może powodować potencjalne problemy z bezpieczeństwem
+        w systemie.
+        Kontenery nieuprzywilejowanene dają możliwość interakcji z nimi z
+        poziomu superużytkownika i jeśli nie będzie takiej potrzeby lepiej
+        korzystać z tego rodzaju kontenerów.
+      </p>
+      <h2 id="23.1.workwithimagesandcontainers">23.1. Praca z obrazami oraz kontenerami</h2>
+      <p>
+        Do pracy z kontenerami <em>RHEL</em> dostarcza dwa narzędzia:
+        wspomniany już wcześniej <strong>podman</strong> oraz
+        <strong>skopeo</strong>. Przyczym wszystkie czynności będą operać się
+        na wykorzystaniu polecenia <em>podman</em>. Polecenie <em>skopeo</em>
+        posłuży nam tylko do pobrania bardziej szczegółowych informacji na 
+        temat dostępnego
+        w rejestrze obrazu. W tym ostatnim rodziale skupimy się na praktyce.
+        Jeśli będzie trzeba coś dopowiedzieć, zostanie to dopisane podczas
+        omawiania danej kwestii. Do rozpoczęcia pracy z konterami, potrzebujemy
+        oprogramowania oraz dostępu do rejestrów <em>Red Hat</em>. Najlepiej
+        więc zarejestrować tę instalację systemu na koncie firmy 
+        <em>Red Hat</em>, wtedy
+        bez problemu będziemy mogli zaktualizować system a następnie
+        zainstalować potrzebne oprogramowanie.
+      </p>
+      <h3 id="23.1.1.registeringredhatsystem">23.1.1. Rejestrowanie systemu Red Hat</h3>
+      <p>
+        Za pomocą konsoli wirtualne również możemy zarejestrować system w sieci
+        <em>Red Hat</em>, do tego służy polecenie 
+        <strong>subscription-manager</strong> wraz z podpoleceniem 
+        <em>register</em>. Polecenie to wydajemy z
+        podniesieniem uprawnień. Do rejestracji potrzebna jest nazwa
+        użytkownika (login) podawany podczas logowania do <em>Red Hat</em>,
+        podajemy ją po opcji <em>--username</em>. Na poniższym przykładzie
+        przedstawiam składnie polecenia oraz zwracane przez nie informacje
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo subscription-manager register --username
+Registering to: subscription.rhsm.redhat.com:443/subscription
+Password: 
+The system has been registered with ID: 12d0865f-3b78-4ce3-93db-b836b50ef879
+The registered system name is: primeb450.morketsmerke.net
+</pre>
+      <p>
+        Moja nazwa użytkownika została ocenzurowana na tym przykładzie, także
+        po opcji <code class="code-inline">--username</code> znajduje się
+        <em>login</em> do sieci <em>Red Hat</em>. Poprawność rejestracji możemy
+        sprawdzić za pomocą polecenia <em>attach</em>.
+        Poniżej pokazałem jak to wygląda w przypadku mojego serwera.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo subscription-manager attach
+[sudo] password for xf0r3m: 
+All installed products are covered by valid entitlements. No need to update subscriptions at this time.
+Installed Product Current Status:
+Product Name: Red Hat Enterprise Linux for x86_64
+Status:       Subscribed
+</pre>
+      <p>
+        Teraz możemy korzystać z repozytoriów sieci <em>Red Hat</em> i na
+        początek radzę zaktualizować system. Jeśli będziemy korzystać z tego
+        systemu w celach innych niż testy jego i jego możliwości oraz
+        zawartości, możemy podłączyć ten system już podczas instalacji.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo dnf update
+[sudo] password for xf0r3m: 
+Updating Subscription Management repositories.
+Red Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)                   2.5 MB/s | 3.6 MB     00:01    
+Red Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)                6.1 MB/s | 9.2 MB     00:01    
+Dependencies resolved.
+...
+</pre>
+      <h3 id="23.1.2.contsoftwareinstallation">23.1.2. Instalacja oprogramowania kontenerów</h3>
+      <p>
+        Moduły <em>RHEL</em> 9 nie są jeszcze dostępne. Pojawią się dopiero w
+        kolejnym mniejszym wydaniu (9.1), ale w repozytoriach znajduje się
+        pakiet, który wraz z zależnościami odpowiada za obsługę kontenerów 
+        w tej wersji systemu <em>Red Hat</em>. Tym pakietem jest
+        <strong>container-tools</strong>. 
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo dnf install container-tools
+[sudo] password for xf0r3m: 
+Updating Subscription Management repositories.
+Red Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)                                        8.2 kB/s | 4.1 kB     00:00    
+Red Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)                                      10 kB/s | 4.1 kB     00:00    
+Dependencies resolved.
+============================================================================================================================
+ Package                Architecture       Version                        Repository                                    Size
+============================================================================================================================
+Installing:
+ container-tools        noarch             1-10.el9                       rhel-9-for-x86_64-appstream-rpms             8.7 k
+Installing dependencies:
+ podman-docker          noarch             2:4.1.1-1.el9_0                rhel-9-for-x86_64-appstream-rpms              42 k
+ podman-remote          x86_64             2:4.1.1-1.el9_0                rhel-9-for-x86_64-appstream-rpms             8.1 M
+ python3-podman         noarch             3:4.0.0-1.el9                  rhel-9-for-x86_64-appstream-rpms             171 k
+ python3-pyxdg          noarch             0.27-3.el9                     rhel-9-for-x86_64-appstream-rpms             108 k
+ python3-toml           noarch             0.10.2-6.el9                   rhel-9-for-x86_64-appstream-rpms              46 k
+ skopeo                 x86_64             2:1.8.0-4.el9_0                rhel-9-for-x86_64-appstream-rpms             6.7 M
+ toolbox                x86_64             0.0.99.3-3.el9_0               rhel-9-for-x86_64-appstream-rpms             2.2 M
+ udica                  noarch             0.2.6-4.el9                    rhel-9-for-x86_64-appstream-rpms              54 k
+
+Transaction Summary
+============================================================================================================================
+Install  9 Packages
+
+Total download size: 17 M
+Installed size: 65 M
+Is this ok [y/N]: 
+</pre>
+      <p>
+        Teraz w systemie dostępne będą takie narzędzia jak <strong>podman</strong>
+        oraz <strong>skopeo</strong>.
+      </p>
+      <h3 id="23.1.3.podmancommand">23.1.3. Polecenie podman</h3>
+      <p>
+        Polecenie <strong>podman</strong> jest podstawowym polecenień związanym
+        z obsługą kontenerów na <em>RHEL</em>. Za jego pomocą będziemy 
+        wykonywać wiekszość czynności związanych z kontenerami. Poniżej
+        znajdują się najczęściej wykorzystywane podpolecenia.
+      </p>
+      <ul>
+        <li><strong>images</strong> - wyświetla listę pobranych obrazów.</li>
+        <li><strong>pull</strong> - pobiera wskazany obraz z rejestru na dysk</li>
+        <li><strong>rmi</strong> - usuwa wskazany obraz.</li>
+        <li><strong>search</strong> - poszukuje obrazów pasujących do podanego
+          słowa kluczowego.</li>
+        <li><strong>attach</strong> - podłącza powłokę pod uruchomiony kontener.</li>
+        <li><strong>exec</strong> - wykonuje polecenie na uruchomionym
+          kontenerze.</li>
+        <li><strong>generate</strong> - generuje plik, np. jednostki 
+          <em>systemd</em> pozwalający na kontrolę kontenera jakby był zwykłą
+          usługą.</li>
+        <li><strong>ps</strong> - wyświetla listę działających kontenerów,
+          dodanie opcji <em>-a</em>, wyświetli listę zatrzymanych kontenerów.</li>
+        <li><strong>rm</strong> - usuwa kontenery.</li>
+        <li><strong>run</strong> - uruchamiana (instaluje) kontenery, jesli 
+          obraz
+          kontenera nie istnieje na dysku zostanie pobrany z rejestru. To
+          podpolecenie posiada kilka opcji, które będziemy poznawać podczas
+          omawiania konkretnych przypadków uruchamiania kontenerów.</li>
+        <li><strong>start/stop/restart</strong> - podstawowe czynności
+          wykonywane na konternerach, takie uruchomienie, zatrzymanie czy
+          ponowne uruchomienie.</li>
+      </ul>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Zrozumienie przedstawionych wyżej podpoleceń oraz swobodne używanie
+        polecenia <em>podman</em> jest kluczowe do wykonania zadań związanych
+        z kontenerami.
+      </p>
+      <h3 id="23.1.4.skopeocommand">23.1.4. Polecenie skopeo</h3>
+      <p>
+        Polecenie <strong>skopeo</strong> służy do obsługi obrazów zarówno tych
+        znajdujących się
+        na dysku, jak i tych, które znajdują się w rejestrach. Nie mniej jednak
+        w tym materiale skupimy się tylko na jednym podpoleceniu jakim jest
+        podpoleceniem <strong>inspect</strong>, które zwraca szczegóły
+        na temat obrazu. 
+      </p>
+      <h3 id="23.1.5.registries.conf">23.1.5. Plik registries.conf</h3>
+      <p>
+        W pliku <em>registries.conf</em> przechowywane są adresy rejestrów,
+        z których możemy pobierać obrazy kontenerów. Plik znajduje się w 
+        katalogu <em>/etc/containers</em> jest on plikem globalnym, a każdy z 
+        użytkowników może przychowywać swoją kopię pliku w katalogu
+        <em>~/.config/containers</em>, ustawienia zawarte w plikach 
+        użytkowników nadpisują
+        te wartości z pliku globalnego, co może być przydatne w przypadku
+        kontenerów nieuprzywilejowanych. Poniżej znajduje się zawartości tego
+        pliku:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ grep -v '^#' /etc/containers/registries.conf 
+
+unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]
+
+short-name-mode = "enforcing"
+</pre>
+      <p>
+        Plik zawiera masę komentarzy wyjaśniających wiele rzeczy. Nas jednak
+        będzie interesować wyłącznie pierwsza linia zawierająca adresy
+        rejestrów. W momencie poszukiwania obrazu polecenie <em>podman</em>
+        odpytuje rejestry w zapisanej kolejności. Oczywiście jeśli jest taka
+        potrzeba możemy dopisać swoje prywatne rejestry do tego pliku.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Podczas egzaminu nie będzie dostępu do sieci, więc prawdopodbnie będzie
+        trzeba ustawić rejestr prywatny znajdujący się w sieci egzaminacyjnej.
+      </p>
+      <h3 id="23.1.6.podmaninfo">23.1.6. Informacje nt. konfiguracji kontenerów w systemie</h3>
+      <p>
+        Pierwszą czynnością jaką poznamy odnośnie kontenerów jest sprawdzenie
+        konfiguracji programu <em>podman</em>, możemy zrealizować to za pomocą
+        podpolecenia <strong>info</strong>. Poniżej znajduje się fragment
+        wyniku działania tego polecenia:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman info
+host:
+  arch: amd64
+  buildahVersion: 1.26.2
+  cgroupControllers:
+  - memory
+  - pids
+  cgroupManager: systemd
+  cgroupVersion: v2
+  conmon:
+    package: conmon-2.1.2-2.el9_0.x86_64
+    path: /usr/bin/conmon
+    version: 'conmon version 2.1.2, commit: 1ed53517f446a779f9d0edafe090ce821a41e255'
+  cpuUtilization:
+    idlePercent: 99.94
+    systemPercent: 0.02
+    userPercent: 0.04
+  cpus: 8
+  distribution:
+    distribution: '"rhel"'
+    version: "9.0"
+  eventLogger: journald
+  hostname: primeb450.morketsmerke.net
+...
+</pre>
+      <p>
+        Polecenie to zwraca masę informacji od architektury przez informacje
+        o zużyciu procesora, informacje o dystrybucji po informacje na temat 
+        pakietów odpowiedzialnych za kontenery w systemie oraz miejsce
+        składowania obrazów. Warto wspomnieć że te informację
+        mogą się różnić kiedy wydamy to polecenie z <em>sudo</em>, wówczas te
+        informacje
+        będą dotyczyć konfiguracji globalnej, przeznaczonej dla kontenerów
+        uprzywilejowanych.
+      </p>
+      <p>
+        Po za tymi informacjami możemy za pomocą podpolecenia 
+        <strong>version</strong> zwrócić wersję polecenia <em>podman</em> oraz
+        kilku dostarczanych wraz z nim składników.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman version
+Client:       Podman Engine
+Version:      4.1.1
+API Version:  4.1.1
+Go Version:   go1.17.12
+Built:        Wed Jul 27 16:26:10 2022
+OS/Arch:      linux/amd64
+</pre>
+      <h2 id="23.2.imagesmgmt">23.2. Zarządzanie obrazami</h2>
+      <p>
+        Jedną z podstawowych czynności jakie możemy wykonać w obrębie
+        kontenerów jest zarządzanie obrazami, czyli: wyszukanie, sprawdzenie
+        szczegółów, pobranie oraz jego usunięcie. Tym zajmiemy się w tym
+        podrozdziale.
+      </p>
+      <p>
+        Za pomocą polecenia <em>podman</em> z podpoleceniem <em>search</em>
+        wyszukamy kontenera systemu bazodanowego <em>MySQL</em>. 
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman search mysql
+registry.redhat.io/rhel8/mysql-80                     This container image provides a containerize...
+registry.redhat.io/rhel9/mysql-80                     rhcc_registry.access.redhat.com_rhel9/mysql-...
+</pre>
+      <p>
+        Te dwa obrazy wydają się najbardziej trafne. Opisy możemy rozwinąć 
+        dodając opcję <em>--no-trunc</em>. W pierwszej kolumnie wyjścia tego
+        polecenia znajduje się <em>FQIN</em> w drugiej zaś opis obrazu. Obraz
+        jest przeznaczony dla <code class="code-inline">rhel9</code> co możemy
+        wywnioskować po napisie znajującym się w drugiej części nazwy obrazu.
+        Aby poznać więcej szczegółów na temat tego obrazu posłużymy się
+        poleceniem <strong>skopeo</strong> wraz podpoleceniem <em>inspect</em>.
+        To polecenie przyjmuje jako argument <em>FQIN</em> poprzedzonym
+        wskazaniem protokołu <em>Docker</em> (<strong>docker://</strong>).
+        Poniżej znajdują się informacje jakie udało się uzyskać poleceniu 
+        <em>skopeo</em> na temat tego obrazu.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ skopeo inspect docker://registry.redhat.io/rhel9/mysql-80
+FATA[0000] Error parsing image name "docker://registry.redhat.io/rhel9/mysql-80": unable to retrieve auth token: invalid username/password: unauthorized: 
+Please login to the Red Hat Registry using your Customer Portal credentials. 
+Further instructions can be found here: https://access.redhat.com/RegistryAuthentication 
+</pre>
+      <p>
+        Jeśli rejestrowaliśmy system za pomocą polecenia 
+        <em>subscription-manager</em> potrzebne może być zalogowanie się za 
+        do rejestrów. Logowania dokonujemy za pomocą polecenia <em>podman</em>
+        wraz podpolecenie <em>login</em> oraz polecenia <em>skopeo</em> wraz
+        podpoleceniem <em>login</em>, przy czym przy poleceniu <em>skopeo</em>
+        należy podać adres rejestru.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo podman login
+[sudo] password for xf0r3m: 
+Username: 
+Password: 
+Login Succeeded!
+
+[xf0r3m@primeb450 ~]$ skopeo login registry.redhat.io
+Username: 
+Password: 
+Login Succeeded!
+</pre>
+      <p>
+        Polecenia zapytaja nas o nazwę użytkownika sieci <em>Red Hat</em> oraz
+        o hasło. Moja nazwa użytkownika została ocenzurowana. Teraz powinniśmy
+        otrzymać interesujące nas informacje na temat żądanego obrazu.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ skopeo inspect docker://registry.redhat.io/rhel9/mysql-80
+{
+    "Name": "registry.redhat.io/rhel9/mysql-80",
+    "Digest": "sha256:e6dbbce33d195df0380cb5b0207167be1ba45e4fe1229e50fc9d769b928e5cb7",
+    "RepoTags": [
+        "1-190-source",
+        "1-197-source",
+        "1-190.1655192188-source",
+        "1-206",
+        "1",
+        "1-206-source",
+        "1-190.1655192188",
+        "1-197",
+        "1-190",
+        "latest"
+...
+</pre>
+      <p>
+        Na przykładzie znajduje się tylko fragment, ale to polecenie zwraca
+        bardzo dużo przydatnych informacji, na przykład przy kluczu
+        <code class="code-inline">RepoTags</code> znajdują się dostępne wersje
+        tego obrazu jakie możemy pobrać podając je pod dwukropku na końcu
+        <em>FQIN</em>, domyślnie pobieraną wersją jest <strong>latest</strong>.
+        Inną ciekawą wartością jest klucz <em>usage</em>, który zwraca nam
+        całe polecenie, za pomocą którego możemy uruchomić ten kontener.
+      </p>
+      <p>
+        Za pomocą podpolecenia <em>pull</em> polecenia <em>podman</em> możemy
+        pobrać wybrany przez nas obraz. To polecenie wymaga podania
+        <em>FQIN</em> jako argumentu. Poniżej znajduje się wynik działania tego
+        polecenia:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman pull registry.redhat.io/rhel9/mysql-80
+Trying to pull registry.redhat.io/rhel9/mysql-80:latest...
+Getting image source signatures
+Checking if image destination supports signatures
+Copying blob a021685edffe done  
+Copying blob c6e5292cfd5f done  
+Copying blob bf30f05a2532 done  
+Copying blob f540faa799cb done  
+Copying config 536612cfc7 done  
+Writing manifest to image destination
+Storing signatures
+536612cfc795266464d7828ff38ab12c44a55620174a769243d4cf31edadc8db
+</pre>
+      <p>
+        A tak przezentuje się obraz na liście obrazów polecenia 
+        <em>podman</em>:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman images
+REPOSITORY                         TAG         IMAGE ID      CREATED     SIZE
+registry.redhat.io/rhel9/mysql-80  latest      536612cfc795  7 days ago  558 MB
+</pre>
+      <p>
+        Aby poznać szczegóły pobranego już obrazu należy skorzystać z
+        podpolecenia <em>inspect</em> polecenia <em>podman</em>. Jako argument
+        wystarczy że podamy ostatni człon <em>FQIN</em> w tym przypadku będzie
+        to: <code class="code-inline">mysql-80</code>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman inspect mysql-80
+[
+     {
+          "Id": "536612cfc795266464d7828ff38ab12c44a55620174a769243d4cf31edadc8db",
+          "Digest": "sha256:e6dbbce33d195df0380cb5b0207167be1ba45e4fe1229e50fc9d769b928e5cb7",
+          "RepoTags": [
+               "registry.redhat.io/rhel9/mysql-80:latest"
+          ],
+...
+</pre>
+      <p>
+        Jeśli obraz nie będzie nam już potrzebny możemy usunąć go z dysku za
+        pomocą podpolecenia <em>rmi</em> polecenia <em>podman</em>. Podobnie
+        jak w przypadku podpolecenia <em>inspect</em> wystarczy, że podamy
+        ostatnią część <em>FQIN</em>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman rmi mysql-80
+Untagged: registry.redhat.io/rhel9/mysql-80:latest
+Deleted: 536612cfc795266464d7828ff38ab12c44a55620174a769243d4cf31edadc8db
+</pre>
+      <p>
+        Aby potwierdzić usunięcie obrazu możemy jeszcze raz wyświetlić ich
+        listę.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman images
+REPOSITORY  TAG         IMAGE ID    CREATED     SIZE
+</pre>
+      <h2 id="23.3.basicscontainermgmt">23.3. Podstawy zarządzania kontenerami</h2>
+      <p>
+        Po opanowaniu obsługi obrazów przyszedł czas na pierwszy kontakt z
+        kontenerami. Kontenery działają tak długo, jak działa aplikacja dla
+        której są zbudowane. Trzeba sobie to wyjaśnić. Kontenery możemy
+        podzielić na te <strong>nazwane</strong> oraz te 
+        <strong>bez nazw</strong>. Kontenery bez nazwy są jednorazowe i
+        czesto usuwane po wykonaniu swojego zadania. Nie mniej jednak w tym
+        pod rozdziale zajmiemy się zarówno jednym i drugim. Dla kontenerów na
+        nazwanych wybrałem najnowszą wersję obrazu <strong>UBI</strong> czyli
+        uniwersalnej bazy, która służy jako podstawa dla innych kontenerów
+        zawierających już aplikacje.
+      </p>
+      <h3 id="23.3.1.namedcontainer">23.3.1. Zarządzanie konterami nazwanymi</h3>
+      <p>
+        Aby uruchomić swój pierwszy kontenery należy na początku upewnić się,
+        że w systemie w katalogu <em>/etc</em> nie znajduje się katalog
+        <em>docker</em>. Jego obecność może powodować problemy z uprawnieniami.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ ls -l /etc/docker
+ls: cannot access '/etc/docker': No such file or directory
+</pre>
+      <p>
+        Kiedy tego katalogu nie ma w systemie możemy przejść do uruchomienia
+        kontenera za pomocą poniższego polecenia.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run -it --name rhel9-base-os ubi9
+Resolved "ubi9" as an alias (/etc/containers/registries.conf.d/001-rhel-shortnames.conf)
+Trying to pull registry.access.redhat.com/ubi9:latest...
+Getting image source signatures
+Checking if image destination supports signatures
+Copying blob bf30f05a2532 done  
+Copying blob c6e5292cfd5f done  
+Copying config 168c58a383 done  
+Writing manifest to image destination
+Storing signatures
+[root@baf4f328600d /]# 
+</pre>
+      <p>
+        Za pomocą podpolecenia <code class="code-inline">run</code> uruchomiłem
+        kontener w trybie interaktywnym (<code class="code-inline">-it</code>).
+        Kontener nazwałem za pomocą opcji 
+        <code class="code-inline">--name</code>,
+        został on zbudowany w oparciu o obraz 
+        <code class="code-inline">ubi9</code>, czyli obraz bazowy <em>RHEL</em>
+        9. Nazwa obrazu została podana w krótkiej wersji, bez <em>FQIN</em>.
+        W przypadku innych kontenerów niż tez zbudowane na <em>UBI</em>
+        nie zaleca się używania tej formy przekazywania nazw obrazów. Polecenie
+        samo rozwiązało <em>FQIN</em> na podstawie informacji zawartych w
+        pliku 
+        <code class="code-inline">/etc/containers/registries.conf.d/001-rhel-shortnames.conf</code>.
+        Po pobraniu obrazu oraz uruchomieniu na jego podstawie kontenera,
+        została na zwrócona powłoka wewnątrz kontenera. W celach testowych
+        możemy wykonać kilka podstawowych poleceń:
+      </p>
+<pre class="code-block">
+[root@baf4f328600d /]# ls
+afs  bin  boot dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
+[root@baf4f328600d /]# pwd
+/
+[root@baf4f328600d /]# whoami
+root
+[root@baf4f328600d /]# cat /etc/redhat-release 
+Red Hat Enterprise Linux release 9.0 (Plow)
+[root@baf4f328600d /]# cat /etc/os-release 
+NAME="Red Hat Enterprise Linux"
+VERSION="9.0 (Plow)"
+ID="rhel"
+ID_LIKE="fedora"
+VERSION_ID="9.0"
+PLATFORM_ID="platform:el9"
+PRETTY_NAME="Red Hat Enterprise Linux 9.0 (Plow)"
+ANSI_COLOR="0;31"
+LOGO="fedora-logo-icon"
+CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
+HOME_URL="https://www.redhat.com/"
+DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/9/"
+BUG_REPORT_URL="https://bugzilla.redhat.com/"
+
+REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
+REDHAT_BUGZILLA_PRODUCT_VERSION=9.0
+REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
+REDHAT_SUPPORT_PRODUCT_VERSION="9.0"
+</pre>
+      <p>
+        W znaku zachęty, w miejscu nazwy <em>hosta</em> znajduje się
+        ciąg znaków przedstawiających identyfikator kontenera. Jeśli opuścimy
+        powłokę kontenera, zostanie on zatrzymany ponieważ wykonane zostało
+        jego domyślne zadaniem jakim była obsługa procesu powłoki. Zatem tego
+        kontenera trzeba szukać na liście zatrzymanych kontenerów.
+      </p>
+<pre class="code-block">
+[root@baf4f328600d /]# exit
+exit
+[xf0r3m@primeb450 ~]$ podman ps -a
+CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS                    PORTS       NAMES
+baf4f328600d  registry.access.redhat.com/ubi9:latest  /bin/bash   14 minutes ago  Exited (0) 9 seconds ago              rhel9-base-os
+[xf0r3m@primeb450 ~]$ 
+</pre>
+      <p>
+        Kontener ten możemy włączy ponownie, za pomocą podpolecenia 
+        <em>start</em> oraz nazwy kontenera.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman start rhel9-base-os 
+rhel9-base-os
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS            PORTS       NAMES
+baf4f328600d  registry.access.redhat.com/ubi9:latest  /bin/bash   16 minutes ago  Up 3 seconds ago              rhel9-base-os
+</pre>
+      <p>
+        Na kontenerach możemy wykonywać polecenia, bez podłączania się do ich
+        powłoki, temu celowi służy podpolecenie <em>exec</em>. Wymaga ono
+        podania nazwy uruchomionego kontenera oraz polecenia.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman exec rhel9-base-os cat /etc/redhat-release
+Red Hat Enterprise Linux release 9.0 (Plow)
+</pre>
+      <p>
+        Jeśli jednak chcielibyśmy podłączyć się do powłoki kontenera, to
+        wówczas należy użyć podpolecenia <em>attach</em> wraz z nazwą
+        kontenera.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS            PORTS       NAMES
+baf4f328600d  registry.access.redhat.com/ubi9:latest  /bin/bash   18 minutes ago  Up 2 minutes ago              rhel9-base-os
+[xf0r3m@primeb450 ~]$ podman attach rhel9-base-os 
+[root@baf4f328600d /]# 
+</pre>
+      <p>
+        Po opuszczeniu powłoki, kontener zostanie zatrzymany. Jeśli
+        nie potrzebujemy już w systemie kontenerów, możemy je
+        usunąć za pomocą podpolecenia <em>rm</em>, przy czym należy upewnić
+        się, że kontener jest zatrzymany inaczej polecenie niepowiedzie się.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+[xf0r3m@primeb450 ~]$ podman rm rhel9-base-os 
+baf4f328600dad7e8fce03d854a6c4e480453679181f97233dccee5ea5a9e5dc
+[xf0r3m@primeb450 ~]$ podman ps -a
+CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+</pre>
+      <p>
+        Za pomocą pierwszego wywołania podpolecenia <em>ps</em> upewniłem się,
+        że kontener nie jest uruchomiony, następnie za pomocą podpolecenia
+        <em>rm</em> usunąłem kontener. Za pomocą podpolecenia <em>ps</em> z
+        opcją <em>-a</em> sprawdziłem czy kontener jest rzeczywiście
+        usunięty.
+      </p>
+      <h3 id="23.3.2.namelesscontainers">23.3.2. Zarządzanie kontenerami bez nazw</h3>
+      <p>
+        Zarządzanie kontenerami bez nazw, jest znacznie prostsze, ponieważ
+        może zostać sprowadzone do jednego polecenia. Poniżej przedstawiłem w
+        jaki sposób można uruchomić kontener bez nazwy, aby wykonał proces do
+        które został stworzony następnie został usunięty z systemu. 
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run --rm docker.io/library/hello-world
+Trying to pull docker.io/library/hello-world:latest...
+Getting image source signatures
+Copying blob 2db29710123e done  
+Copying config feb5d9fea6 done  
+Writing manifest to image destination
+Storing signatures
+
+Hello from Docker!
+This message shows that your installation appears to be working correctly.
+
+To generate this message, Docker took the following steps:
+ 1. The Docker client contacted the Docker daemon.
+ 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
+    (amd64)
+ 3. The Docker daemon created a new container from that image which runs the
+    executable that produces the output you are currently reading.
+ 4. The Docker daemon streamed that output to the Docker client, which sent it
+    to your terminal.
+
+To try something more ambitious, you can run an Ubuntu container with:
+ $ docker run -it ubuntu bash
+
+Share images, automate workflows, and more with a free Docker ID:
+ https://hub.docker.com/
+
+For more examples and ideas, visit:
+ https://docs.docker.com/get-started/
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+[xf0r3m@primeb450 ~]$ podman ps -a
+CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+</pre>
+      <p>
+        Kontener zwrócił informacje powitalną podobnego systemu kontenerów
+        jakim jest <em>Docker</em>, następnie został usunięty co zostało
+        potwierdzone za pomocą dwóch ostatnich poleceń na przykładzie.
+      </p>
+      <h2 id="23.4.advcontainermgmt">23.4. Zaawansowane zarządzanie kontenerami</h2>
+      <p>
+        Po poznaniu podstaw, możemy przejść do bardziej zaawansowanych 
+        czynności wykonywanych na kontenerach, takich jak mapowanie portów,
+        przekazywanie zmiennych środowiskowych, katalogu hostującej maszyny
+        czy zarządania kontenerami z poziomu <em>systemd</em>.
+      </p>
+      <h3 id="23.4.1.portmapping">23.4.1. Mapowanie portów hosta na porty kontenera</h3>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Podczas wykonywania tej czynność, należy pamiętać o bardzo ważnej
+        rzeczy. Mianowicie, kontenery nieuprzywilejowane nie mogą mapować
+        portów na porty <em>hosta</em> poniżej 1024 portu.
+      </p>
+      <p>
+        <strong>Mapowanie portów</strong> spowoduje,
+        że jaki kolwiek ruch sieciowy, który będzie skierowany do określonego
+        portu <em>hosta</em> zostanie przekierowny do portu kontenera. Tą
+        czynność wykonuje się poprzez użycie opcji <strong>-p</strong>
+        podpolecenia <em>run</em>. Rozważmy poniższym przykład.
+      </p>
+      <p>
+        Na początek pobiorę obraz serwera HTTP.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman pull registry.redhat.io/rhel9/httpd-24
+Trying to pull registry.redhat.io/rhel9/httpd-24:latest...
+Getting image source signatures
+...
+</pre>
+      <p>
+        Następnie na podstawie tego obrazu przygotuje nazwany kontener z
+        mapowaniem portów.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run -d -p 8080:80 --name rhel9-http-map registry.redhat.io/rhel9/httpd-24
+cdb3fe727ec39de7323da49bb230f2dc22bdc51da43bc48e9218d2eeb09b166b
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                     COMMAND               CREATED        STATUS            PORTS                 NAMES
+cdb3fe727ec3  registry.redhat.io/rhel9/httpd-24:latest  /usr/bin/run-http...  3 seconds ago  Up 4 seconds ago  0.0.0.0:8080-&gt;80/tcp  rhel9-http-map
+</pre>
+      <p>
+        Za pomocą <code class="code-inline">-d</code> kontener zostaje
+        odłączony od terminala i kontynuje pracę w tle. Przyczym ma to
+        zastosowanie wyłącznie w przypadku programów, które oczekują na 
+        połączenia od innych np. demonów.
+        Teraz ruch przychodzący na port <em>8080</em> <em>hosta</em> zostanie
+        przekierowany do kontenera. Mapowania widać w kolumnie
+        <code class="code-inline">PORTS</code>. Mapowania możemy zobrazować
+        lepiej za pomocą podpolecenia <em>port</em> polecenia <em>podman</em>,
+        przy czym to podpolecenie wymaga podania nazwy kontenera.  
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman port rhel9-http-map 
+80/tcp -&gt; 0.0.0.0:8080
+</pre>
+      <p>
+        Na koniec usunąłem ten kontener, za pomocą poniższych poleceń.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman stop rhel9-http-map 
+rhel9-http-map
+[xf0r3m@primeb450 ~]$ podman rm rhel9-http-map 
+cdb3fe727ec39de7323da49bb230f2dc22bdc51da43bc48e9218d2eeb09b166b
+</pre>
+      <h3 id="23.4.2.envtocontainers">23.4.2. Przekazywanie zmiennych środowiskowych do kontenerów</h3>
+      <p>
+        Nie które z konteneryzowanych aplikacji wymagają podania od użytkownika
+        pewnych parametrów do uruchomienia. Te parametry przekazuje
+        się za pomocą zmiennych środowiskowych, a są one przezkazywane za
+        pomocą opcji <strong>-e</strong> podpolecenia <em>run</em>.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Warto dodać, że przekazanie każdej wartości do kontenera wymaga podania
+        opcji <em>-e</em>. 
+      </p>
+      <p>
+        Dobrze obrazuje to poniższy przykład.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run -dt -e VAR1="test1" -e VAR2="test2" --name rhel9-cont-env ubi9
+13a244c2d73d2d604591ebbdf2112e222392f3f046b90e220e55397888cae80a
+[xf0r3m@primeb450 ~]$ podman exec rhel9-cont-env env
+TERM=xterm
+container=oci
+VAR1=test1
+VAR2=test2
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+HOME=/root
+</pre>
+      <p>
+        Za pomocą opcji <code class="code-inline">-dt</code> umożliwiłem
+        działanie powłoki w tle (głownym procesem obrazów <em>UBI</em> jest
+        powłoka). Przy użyciu opcji <code class="code-inline">-e</code> 
+        przekazałem do kontenera przedstawione na przykładzie zmienne 
+        środowiskowe. W drugim poleceniu używając podpolecenia
+        <code class="code-inline">exec</code> uruchomiłem na kontenerze
+        polecenie <code class="code-inline">env</code>, które zwraca zmienne
+        środowiskowe. Jak wskazuje wynik działania tego polecenia, przekazane
+        przez nas wartości są obecne w środowisku kontenera jako zmienne
+        środowiskowe. Teraz możemy zatrzymać i usunąć ten kontener. 
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman stop rhel9-cont-env 
+rhel9-cont-env
+[xf0r3m@primeb450 ~]$ podman rm rhel9-cont-env 
+13a244c2d73d2d604591ebbdf2112e222392f3f046b90e220e55397888cae80a
+</pre>
+      <h3 id="23.4.3.storageforcontainers">23.4.3. Konfigurowanie miejsca na dane dla kontenerów</h3>
+      <p>
+        Kontenery działają tak długo, jak długo działa główny proces. Kiedy on
+        kończy swoje działanie, tak i kontener zostaje zatrzymany. Zatrzymanie
+        albo restart kontenera powodują utratę wszystkich wytworzonych przez
+        niego danych. Jeśli te dane mogą być potrzebne, to należy zaopatrzyć
+        kontenery w miejsce gdzie będą mogły je składować.
+        Takim miejscem może być katalog znajdujący się gdzieś na hoście.
+      </p>
+      <p class="exam_tip">
+        <strong>Odnośnie egzaminu:</strong><br />
+        Konfigurując taki katalog należy pamiętać o trzech czynnościach jakie
+        należy wykonać: 1. Odpowiednie uprawnienia, w przykładach będę stosować
+        raczej pełnych uprawnień, tj. 777; 2. Prawo własności, jeśli jest to
+        kontener nieuprzywilejowany to włascicielem oraz grupą, do której ten
+        katalog należy powinien być użytkownik, który uruchamia kontener;
+        3. Właściwy typ pliku <em>SELinux</em>, tej wartości nie trzeba
+        konfigurować ręcznie, wystarczy że podamy na koniec wartości
+        przekazywania katalogu
+        opcję <strong>:Z</strong>, spowoduje ona samodzielne przypisanie
+        odpowiedniego kontesktu <em>SELinux</em>.
+      </p>
+      <p>
+        Chcąc zobrazować jak może wyglądać takie przekazanie katalogu.
+        Czynności należy rozpocząć od utworzenia katalogu, nadania mu
+        odpowiednich uprawnień oraz prawa własności.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo mkdir /host_dir
+[sudo] password for xf0r3m: 
+[xf0r3m@primeb450 ~]$ sudo chmod 777 /host_dir/
+[xf0r3m@primeb450 ~]$ sudo chown xf0r3m:xf0r3m /host_dir/
+</pre>
+      <p>
+        Następnie uruchomie kontener przekazując ten katalog jako katalog
+        <em>/container_dir</em> w głównym systemie plików kontenera.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run -dt --name rhel9-persistent-data -v /host_dir:/container_dir:Z ubi9
+96e45fa0558c0d2da216de2c91747aae1fc177301ea58eb81571f200f8022fb2
+</pre>
+      <p>
+        Za pomocą opcji <code class="code-inline">-v</code> dokonujemy 
+        przekazania katalogu do kontenera. Zwróćmy uwagę na dodatkową opcję
+        <code class="code-inline">:Z</code>, powoduje ona dobranie 
+        odpowiedniego kontekstu <em>SELinux</em>. Teraz podłącze się pod 
+        kontener aby sprawdzić uprawnienia przekazanego katalogu, kontekst
+        <em>SELinux</em> oraz to czy możemy przechowywać w nim dane.
+      </p>
+<pre class="code-block">
+[root@96e45fa0558c /]# ls -l 
+total 0
+dr-xr-xr-x.   2 root   root     6 Aug  9  2021 afs
+lrwxrwxrwx.   1 root   root     7 Aug  9  2021 bin -&gt; usr/bin
+dr-xr-xr-x.   2 root   root     6 Aug  9  2021 boot
+drwxrwxrwx.   2 root   root     6 Aug 11 11:52 container_dir
+...
+[root@96e45fa0558c /]# cd container_dir/
+[root@96e45fa0558c container_dir]# echo "This is a test message!" &gt; test_file.txt
+[root@96e45fa0558c container_dir]# ls -ldZ /container_dir
+drwxrwxrwx. 2 root root system_u:object_r:container_file_t:s0:c417,c733 27 Aug 11 11:55 /container_dir
+[root@96e45fa0558c container_dir]# ls -lZ /container_dir/
+total 4
+-rw-r--r--. 1 root root system_u:object_r:container_file_t:s0:c417,c733 24 Aug 11 11:55 test_file.txt
+</pre>
+      <p>
+        Jak możemy zauważyć na powyższym przykładzie katalog przekazany do
+        kontenera znajduje się w katalogu głównym tak jak to zostało zapisane
+        podczas jego utworzenia. Następnie sprawdziłem czy da się utworzyć
+        jakiś plik z zawartością w tym katalogu. Po wydaniu polecenia 
+        <code class="code-inline">echo</code> powłoka nie zwróciła żadnego
+        błędu więc można było przypuszczać, że zapis do pliku powiódł się.
+        Na koniec jeszcze sprawdziłem konteskt <em>SELinux</em>. Po zamknięciu
+        powłoki, sprawdziłem czy utworzony plik znajduje się w katalogu 
+        przeznaczonym dla kontenera oraz plik posiada wcześniej zapisaną
+        zawartość. Możemy się o tym przekonać analizując poniższy przykład:
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ ls -l /host_dir/
+total 4
+-rw-r--r--. 1 xf0r3m xf0r3m 24 Aug 11 13:55 test_file.txt
+[xf0r3m@primeb450 ~]$ cat /host_dir/test_file.txt 
+This is a test message!
+</pre>
+      <p>
+        Jak widzimy wszystko zadziałało. Teraz możemy usunąć ten kontener.
+      </p>
+      <h3 id="23.4.4.controlingcontainersviasystemd">23.4.4. Kontrolowanie kontenerów przez systemd</h3>
+      <p>
+        Jeśli konterów w systemie jest bardzo wiele, łatwiej jest nimi zarządać 
+        za pomocą programu typu <em>init</em>, jakim jest <em>systemd</em>.
+        Za pomocą podpolecenia <strong>generate</strong> polecenia <em>podman</em>,
+        możemy wygenerować pliki jednostki usługi, dla każdego kontenera i 
+        zarządzać nimi jak usługami. Tego typu funkcja ma jedną bardzo ważną
+        cechę przez co jest dość mocno wykorzystywana, mianowicie
+        automatyczne uruchomienie kontenerów podczas startu systemu. Przy
+        okazji tego zagadnienia również zauważymy różnicę między kontenerami
+        nieuprzywilejowanymi oraz uprzyprzywilejowanymi, ponieważ przekazanie
+        ich kontroli do <em>systemd</em> wygląda nieco inaczej.
+      </p>
+      <p>
+        <strong>Kontenery uprzywilejowane</strong>:
+      </p>
+      <p>
+        Na początku konfiguracji potrzebujemy kontenera. Utwórzmy prosty
+        kontener na bazie <em>UBI</em>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo podman run -dt --name rhel9-cont-systemd ubi9
+[sudo] password for xf0r3m: 
+Resolved "ubi9" as an alias (/etc/containers/registries.conf.d/001-rhel-shortnames.conf)
+Trying to pull registry.access.redhat.com/ubi9:latest...
+Getting image source signatures
+Checking if image destination supports signatures
+Copying blob bf30f05a2532 done  
+Copying blob c6e5292cfd5f done  
+Copying config 168c58a383 done  
+Writing manifest to image destination
+Storing signatures
+d9ef99614a37c58d55edbca805cbc4da5bd99dae9c1674ed3c336893dbe901d6
+</pre>
+      <p>
+        Nie ma się co dziwić jeśli polecenie to pobierze jeszcze raz obraz.
+        Wynika to z tego, że konfiguracja kontenerów nieuprzywilejowanych i 
+        tych uprzywilejowanych jest zupełnie inna, te kontenery również mają 
+        oddzielny katalog, który przechowuje ich obrazy. Po utworzeniu katalogu
+        generujemy plik jednostki, zapisujemy go katalogu konfiguracji
+        lokalnej <em>/etc/systemd/system</em>.
+      </p>
+<pre class="code-block">
+sudo podman generate systemd --new rhel9-cont-systemd | sudo tee /etc/systemd/system/rhel9-cont-systemd.service
+</pre>
+      <p>
+        Podpolecenie <em>generate</em> wymaga podania typu generowanego pliku
+        w tym przypadku jest <code class="code-inline">systemd</code>. Użyłem
+        tutaj również opcji <code class="code-inline">--new</code>, co powoduje
+        za każdym startem utworzenie nowego kontenera. Wynik musiałem
+        przepuścić przez polecenie <code class="code-inline">tee</code>,
+        ponieważ przy użyciu operatora przekierowania nie damy rady zapisać 
+        nic w tej
+        lokalizacji. Po utworzeniu tego pliku możemy załadować plik jednostki
+        i kontrolować kontener z poziomu <em>systemd</em>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ sudo systemctl daemon-reload 
+[sudo] password for xf0r3m: 
+[xf0r3m@primeb450 ~]$ sudo systemctl enable --now rhel9-cont-systemd.service
+Created symlink /etc/systemd/system/default.target.wants/rhel9-cont-systemd.service → /etc/systemd/system/rhel9-cont-systemd.service.
+[xf0r3m@primeb450 ~]$ sudo systemctl status rhel9-cont-systemd.service --no-pager
+● rhel9-cont-systemd.service - Podman container-d9ef99614a37c58d55edbca805cbc4da5bd99dae9c1674ed3c336893dbe901d6.service
+     Loaded: loaded (/etc/systemd/system/rhel9-cont-systemd.service; enabled; vendor preset: disabled)
+     Active: active (running) since Thu 2022-08-11 14:44:32 CEST; 12s ago
+       Docs: man:podman-generate-systemd(1)
+    Process: 9123 ExecStartPre=/bin/rm -f /run/rhel9-cont-systemd.service.ctr-id (code=exited, status=0/SUCCESS)
+   Main PID: 9294 (conmon)
+      Tasks: 2 (limit: 48032)
+     Memory: 980.0K
+        CPU: 246ms
+     CGroup: /system.slice/rhel9-cont-systemd.service
+             └─9294 /usr/bin/conmon --api-version 1 -c fa9a83e06b6c9b75b64c69d80925b67e6d7458f3de5d78075b180bb2da0156fb -u fa9a83e06…
+
+[xf0r3m@primeb450 ~]$ sudo podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS             PORTS       NAMES
+fa9a83e06b6c  registry.access.redhat.com/ubi9:latest  /bin/bash   37 seconds ago  Up 37 seconds ago              rhel9-cont-systemd
+</pre>
+      <p>
+        Teraz możemy kontenery zatrzymywać oraz uruchamiać ponownie z poziomu
+        polecenia <em>systemctl</em>. Zatrzymanie kontenera z tego poziomu 
+        spowoduje jego usunięcie z systemu. Utworzony plik usługi można
+        traktować wówczas jako pliki szablonu dla kontenerów.
+      </p>
+      <p>
+        <strong>Kontenery nieuprzywilejowane</strong>:
+      </p> 
+      <p>
+        W przypadku tego rodzaju kontenerów sprawa się dodatkowo komplikuje
+        z powodu tego, iż kontenery są zatrzymywane w momencie wylogowania się
+        użytkownika. Jednak w tym przypadku stosuje się sztuczkę, która
+        powoduje pojawienia się użytkownika jeśli tylko jest potrzebny. Ta
+        metoda nazywana jest <strong>lingering</strong>. Inną komplikacją jest
+        fakt, że do obsługi <em>systemd</em> z poziomu zwykłego użytkownika,
+        musi być on zalogowany albo fizycznie, albo za pomocą SSH, nie może być
+        to przełączony użytkownik za pomocą poleceń <em>sudo</em> lub
+        <em>su</em>.
+      </p>
+      <p>
+        Czynności tym razem zaczniemy od utworzenia katalogu
+        <em>~/.config/systemd/user</em> oraz włączenia <em>lingeringu</em>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ mkdir -p ~/.config/systemd/user
+[xf0r3m@primeb450 ~]$ loginctl enable-linger
+</pre>
+      <p>
+        <em>Lingering</em> włącza się za pomocą pojedynczego polecenia, wiec
+        nie jest jakoś zbytnio skomplikowane, a naprawdę robi robotę. Teraz
+        możemy przejść do utworzenia kontenera.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ podman run -dt --name rhel9-unpriv-cont-systemd ubi9
+fbe3ab11d3728470f1fcd38f07b99bd7e151ac2fc0c4a6a8dad85c486c3bce60
+</pre>
+      <p>
+        Tego przykładu chyba nie muszę tłumaczyć. Teraz wygeneruje plik
+        jednostki dla tego kontenera w utworzonym wcześniej katalogu.
+      </p>
+<pre class="code-block">
+podman generate systemd --new rhel9-unpriv-cont-systemd &gt; ~/.config/systemd/user/rhel9-unpriv-cont-systemd.service
+</pre>
+      <p>
+        Teraz mogłem użyć przekierowania, ponieważ cały czas działam w obrębie
+        tych samych uprawnień. Teraz załaduje plik jednostki i uruchomię
+        nowy kontener, tutaj też użyłem opcji 
+        <code class="code-inline">--new</code>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ systemctl --user daemon-reload 
+[xf0r3m@primeb450 ~]$ systemctl --user enable --now rhel9-unpriv-cont-systemd.service 
+Created symlink /home/xf0r3m/.config/systemd/user/default.target.wants/rhel9-unpriv-cont-systemd.service → /home/xf0r3m/.config/systemd/user/rhel9-unpriv-cont-systemd.service.
+[xf0r3m@primeb450 ~]$ systemctl --user status rhel9-unpriv-cont-systemd.service --no-pager
+● rhel9-unpriv-cont-systemd.service - Podman container-fbe3ab11d3728470f1fcd38f07b99bd7e151ac2fc0c4a6a8dad85c486c3bce60.service
+     Loaded: loaded (/home/xf0r3m/.config/systemd/user/rhel9-unpriv-cont-systemd.service; enabled; vendor preset: disabled)
+     Active: active (running) since Thu 2022-08-11 15:02:52 CEST; 31s ago
+       Docs: man:podman-generate-systemd(1)
+    Process: 9876 ExecStartPre=/bin/rm -f /run/user/1000/rhel9-unpriv-cont-systemd.service.ctr-id (code=exited, status=0/SUCCESS)
+   Main PID: 9914 (conmon)
+      Tasks: 3 (limit: 48032)
+     Memory: 1.4M
+        CPU: 211ms
+     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/rhel9-unpriv-cont-systemd.service
+             ├─9910 /usr/bin/slirp4netns --disable-host-loopback --mtu=65520 --enable-sandbox --enable-seccomp --enable-ipv6 -c -e 3…
+             └─9914 /usr/bin/conmon --api-version 1 -c 73435f815694db611703dca5e48b52321f95849de15e6ac3cd2859f469a2d116 -u 73435f815…
+
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS             PORTS       NAMES
+73435f815694  registry.access.redhat.com/ubi9:latest  /bin/bash   42 seconds ago  Up 43 seconds ago              rhel9-unpriv-cont-systemd
+</pre>
+      <p>
+        Jak widzimy na przykładzie kontener został uruchomiony, teraz uruchomie
+        go ponownie za pomocą polecenia <em>systemctl</em>.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ systemctl --user restart rhel9-unpriv-cont-systemd.service 
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED        STATUS            PORTS       NAMES
+810555dd08f1  registry.access.redhat.com/ubi9:latest  /bin/bash   3 seconds ago  Up 4 seconds ago              rhel9-unpriv-cont-systemd
+[xf0r3m@primeb450 ~]$ systemctl --user restart rhel9-unpriv-cont-systemd.service &amp;&amp; podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED                 STATUS                     PORTS       NAMES
+433ac061577e  registry.access.redhat.com/ubi9:latest  /bin/bash   Less than a second ago  Up Less than a second ago              rhel9-unpriv-cont-systemd
+</pre>
+      <p>
+        Różne identyfikatory kontenerów w pierwszej kolumnie, wyjścia polecenia
+        <code class="code-inline">podman ps</code> wskazuje, że za każdym
+        ponownym aktywowaniem jednostki, tworzony jest nowy kontener. Po
+        wylogowaniu i zalogowaniu się ponownie, kontener nadal działa, co 
+        oznacza, że <em>lingering</em> jest dobrze skonfigurowany.
+      </p>
+<pre class="code-block">
+[xf0r3m@primeb450 ~]$ exit
+logout
+Connection to 192.168.8.7 closed.
+[xf0r3m@latitude-e5270 ~]$ ssh 192.168.8.7
+xf0r3m@192.168.8.7's password: 
+Activate the web console with: systemctl enable --now cockpit.socket
+
+Register this system with Red Hat Insights: insights-client --register
+Create an account or view all your systems at https://red.ht/insights-dashboard
+Last login: Thu Aug 11 08:37:43 2022 from 192.168.8.168
+[xf0r3m@primeb450 ~]$ podman ps
+CONTAINER ID  IMAGE                                   COMMAND     CREATED        STATUS            PORTS       NAMES
+433ac061577e  registry.access.redhat.com/ubi9:latest  /bin/bash   3 minutes ago  Up 3 minutes ago              rhel9-unpriv-cont-systemd
+</pre>
+      <h3 id="exec23.1">Ćwiczenie 1: Utwórzenie laboratorium kontenerów</h3>
+      <p>
+        Na fizycznym komputerze lub maszynie wirtualne, zainstaluj system
+        <em>RHEL</em> 9, zarejestruj go w sieci <em>Red Hat</em> podczas
+        instalacji oraz utwórz użytkownika z uprawnieniami administratora. Po 
+        zainstalowaniu systemu zaktualizuj go i zainstaluj
+        niezbędne oprogramowanie do obsługi kontenerów w systemie. Wykonanie
+        tego ćwiczenia jest niezbędne do wykonania pozostałych. 
+      </p>
+      <h3 id="exec23.2">Ćwiczenie 2: Nazwany kontener z mapowaniem portów</h3>
+      <p>
+        W laboratorium kontenerów, utworz uprzywilejowany kontener z mapowaniem
+        portu 80:8080 oraz dowolną nazwą. Do tworzenia kontenera wykorzystaj 
+        obraz <em>UBI</em>
+        dla <em>RHEL</em> 7. Wykonaj kilka poleceń takich jak: <em>ls, pwd, df,
+        cat /etc/redhat-release</em> oraz <em>cat /etc/os-release</em>.
+        Sprawdź mapowanie portów. Nie usuwaj jeszcze tego kontenera.
+      </p>
+      <h3 id="exec23.3">Ćwiczenie 3: Kontener bez nazwy z przekazanymi zmiennymi</h3>
+      <p>
+        W laboratorium kontenerów, na podstawie <em>UBI</em> dla <em>RHEL</em> 
+        8 utwórz nieuprzywilejowany kontener bez nazwy
+        z przekazaniem dwóch zmiennych <em>VAR1="lab1"</em> oraz
+        <em>VAR2="lab2"</em>. Działanie kontenera powinno polegać na 
+        wyświetleniu zmiennych środowiskowych, a kontener powinien zostać
+        usunięty po skończeniu zadania. 
+        Na koniec usuń także obraz <em>UBI</em> dla <em>RHEL</em> 8.
+      </p>
+      <h3 id="exec23.4">Ćwiczenie 4: Kontener ze stałym miejscem przechowywania</h3>
+      <p>
+        W laboratorium kontenerów, utwórz katalog o nazwie <em>/host_perm1</em>
+        wraz z plikiem <em>str1</em> przeznaczony na stałe miejsce dla danych
+        kontenera uprzywilejowanego, następnie na podstawie <em>UBI</em> dla
+        <em>RHEL</em> 9 utwórz kontener o nazwie <em>priv-cont-str</em> 
+        przekazując do niego ten katalog pod punkt montowania
+        <em>/cont_perm1</em>. 
+        Przez powłokę kontenera sprawdź uprawnienia przekazanego katalogu oraz
+        obecność pliku, następnie utwórz w nim dodatkowy podkatalog.
+        Opuść powłokę kontenera i na
+        <em>hoście</em> sprawdź obecność utworzonego podkatalogu. Na koniec
+        usuń kontener oraz utworzony na potrzeby tego ćwiczenia katalog. 
+      </p>
+      <h3 id="exec23.5">Ćwiczenie 5: Kontener z przekazywaniem portów, zmiennymi oraz stałym miejscem przechowywania</h3>
+      <p>
+        W laboratorium kontenerów, utworz katalog o nazwie <em>/host_perm2</em>
+        na stałe miejsce przechowywania dla kontenera nieuprzywilejowanego, 
+        na podstawie <em>UBI</em> dla <em>RHEL</em> 9 utwórz kontener o nazwie
+        <em>rootless-adv-cont</em> w trybie interaktywym przekaż do niego dwie
+        zmienne <em>HISTSIZE=100</em> oraz <em>MYNAME=RedHat</em> zmapuj 
+        port hosta 9000 na port 8080 kontenera, przekaż wcześniej utworzony
+        katalog pod punkt montowania <em>/cont_perm2</em>, sprawdź zmienne 
+        oraz punkt montowania, następie opuść powłokę i sprawdź czy mapowanie
+        portów było prawidłowe. Nie usuwaj tego kontenera jeszcze. 
+      </p> 
+      <h3 id="exec23.6">Ćwiczenie 6: Konfigracja kontroli systemd nad kontenerami uprzywilejowanymi</h3>
+      <p>
+        Korzystając z kontenera z ćwiczenia drugiego, w laboratorium
+        kontenerów skonfiguruj kontrolę tego kontenera przez <em>systemd</em>.
+        Aby potwierdzić działanie konfiguracji zrestartuj system. 
+      </p>
+      <h3 id="exec23.7">Ćwiczenie 7: Konfigracja kontroli systemd nad kontenerami nieuprzywilejowanymi</h3>
+      <p>
+        Korzystając z kontenera z ćwiczenia piątego, w laboratorum 
+        kontenerów skonfiguruj kontrolę tego kontenera przez <em>systemd</em>,
+        zwróć uwagę na to iż jest to kontener nieuprzywilejowany. Aby
+        potwierdzić działanie konfiguracji zrestartuj system.
+      </p>
+      <h2 id="ch23summary">Podsumowanie</h2>
+      <p>
+        W tym ostatnim już rozdziale zapoznaliśmy się technikami
+        kontenerów w <em>RHEL</em>. Poznalismy niezbędną wiedzę teoretyczną
+        oraz narzędzia potrzebne w praktyce. Poznaliśmy wiele przypadków
+        praktycznej obsługi kontenerów, od przekazywania portów do przekazania
+        kontroli nad konterami do programu typu <em>init</em>, jakim jest
+        <em>systemd</em> zapoznaliśmy się też z konfiguracją plików jednostek
+        użytkownika. Ten rozdział zamyka ten materiał. Jeśli chcemy więcej 
+        technologii <em>Red Hat</em>, możemy przystąpić
+        kolejnego certyfikatu po zdaniu <em>RHCSA</em>. Powodzenia!
+      </p>
+      </div>
+    </div>
+       </body>
+</html>
diff --git a/articles/terminallog/cwiczenia_python.html b/articles/terminallog/cwiczenia_python.html
new file mode 100755 (executable)
index 0000000..8d24684
--- /dev/null
@@ -0,0 +1,1799 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+      <style>
+        body {
+          width: 99%;
+          height: 100vh;
+        }
+        .main {
+          width: 100%;
+        }
+      </style>
+               </head>
+               <body>
+                       <div class="main">
+      <div id="tableOfContent">
+        <h1>Python. Ćwiczenia.</h1>
+                <ol class="toc mainToc">
+          <li><a href="#1.part">Część I - Python.</a>
+            <ul class="toc">
+              <li><a href="#1.1.ch">Rozdział 1:</a>
+                <ul class="toc">
+                  <li><a href="#1.1.1.exerc">1.1. Witryna python.org</a></li>
+                  <li><a href="#1.1.2.exerc">1.2. Błędy w programie typu „Witaj, świecie!”</a></li>
+                  <li><a href="#1.1.3.exerc">1.3. Niczym nieograniczone umiejętności</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.2.ch">Rozdział 2:</a>
+                <ul class="toc">
+                  <li><a href="#1.2.1.exerc">2.1. Prosty komunikat</a></li>
+                  <li><a href="#1.2.2.exerc">2.2. Proste komunikaty</a></li>
+                  <li><a href="#1.2.3.exerc">2.3. Osobiste powitanie</a></li>
+                  <li><a href="#1.2.4.exerc">2.4. Wielkość liter w imionach</a></li>
+                  <li><a href="#1.2.5.exerc">2.5. Sławny cytat</a></li>
+                  <li><a href="#1.2.6.exerc">2.6. Sławny cytat 2</a></li>
+                  <li><a href="#1.2.7.exerc">2.7. Usunięcie białych znaków z imienia</a></li>
+                  <li><a href="#1.2.8.exerc">2.8. Liczba osiem</a></li>
+                  <li><a href="#1.2.9.exerc">2.9. Ulubiona liczba</a></li>
+                  <li><a href="#1.2.10.exerc">2.10. Dodawanie komentarzy</a></li>
+                  <li><a href="#1.2.11.exerc">2.11. Zen Pythona</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.3.ch">Rozdział 3:</a>
+                <ul class="toc">
+                  <li><a href="#1.3.1.exerc">3.1. Imiona</a></li>
+                  <li><a href="#1.3.2.exerc">3.2. Powitania</a></li>
+                  <li><a href="#1.3.3.exerc">3.3. Twoja własna lista</a></li>
+                  <li><a href="#1.3.4.exerc">3.4. Lista gości</a></li>
+                  <li><a href="#1.3.5.exerc">3.5. Zmiana listy gości</a></li>
+                  <li><a href="#1.3.6.exerc">3.6. Więcej gości</a></li>
+                  <li><a href="#1.3.7.exerc">3.7. Kurcząca się lista gości</a></li>
+                  <li><a href="#1.3.8.exerc">3.8. Zwiedzaj świat</a></li>
+                  <li><a href="#1.3.9.exerc">3.9. Goście na obiad</a></li>
+                  <li><a href="#1.3.10.exerc">3.10. Każda funkcja.</a></li>
+                  <li><a href="#1.3.11.exerc">3.11. Celowy błąd</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.4.ch">Rozdział 4:</a>
+                <ul class="toc">
+                  <li><a href="#1.4.1.exerc">4.1. Pizza</a></li>
+                  <li><a href="#1.4.2.exerc">4.2. Zwierzęta</a></li>
+                  <li><a href="#1.4.3.exerc">4.3. Odliczanie do dwudziestu</a></li>
+                  <li><a href="#1.4.4.exerc">4.4. Milion</a></li>
+                  <li><a href="#1.4.5.exerc">4.5. Sumowanie do miliona</a></li>
+                  <li><a href="#1.4.6.exerc">4.6. Listy nieparzyste</a></li>
+                  <li><a href="#1.4.7.exerc">4.7. Trzy</a></li>
+                  <li><a href="#1.4.8.exerc">4.8. Sześcian</a></li>
+                  <li><a href="#1.4.9.exerc">4.9. Sześcian za pomocą listy składanej</a></li>
+                  <li><a href="#1.4.10.exerc">4.10. Wycinki</a></li>
+                  <li><a href="#1.4.11.exerc">4.11. Moja pizza, Twoja pizza</a></li>
+                  <li><a href="#1.4.12.exerc">4.12. Więcej pętli</a></li>
+                  <li><a href="#1.4.13.exerc">4.13. Bufet</a></li>
+                  <li><a href="#1.4.14.exerc">4.14. Specyfikacja PEP 8</a></li>
+                  <li><a href="#1.4.15.exerc">4.15. Przegląd kodu</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.5.ch">Rozdział 5:</a>
+                <ul class="toc">
+                  <li><a href="#1.5.1.exerc">5.1. Testy warunkowe</a></li>
+                  <li><a href="#1.5.2.exerc">5.2. Więcej testów warunkowych.</a></li>
+                  <li><a href="#1.5.3.exerc">5.3. Kolory obcych, część 1.</a></li>
+                  <li><a href="#1.5.4.exerc">5.4. Kolory obcych, część 2</a></li>
+                  <li><a href="#1.5.5.exerc">5.5. Kolory obcych, część 3</a></li>
+                  <li><a href="#1.5.6.exerc">5.6. Etapy życia</a></li>
+                  <li><a href="#1.5.7.exerc">5.7. Ulubione owoce</a></li>
+                  <li><a href="#1.5.8.exerc">5.8. Witaj, administratorze</a>.</li>
+                  <li><a href="#1.5.9.exerc">5.9. Brak użytkowników</a></li>
+                  <li><a href="#1.5.10.exerc">5.10. Sprawdzanie nazw użytkowników</a></li>
+                  <li><a href="#1.5.11.exerc">5.11. Liczby porządkowe</a></li>
+                  <li><a href="#1.5.12.exerc">5.12. Nadanie stylu konstrukcji if</a></li>
+                  <li><a href="#1.5.13.exerc">5.13. Twoje pomysły</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.6.ch">Rozdział 6:</a>
+                <ul class="toc">
+                  <li><a href="#1.6.1.exerc">6.1. Osoba</a></li>
+                  <li><a href="#1.6.2.exerc">6.2. Ulubione liczby</a></li>
+                  <li><a href="#1.6.3.exerc">6.3. Glosariusz</a></li>
+                  <li><a href="#1.6.4.exerc">6.4. Glosariusz 2</a></li>
+                  <li><a href="#1.6.5.exerc">6.5. Rzeki</a></li>
+                  <li><a href="#1.6.6.exerc">6.6. Ankieta</a></li>
+                  <li><a href="#1.6.7.exerc">6.7. Osoby.</a></li>
+                  <li><a href="#1.6.8.exerc">6.8. Zwierzęta.</a></li>
+                  <li><a href="#1.6.9.exerc">6.9. Ulubione miejsca.</a></li>
+                  <li><a href="#1.6.10.exerc">6.10. Ulubione liczby</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.7.ch">Rozdział 7:</a>
+                <ul class="toc">
+                  <li><a href="#1.7.1.exerc">7.1. Wypożyczenie samochodu</a></li>
+                  <li><a href="#1.7.2.exerc">7.2. Stolik w restauracji</a></li>
+                  <li><a href="#1.7.3.exerc">7.3. Wielokrotność dziesięciu</a></li>
+                  <li><a href="#1.7.4.exerc">7.4. Dodatki do pizzy</a></li>
+                  <li><a href="#1.7.5.exerc">7.5. Bilety do kina</a></li>
+                  <li><a href="#1.7.6.exerc">7.6. Trzy wyjścia.</a></li>
+                  <li><a href="#1.7.7.exerc">7.7. Nieskończoność</a></li>
+                  <li><a href="#1.7.8.exerc">7.8. Bar</a></li>
+                  <li><a href="#1.7.9.exerc">7.9. Brak pastrami</a></li>
+                  <li><a href="#1.7.10.exerc">7.10. Wymarzone wakacje</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.8.ch">Rozdział 8:</a>
+                <ul class="toc">
+                  <li><a href="#1.8.1.exerc">8.1. Komunikat</a></li>
+                  <li><a href="#1.8.2.exerc">8.2. Ulubiona książka</a></li>
+                  <li><a href="#1.8.3.exerc">8.3. T-shirt</a></li>
+                  <li><a href="#1.8.4.exerc">8.4. Duże koszulki</a></li>
+                  <li><a href="#1.8.5.exerc">8.5. Miasta</a></li>
+                  <li><a href="#1.8.6.exerc">8.6. Nazwy miast</a></li>
+                  <li><a href="#1.8.7.exerc">8.7. Album</a></li>
+                  <li><a href="#1.8.8.exerc">8.8. Albumy użytkowników</a></li>
+                  <li><a href="#1.8.9.exerc">8.9. Komunikaty</a></li>
+                  <li><a href="#1.8.10.exerc">8.10. Wysyłanie komunikatów</a></li>
+                  <li><a href="#1.8.11.exerc">8.11. Zarchiwizowane komunikaty</a></li>
+                  <li><a href="#1.8.12.exerc">8.12. Kanapki</a></li>
+                  <li><a href="#1.8.13.exerc">8.13. Profil użytkownika</a></li>
+                  <li><a href="#1.8.14.exerc">8.14. Samochody</a></li>
+                  <li><a href="#1.8.15.exerc">8.15. Wydruk modeli</a></li>
+                  <li><a href="#1.8.16.exerc">8.16. Polecenia importu</a></li>
+                  <li><a href="#1.8.17.exerc">8.17. Nadanie stylu funkcjom</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.9.ch">Rozdział 9: </a>
+                <ul class="toc">
+                  <li><a href="#1.9.1.exerc">9.1. Restauracja</a></li>
+                  <li><a href="#1.9.2.exerc">9.2. Trzy restauracje</a></li>
+                  <li><a href="#1.9.3.exerc">9.3. Użytkownicy</a></li>
+                  <li><a href="#1.9.4.exerc">9.4. Liczba obsłużonych</a></li>
+                  <li><a href="#1.9.5.exerc">9.5. Próby logowania</a></li>
+                  <li><a href="#1.9.6.exerc">9.6. Budka z lodami</a></li>
+                  <li><a href="#1.9.7.exerc">9.7. Admin</a></li>
+                  <li><a href="#1.9.8.exerc">9.8. Uprawnienia</a></li>
+                  <li><a href="#1.9.9.exerc">9.9. Uaktualnienie akumulatora</a></li>
+                  <li><a href="#1.9.10.exerc">9.10. Zaimportowana klasa Restaurant</a></li>
+                  <li><a href="#1.9.11.exerc">9.11. Zaimportowana klasa Admin</a></li>
+                  <li><a href="#1.9.12.exerc">9.12. Wiele modułów</a></li>
+                  <li><a href="#1.9.13.exerc">9.13. Kości do gry</a></li>
+                  <li><a href="#1.9.14.exerc">9.14. Loteria</a></li>
+                  <li><a href="#1.9.15.exerc">9.15. Analiza loterii</a></li>
+                  <li><a href="#1.9.16.exerc">9.16. Moduł Pythona tygodnia</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.10.ch">Rozdział 10:</a>
+                <ul class="toc">
+                  <li><a href="#1.10.1.exerc">10.1. Poznajemy Pythona</a></li>
+                  <li><a href="#1.10.2.exerc">10.2. Poznajemy C</a></li>
+                  <li><a href="#1.10.3.exerc">10.3. Gość</a></li>
+                  <li><a href="#1.10.4.exerc">10.4. Księga gości</a></li>
+                  <li><a href="#1.10.5.exerc">10.5. Ankieta dotycząca programowania</a></li>
+                  <li><a href="#1.10.6.exerc">10.6. Dodawanie</a></li>
+                  <li><a href="#1.10.7.exerc">10.7. Kalkulator dodawania</a></li>
+                  <li><a href="#1.10.8.exerc">10.8. Koty i psy</a></li>
+                  <li><a href="#1.10.9.exerc">10.9. Ciche koty i psy</a></li>
+                  <li><a href="#1.10.10.exerc">10.10. Najczęściej występujące słowa.</a></li>
+                  <li><a href="#1.10.11.exerc">10.11. Ulubiona liczba</a></li>
+                  <li><a href="#1.10.12.exerc">10.12. Zapamiętana ulubiona liczba</a></li>
+                  <li><a href="#1.10.13.exerc">10.13. Weryfikacja użytkownika.</a></li>
+                </ul>
+              </li>
+              <li><a href="#1.11.ch">Rozdział 11:</a>
+                <ul class="toc">
+                  <li><a href="#1.11.1.exerc">11.1. Miasto, państwo</a></li>
+                  <li><a href="#1.11.2.exerc">11.2. Populacja</a></li>
+                  <li><a href="#1.11.3.exerc">11.3. Pracownik</a></li>
+                </ul>
+              </li>
+            </ul>
+          </li>
+          <li><a href="#2.part">Część II - Aplikacje internetowe</a>
+            <ul class="toc">
+              <li><a href="#2.1.ch">Rozdział 18:</a>
+                <ul class="toc">
+                  <li><a href="#2.1.1.exerc">18.1. Nowe projekty</a></li>
+                  <li><a href="#2.1.2.exerc">18.2. Krótkie wpisy</a></li>
+                  <li><a href="#2.1.3.exerc">18.3. API Django</a></li>
+                  <li><a href="#2.1.4.exerc">18.4. Pizzeria</a></li>
+                  <li><a href="#2.1.5.exerc">18.5. Jadłospis</a></li>
+                  <li><a href="#2.1.6.exerc">18.6. Strona główna pizzerii</a></li>
+                  <li><a href="#2.1.7.exerc">18.7. Dokumentacja szablonów</a></li>
+                  <li><a href="#2.1.8.exerc">18.8. Strony pizzerii.</a></li>
+                </ul>
+              </li>
+              <li><a href="#2.2.ch">Rozdział 19:</a>
+                <ul class="toc">
+                  <li><a href="#2.2.1.exerc">19.1. Blog</a></li>
+                  <li><a href="#2.2.2.exerc">19.2. Konta bloga.</a></li>
+                  <li><a href="#2.2.3.exerc">19.3. Refaktoryzacja</a></li>
+                  <li><a href="#2.2.4.exerc">19.4. Ochrona strony new_entry.</a></li>
+                  <li><a href="#2.2.5.exerc">19.5. Ochrona bloga</a></li>
+                </ul>
+              </li>
+              <li><a href="#2.3.ch">Rozdział 20:</a>
+                <ul class="toc">
+                  <li><a href="#2.3.1.exerc">20.1. Inne formularze</a></li>
+                  <li><a href="#2.3.2.exerc">20.2. Nadanie stylu blogowi</a></li>
+                  <li><a href="#2.3.3.exerc">20.3. Wdrożenie bloga</a></li>
+                  <li><a href="#2.3.4.exerc">20.4. Więcej błędów 404</a></li>
+                  <li><a href="#2.3.5.exerc">20.5. Rozbudowa aplikacji Learning Log</a></li>
+                </ul>
+              </li>
+            </ul>
+          </li>
+             </ol>
+        <p>
+        Źródła:
+        </p>
+        <ol>
+          <li><strong>Python. Instrukcje dla programisty. Wydanie II</strong>,
+            <em>Eric Matthes</em> Helion @ 2020</li>
+        </ol>
+        <p class="footer">
+                                 2022; COPYLEFT; ALL RIGHTS REVERSED;
+                         </p>
+      </div>
+      <div id="content">
+      <div id="contentHeader">
+<pre id="divisionBaner">
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p id="contentHeaderLink" class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+      </div>
+<h1 id="1.part">Część I - Python.</h1>
+<p>
+          <strong>Uwaga!</strong> Poniższy zbiór cwiczeń został skopiowany
+          bezpośrednio z ksiązki (poz. 1 w źródłach) z sekcji 
+          <em>ZRÓB TO SAM</em>.
+        </p>
+
+<h2 id="1.1.ch">Rozdział 1:</h2>
+<h3 id="1.1.1.exerc">1.1. Witryna python.org</h3> 
+<p>
+  Zapoznaj się ze stroną domową <em>Pythona</em> (<em>http://python.org/</em>) 
+  i spróbuj wyszukać interesujące Cię tematy. Gdy zdobędziesz
+  nieco więcej doświadczenia w programowaniu w Pythonie, poszczególne części
+  tej witryny staną się dla Ciebie znacznie użyteczniejsze.
+<p>
+<h3 id="1.1.2.exerc">1.2. Błędy w programie typu „Witaj, świecie!”</h3>
+<p>
+  Otwórz utworzony w tym 
+  rozdziale plik <em>hello_world.py</em>. Wprowadź dowolny błąd w wierszu kodu,
+  a następnie uruchom program. Czy potrafisz wprowadzić zmianę powodującą 
+  wygenerowanie komunikatu błędu? Czy ten komunikat błędu ma dla Ciebie sens?
+  Czy potrafisz wprowadzić zmianę niepowodującą wygenerowania błędu? Na
+  jakiej podstawie uważasz, że ta zmiana nie jest błędem?
+</p>
+<h3 id="1.1.3.exerc">1.3. Niczym nieograniczone umiejętności</h3>
+<p>
+  Gdybyś posiadał nieograniczone
+  umiejętności w zakresie programowania, jaki program byś stworzył? Dzięki tej
+  książce masz nauczyć się programować. Jeżeli będziesz miał na uwadze pewien
+  cel, który sam sobie wyznaczysz, zyskasz możliwość częściowego 
+  wykorzystania nowo nabytych umiejętności. Teraz jest więc doskonały moment 
+  na określenie tego, co chciałbyś stworzyć. Dobrym rozwiązaniem jest 
+  prowadzenie dziennika „idei”, do którego będziesz mógł się odwoływać, 
+  rozpoczynając pracę nad nowym projektem. Poświęć kilka minut na opisanie 
+  trzech programów, które chciałbyś stworzyć.
+</p>
+<h2 id="1.2.ch">Rozdział 2:</h2>
+<p>
+  Utwórz oddzielne programy dla każdego z poniższych ćwiczeń. Poszczególne
+  programy umieszczaj w plikach o nazwach zgodnych ze standardowymi konwencjami
+  <em>Pythona</em>, czyli zawierających jedynie małe litery i znaki 
+  podkreślenia, na przykład <em>prosty_komunikat.py</em> i 
+  <em>proste_komunikaty.py</em>.
+</p>
+<h3 id="1.2.1.exerc">2.1. Prosty komunikat</h3>
+<p>
+  Umieść komunikat w zmiennej, a następnie wyświetl go.
+</p>
+<h3 id="1.2.2.exerc">2.2. Proste komunikaty</h3>
+<p>
+  Umieść komunikat w zmiennej, a następnie go
+  wyświetl. Później zmień wartość zmiennej tak, aby zawierała inny komunikat,
+  i ten nowy komunikat również wyświetl.
+</p>
+<h3 id="1.2.3.exerc">2.3. Osobiste powitanie</h3>
+<p>
+  Zapisz w zmiennej imię osoby, a następnie wyświetl
+  dla niej komunikat powitania. Komunikat powinien być prosty, na przykład
+  <code class="code-inline">„Witaj, Eryk! Czy chcesz dzisiaj poznawać Pythona?”</code>.
+</p>
+<h3 id="1.2.4.exerc">2.4. Wielkość liter w imionach</h3>
+<p>
+  Zapisz w zmiennej imię osoby, a następnie
+  wyświetl je za pomocą małych liter, wielkich liter oraz z użyciem wielkiej 
+  litery jako pierwszej litery imienia.
+</p>
+<h3 id="1.2.5.exerc">2.5. Sławny cytat</h3> 
+<p>
+  Odszukaj cytat sławnej osoby, którą cenisz. Wyświetl ten
+  cytat wraz z imieniem i nazwiskiem jego autora. Wygenerowane dane wyjściowe
+  powinny wyglądać tak, jak pokazałem poniżej, łącznie ze znakami cytowania:
+  Albert Einstein powiedział kiedyś: 
+  <code class="code-inline">"Osoba, która nigdy nie popełniła błędu,
+  jest kimś, kto nigdy nie próbował niczego nowego"</code>.
+</p>
+<h3 id="1.2.6.exerc">2.6. Sławny cytat 2</h3>
+<p>
+  Powtórz ćwiczenie 2.5, ale tym razem imię i nazwisko
+  autora cytatu umieść w zmiennej o nazwie <em>famous_person</em>. Następnie 
+  przygotuj komunikat i umieść go w nowej zmiennej o nazwie <em>message</em>. 
+  Na koniec wyświetl komunikat.
+</p>
+<h3 id="1.2.7.exerc">2.7. Usunięcie białych znaków z imienia</h3>
+<p>
+  Zapisz w zmiennej imię osoby
+  wraz z pewnymi białymi znakami na początku i końcu imienia. Upewnij się,
+  że co najmniej raz użyłeś sekwencji <em>\t</em> i <em>\n</em>.
+</p>
+<p>
+  Wyświetl to imię wraz ze znakami odstępu. Następnie wyświetl je jeszcze trzy
+  razy, ale za każdym razem wykorzystaj jedną z metod przeznaczonych do
+  usuwania białych znaków: <em>lstrip()</em>, <em>rstrip()</em> i 
+  <em>strip()</em>.
+</p>
+<h3 id="1.2.8.exerc">2.8. Liczba osiem</h3>
+<p>
+  Zapisz operacje dodawania, odejmowania, mnożenia i 
+  dzielenia, których wynikiem będzie liczba 8. Upewnij się, że użyłeś funkcji 
+  <em>print()</em>, aby wyświetlić wyniki. Powinieneś utworzyć cztery wiersze,
+  które będą wyglądały tak jak ten poniżej:
+</p>
+<pre class="code-block">
+print(5 + 3)
+</pre>
+<p>
+  Wygenerowane dane wyjściowe powinny składać się po prostu z czterech wierszy
+  wraz z liczbą 8 pojawiającą się jednokrotnie w każdym z nich.
+</p>
+<h3 id="1.2.9.exerc">2.9. Ulubiona liczba</h3>
+<p>
+  Umieść w zmiennej ulubioną liczbę. Następnie 
+  używając tej zmiennej, utwórz komunikat ujawniający tę ulubioną liczbę. 
+  Wyświetl ten komunikat.
+</p>
+<h3 id="1.2.10.exerc">2.10. Dodawanie komentarzy</h3>
+<p>
+  Wybierz dwa utworzone dotąd programy
+  i umieść w nich przynajmniej po jednym komentarzu. Jeżeli nie masz nic 
+  ciekawego do napisania z powodu prostoty dotychczasowych programów, wpisz
+  na początku pliku po prostu imię i datę. Następnie dodaj jedno zdanie 
+  opisujące przeznaczenie danego programu.
+</p>
+<h3 id="1.2.11.exerc">2.11. Zen Pythona</h3> 
+<p>
+  Wydaj polecenie <code class="code-inline">import this</code> w powłoce 
+  <em>Pythona</em> i przejrzyj
+  reguły, które nie zostały przedstawione w tym rozdziale.
+</p>
+<h2 id="1.3.ch">Rozdział 3:</h2>
+<p>
+  Wypróbuj poniższe krótkie programy, aby zdobyć nieco doświadczenia w pracy
+  z listami Pythona. Możesz utworzyć nowy katalog dla ćwiczeń w poszczególnych
+  rozdziałach, aby tym samym trochę je uporządkować.
+</p>
+<h3 id="1.3.1.exerc">3.1. Imiona</h3>
+<p>
+  Utwórz listę o nazwie names i umieść na niej imiona kilku 
+  przyjaciół. Wyświetl wszystkie imiona przez uzyskanie dostępu do 
+  poszczególnych elementów listy (za każdym razem do jednego).
+</p>
+<h3 id="1.3.2.exerc">3.2. Powitania</h3>
+<p>
+  Rozpocznij od listy utworzonej w ćwiczeniu 3.1, ale zamiast
+  samego imiona osoby wyświetl komunikat, który będzie jej dotyczył. Tekst
+  wszystkich komunikatów powinien pozostać taki sam, ale mają być one 
+  spersonalizowane dzięki wykorzystaniu imienia konkretnej osoby.
+</p>
+<h3 id="1.3.3.exerc">3.3. Twoja własna lista</h3>
+<p>
+  Zastanów się nad ulubionymi środkami transportu,
+  na przykład motocykl lub samochód, a następnie utwórz listę przechowującą
+  wiele przykładów. Wykorzystaj tę listę do wyświetlenia kilku zdań o jej 
+  elementach, na przykład „Chciałbym mieć motocykl Honda”.
+</p>
+<h3 id="1.3.4.exerc">3.4. Lista gości</h3>
+<p>
+  Jeżeli mógłbyś zaprosić kogokolwiek na obiad, żyjącego lub
+  nieżyjącego, to kogo byś zaprosił? Utwórz listę zawierającą przynajmniej 
+  trzy osoby, które chciałbyś zaprosić na obiad. Następnie wykorzystaj tę 
+  listę do wyświetlenia dla każdej z tych osób komunikatu zapraszającego ją 
+  na obiad.
+</p>
+<h3 id="1.3.5.exerc">3.5. Zmiana listy gości</h3>
+<p>
+Dowiedziałeś się, że jedna z zaproszonych osób nie
+może przyjść na obiad. Konieczne jest więc wysłanie następnych zaproszeń.
+Zastanów się, kogo w takim razie jeszcze zaprosisz.
+<p>
+<ul class="special_list">
+  <li>Pracę rozpocznij od programu utworzonego w ćwiczeniu 3.4. Na jego
+      końcu umieść polecenie <em>print()</em> wyświetlające komunikat z 
+      informacją, który z zaproszonych gości nie może przyjść.</li>
+  <li>Zmodyfikuj listę i dane gościa, który nie będzie mógł przybyć na obiad,
+      zastąp danymi nowej zaproszonej osoby.</li>
+  <li>Wyświetl drugi zestaw komunikatów z zaproszeniem, po jednym
+      komunikacie dla każdej osoby znajdującej się na liście.</li>
+</ul>
+<h3 id="1.3.6.exerc">3.6. Więcej gości</h3>
+<p>
+Znalazłeś większy stół, co oznacza więcej miejsca dla 
+gości. Zastanów się więc nad jeszcze trzema osobami, które mógłbyś zaprosić
+na obiad.
+</p>
+<ul class="special_list">
+  <li>Pracę rozpocznij od programu utworzonego w ćwiczeniach 3.4 i 3.5.
+      Na jego końcu umieść polecenie <em>print()</em> wyświetlające komunikat o 
+      znalezieniu większego stołu.</li>
+  <li>Za pomocą metody <em>insert()</em> dodaj nowego gościa na początku listy.</li>
+  <li>Za pomocą metody <em>insert()</em> dodaj nowego gościa w środku listy.</li>
+  <li>Za pomocą metody <em>append()</em> dodaj nowego gościa na końcu listy.</li>
+  <li>Wyświetl nowy zestaw komunikatów z zaproszeniem, po jednym
+      komunikacie dla każdej osoby znajdującej się na liście.</li>
+</ul>
+<h3 id="1.3.7.exerc">3.7. Kurcząca się lista gości</h3>
+<p>
+Okazało się, że większy stół nie zostanie 
+dostarczony na czas i dlatego masz miejsce dla jedynie dwóch gości.
+</p>
+<ul class="special_list">
+  <li>Pracę rozpocznij od programu utworzonego w ćwiczeniu 3.6. Dodaj
+      nowy wiersz wyświetlający komunikat, że na obiad możesz zaprosić
+      tylko dwie osoby.</li>
+  <li>Za pomocą metody <em>pop()</em> usuwaj po jednym gościu z listy, aż 
+      zostaną na niej tylko dwie osoby. Po usunięciu każdej osoby wyświetlaj
+      przeznaczony dla niej komunikat z przeprosinami za brak możliwości
+      zaproszenia jej na obiad</li>
+  <li>Obu osobom pozostałym na liście wyświetl spersonalizowany komunikat
+      z zaproszeniem na obiad.</li>
+  <li>Użyj polecenia <em>del</em> do usunięcia dwóch ostatnich osób z listy, 
+      która w ten sposób powinna stać się pusta. Na koniec wyświetl listę, aby 
+      upewnić się, że faktycznie jest pusta.</li>
+</ul>
+<h3 id="1.3.8.exerc">3.8. Zwiedzaj świat</h3>
+<p>
+Pomyśl o pięciu miejscach na świecie, które chciałbyś
+odwiedzić.
+</p>
+<ul class="special_link">
+  <li>Wszystkie miejsca umieść na liście i upewnij się, że nie jest ona 
+      ułożona alfabetycznie.</li>
+  <li>Wyświetl listę w jej pierwotnej kolejności. Nie przejmuj się eleganckim
+      wyświetleniem listy, a po prostu wyświetl ją jako zwykłą listę 
+      <em>Pythona</em>.
+  </li>
+  <li>Za pomocą funkcji <em>sorted()</em> wyświetl listę w kolejności 
+      alfabetycznej bez modyfikacji rzeczywistej listy.</li>
+  <li>Ponownie wyświetl listę początkową, aby pokazać, że nie została
+      zmodyfikowana.</li>
+  <li>Za pomocą funkcji <em>sorted()</em> wyświetl listę w odwrotnej kolejności
+      alfabetycznej bez modyfikacji rzeczywistej listy.</li>
+  <li>Ponownie wyświetl listę początkową, aby pokazać, że nie została
+      zmodyfikowana.</li>
+  <li>Za pomocą metody <em>reverse()</em> zmień kolejność listy, a następnie 
+      wyświetl ją, aby potwierdzić zmianę kolejności.</li>
+  <li>Ponownie wykorzystaj metodę <em>reverse()</em> do zmiany kolejności listy.
+      Wyświetl ją, aby pokazać, że powróciła do pierwotnej kolejności.</li>
+  <li>Za pomocą metody <em>sort()</em> zmień kolejność listy na alfabetyczną,
+      a następnie wyświetl ją, aby potwierdzić zmianę kolejności.</li>
+  <li>Za pomocą metody <em>sort()</em> zmień kolejność listy na odwrotnie 
+      alfabetyczną,
+      a następnie wyświetl ją, aby potwierdzić zmianę kolejności.</li>
+</ul>
+<h3 id="1.3.9.exerc">3.9. Goście na obiad</h3>
+<p>
+Pracę rozpocznij od jednego z programów utworzonych w
+ćwiczeniach od 3.4 do 3.7. Za pomocą funkcji <em>len()</em> wyświetl komunikat 
+wskazujący liczbę osób, które zostały zaproszone na obiad.
+</p>
+
+<h3 id="1.3.10.exerc">3.10. Każda funkcja.</h3>
+<p>
+Zastanów się, jakie informacje mógłbyś umieścić na 
+liście. Na przykład utwórz listę gór, rzek, państw, miast, języków lub 
+czegokolwiek innego. Przygotuj program, który będzie tworzył listę 
+przechowującą te informacje i używał co najmniej jeden raz każdej funkcji 
+wprowadzonej w tym rozdziale.
+</p>
+<h3 id="1.3.11.exerc">3.11. Celowy błąd</h3> 
+<p>
+Jeżeli jeszcze w żadnym z tworzonych programów nie
+spotkałeś się z błędem indeksu, spróbuj go teraz wywołać. W dowolnym 
+programie tak zmień wartość indeksu, aby nastąpiło zgłoszenie błędu indeksu.
+Zanim zamkniesz plik programu, upewnij się, że usunąłeś błąd.
+</p>
+<h2 id="1.4.ch">Rozdział 4:</h2>
+<h3 id="1.4.1.exerc">4.1. Pizza</h3>
+<p>
+Pomyśl o przynajmniej trzech rodzajach pizzy. Umieść te nazwy
+na liście, a następnie wyświetl je za pomocą pętli <em>for</em>.
+</p>
+<ul class="special_list">
+  <li>Zmodyfikuj pętlę <em>for</em> w taki sposób, aby zamiast samej nazwy 
+      pizzy
+      wyświetlała zdanie wykorzystujące tę nazwę. Dla każdego rodzaju pizzy
+      powinieneś mieć jeden wiersz danych wyjściowych zawierający proste
+      zdanie w stylu: „Lubię pizzę pepperoni”.</li>
+  <li>Poza blokiem pętli, na końcu programu dodaj zdanie informujące o tym,
+      jak bardzo lubisz pizzę. Wygenerowane dane wyjściowe powinny więc
+      składać się z co najmniej trzech zdań o Twoich ulubionych rodzajach 
+      pizzy oraz jednego zdania dodatkowego w stylu: „Naprawdę uwielbiam 
+      pizzę!”.</li>
+</ul>
+<h3 id="1.4.2.exerc">4.2. Zwierzęta</h3>
+<p>
+Spróbuj znaleźć trzy różne zwierzęta charakteryzujące się
+podobnymi cechami. Umieść ich nazwy na liście, a następnie wyświetl je za
+pomocą pętli <em>for</em>.
+</p>
+<ul class="special_list">
+  <li>Zmodyfikuj program w taki sposób, aby wyświetlał zdanie dotyczące danego
+      zwierzęcia, na przykład „Pies jest prawdziwym przyjacielem człowieka.
+  </li>
+  <li>Na końcu programu umieść zdanie wskazujące na jakieś podobieństwo
+      między wymienionymi wcześniej zwierzętami. To może być zdanie w stylu:
+      „Wszystkie wymienione powyżej zwierzęta są wspaniałe!”.</li>
+</ul>
+<h3 id="1.4.3.exerc">4.3. Odliczanie do dwudziestu</h3>
+<p>
+Użyj pętli <em>for</em> do wyświetlenia liczb od 1 do 
+20 włącznie.
+</p>
+<h3 id="1.4.4.exerc">4.4. Milion</h3>
+<p>
+Utwórz listę liczb od jednego do miliona, a następnie wyświetl 
+ją za pomocą pętli <em>for</em>. (Jeżeli proces wyświetlania danych 
+wyjściowych trwa zbyt długo, zatrzymaj go przez naciśnięcie klawiszy 
+<em>Ctrl+C</em> lub po 
+prostu przez zamknięcie okna danych wyjściowych).
+</p>
+<h3 id="1.4.5.exerc">4.5. Sumowanie do miliona</h3>
+<p>
+Utwórz listę liczb od jednego do miliona, a następnie za pomocą funkcji 
+<em>min()</em> i <em>max()</em> sprawdź, czy lista faktycznie zaczyna
+się od wartości jeden i kończy na milionie. Ponadto wykorzystaj funkcję 
+<em>sum()</em>, aby zobaczyć, jak szybko <em>Python</em> może dodać milion 
+liczb.
+</p>
+<h3 id="1.4.6.exerc">4.6. Listy nieparzyste</h3>
+<p>
+Za pomocą trzeciego argumentu funkcji <em>range()</em> utwórz
+listę liczb nieparzystych z zakresu od 1 do 20, a następnie wyświetl je za 
+pomocą pętli <em>for</em>.
+</p>
+<h3 id="1.4.7.exerc">4.7. Trzy</h3>
+<p>
+Utwórz listę liczb od 3 do 30 podniesionych do trzeciej potęgi, 
+a następnie wyświetl zawartość listy za pomocą pętli <em>for</em>.
+</p>
+<h3 id="1.4.8.exerc">4.8. Sześcian</h3>
+<p>
+Liczba podniesiona do trzeciej potęgi jest nazywana 
+sześcianem. Na przykład sześcian liczby 2 jest zapisywany w <em>Pythonie</em> 
+jako 
+2**3. Utwórz listę pierwszych dziesięciu sześcianów (to znaczy liczb od 1 
+do 10 podniesionych do trzeciej potęgi), a następnie wyświetl je za pomocą 
+pętli <em>for</em>.
+</p>
+<h3 id="1.4.9.exerc">4.9. Sześcian za pomocą listy składanej</h3> 
+<p>
+Wykorzystaj listę składaną do 
+wygenerowania listy pierwszych dziesięciu sześcianów.
+</p>
+<h3 id="1.4.10.exerc">4.10. Wycinki</h3>
+<p>
+Pracę rozpocznij od jednego z programów utworzonych w tym
+rozdziale, a następnie na końcu dodaj kilka wierszy kodu wykonujących 
+wymienione poniżej zadania:
+</p>
+<ul class="special_list">
+  <li>Wyświetlenie komunikatu „Pierwsze trzy elementy listy to:”. Następnie
+      za pomocą wycinka wyświetl trzy pierwsze elementy listy.</li>
+  <li>Wyświetlenie komunikatu „Trzy elementy w środku listy to:”. Następnie
+      za pomocą wycinka wyświetl trzy elementy znajdujące się w środku listy.
+  </li>
+  <li>Wyświetlenie komunikatu „Ostatnie trzy elementy listy to:”. Następnie
+      za pomocą wycinka wyświetl trzy ostatnie elementy listy.</li>
+</ul>
+<h3 id="1.4.11.exerc">4.11. Moja pizza, Twoja pizza</h3>
+<p>
+Pracę rozpocznij od programu utworzonego
+w ćwiczeniu 4.1 we wcześniejszej części rozdziału. Utwórz kopię listy z 
+pizzami i nadaj jej nazwę <em>friend_pizzas</em>. Teraz wykonaj wymienione 
+poniżej zadania:
+</p>
+<ul class="special_list">
+  <li>Dodaj nową pizzę do listy początkowej.</li>
+  <li>Dodaj pizzę (inną niż w poprzednim punkcie) do listy 
+      <em>friend_pizzas</em>.</li>
+  <li>Sprawdź, czy faktycznie masz dwie oddzielne listy. Wyświetl komunikat
+      „Moje ulubione rodzaje pizzy to:”, a następnie użyj pętli <em>for</em>
+      do wyświetlenia zawartości pierwszej listy. Teraz wyświetl komunikat
+      „Ulubione rodzaje pizzy mojego przyjaciela to:” i za pomocą pętli 
+      <em>for</em>
+      wyświetl zawartość drugiej listy. Upewnij się, że każda nowa pizza 
+      została umieszczona na odpowiedniej liście.</li>
+</ul>
+<h3 id="1.4.12.exerc">4.12. Więcej pętli</h3>
+<p>
+We wszystkich programach <em>foods.py</em> przedstawionych w tym
+rozdziale unikałem użycia pętli <em>for</em>, aby zaoszczędzić nieco miejsca. 
+Wybierz
+dowolną wersję programu <em>foods.py</em>, a następnie utwórz dwie pętle 
+<em>for</em>  w celu wyświetlenie obu list potraw.
+</p>
+<h3 id="1.4.13.exerc">4.13. Bufet</h3>
+<p>
+Restauracja w stylu bufetu oferuje jedynie pięć prostych 
+potraw. Wymień więc pięć prostych potraw i umieść je w krotce.
+</p>
+<ul class="special_list">
+  <li>Za pomocą pętli <em>for</em> wyświetl wszystkie potrawy oferowane przez
+      restaurację.</li>
+  <li>Spróbuj zmodyfikować jeden z elementów i upewnij się, że <em>Python</em>
+      odrzucił tę zmianę.</li>
+  <li>Restauracja zmienia menu i zastępuje dwie dotychczasowe potrawy
+      nowymi. Dodaj blok kodu nadpisujący krotkę, a następnie wykorzystaj
+      pętlę <em>for</em> do wyświetlenia wszystkich potraw ze zmodyfikowanego 
+      menu.</li>
+</ul>
+<h3 id="1.4.14.exerc">4.14. Specyfikacja PEP 8</h3>
+<p>
+Przejrzyj specyfikację <em>PEP 8</em>, którą znajdziesz na
+stronie https://www.python.org/dev/peps/pep-0008/. W tym momencie 
+niewiele z niej skorzystasz, ale i tak warto ją przynajmniej przejrzeć.
+</p>
+<h3 id="1.4.15.exerc">4.15. Przegląd kodu</h3>
+<p>
+Wybierz trzy dowolne programy z tych, które przygoto-
+wałeś w tym rozdziale, a następnie zmodyfikuj je, aby stały się zgodne z 
+<em>PEP 8</em>.
+</p>
+<ul class="special_link">
+  <li>Używaj czterech spacji dla każdego poziomu wcięć. Jeżeli jeszcze tego
+      nie zrobiłeś, skonfiguruj edytor tekstu w taki sposób, aby wstawiał 
+      cztery spacje za każdym razem, gdy naciśniesz klawisz tabulacji (więcej 
+      informacji na ten temat znajdziesz w dodatku B).</li>
+  <li>Używaj mniej niż 80 znaków w każdym wierszu. W edytorze tekstu włącz
+      wyświetlanie pionowej linii wskazującej położenie 80. znaku.</li>
+  <li>W programie oszczędnie używaj pustych wierszy.</li>
+</ul>
+<h2 id="1.5.ch">Rozdział 5:</h2>
+<h3 id="1.5.1.exerc">5.1. Testy warunkowe</h3>
+<p>
+Utwórz serię testów warunkowych. Wyświetl 
+polecenia opisujące poszczególne testy oraz przewidywany wynik. Przygotowany
+przez Ciebie kod powinien być podobny do poniższego:
+</p>
+<pre class="code-block">
+car = 'subaru'
+print("Czy car == 'subaru'? Przewiduję wartość True.")
+print(car == 'subaru')
+print("\nCzy car == 'audi'? Przewiduję wartość False.")
+print(car == 'audi')
+</pre>
+<ul class="special_list">
+  <li>Przyjrzyj się dokładnie uzyskanym wynikom i upewnij się, że zrozumiałeś,
+      dlaczego wartością danego testu jest <em>True</em> lub <em>False</em>.
+  </li>
+  <li>Utwórz przynajmniej 10 testów. Niech co najmniej pięć z nich przyjmuje
+      wartość <em>True</em>, a kolejne pięć wartość <em>False</em>.</li>
+</ul>
+<h3 id="1.5.2.exerc">5.2. Więcej testów warunkowych.</h3>
+<p>
+Nie musisz ograniczać się tylko do 10
+testów. Jeżeli chcesz wypróbować inne porównania, utwórz następne testy
+i umieść je w pliku <em>conditional_tests.py</em>. Powinieneś otrzymać co 
+najmniej po jednym wyniku <em>True</em> i <em>False</em> dla wymienionych 
+poniżej testów:
+</p>
+<ul class="special_list">
+  <li>Sprawdzenie równości i nierówności ciągów tekstowych.</li>
+  <li>Test z użyciem funkcji <em>lower()</em>.</li>
+  <li>Testy liczbowe obejmujące sprawdzenie równości i nierówności, operacje
+      większy niż i mniejszy niż, a także większy niż lub równy i mniejszy niż
+      lub równy.</li>
+  <li>Testy wykorzystujące słowa kluczowe <em>and</em> i <em>or</em>.</li>
+  <li>Sprawdzanie, czy element znajduje się na liście.</li>
+  <li>Sprawdzanie, czy element nie znajduje się na liście.</li>
+</ul>
+<h3 id="1.5.3.exerc">5.3. Kolory obcych, część 1.</h3>
+<p>
+Wyobraź sobie zestrzelenie obcego w grze. 
+Utwórz zmienną o nazwie <em>alien_color</em> i przypisz jej wartość 'zielony', 
+'żółty' lub 'czerwony'.
+</p>
+<ul class="special_link">
+  <li>Przygotuj polecenie <em>if</em> sprawdzające, czy kolorem obcego jest 
+      zielony. Jeżeli tak, wyświetl komunikat informujący gracza, że zarobił 
+      pięć punktów.</li>
+  <li>Przygotuj wersję programu zaliczającą powyższy test oraz drugą
+      niezaliczającą. (Wersja kończąca się niepowodzeniem nie powinna
+      generować żadnych danych wyjściowych).</li>
+</ul>
+<h3 id="1.5.4.exerc">5.4. Kolory obcych, część 2</h3>
+<p>
+Podobnie jak w ćwiczeniu 5.3 wybierz kolor dla
+obcego, a następnie utwórz konstrukcję <em>if-else</em>.
+</p>
+<ul class="special_link">
+  <li>Jeżeli kolor obcego to zielony, wyświetl komunikat informujący gracza,
+      że zarobił pięć punktów za zestrzelenie tego obcego.</li>
+  <li>Jeżeli kolor obcego jest inny niż zielony, wyświetl komunikat 
+      informujący gracza, że zarobił dziesięć punktów za zestrzelenie tego 
+      obcego.</li>
+  <li>Przygotuj wersję programu wykonującą blok <em>if</em> oraz drugą 
+      wykonującą blok <em>else</em>.</li>
+</ul>
+<h3 id="1.5.5.exerc">5.5. Kolory obcych, część 3</h3>
+<p>
+Przygotowaną w ćwiczeniu 5.4 konstrukcję
+<em>if-else</em> zastąp konstrukcją <em>if-elif-else</em>.
+</p>
+<ul class="special_list">
+  <li>Jeżeli kolor obcego to zielony, wyświetl komunikat informujący gracza,
+      że zarobił pięć punktów za zestrzelenie tego obcego.</li>
+  <li>Jeżeli kolor obcego to żółty, wyświetl komunikat informujący gracza,
+      że zarobił dziesięć punktów za zestrzelenie tego obcego.</li>
+  <li>Jeżeli kolor obcego to czerwony, wyświetl komunikat informujący gracza,
+      że zarobił piętnaście punktów za zestrzelenie tego obcego.</li>
+  <li>Przygotuj trzy wersje programu i upewnij się, że każdy komunikat 
+      zostanie wyświetlony dla odpowiedniego koloru zestrzelonego obcego.</li>
+</ul>
+<h3 id="1.5.6.exerc">5.6. Etapy życia</h3>
+<p>
+Przygotuj konstrukcję <em>if-else</em> ustalającą etap życia danej
+osoby. Przypisz wartość zmiennej <em>age</em>, a następnie:
+</p>
+<ul class="special_list">
+  <li>Jeżeli osoba ma mniej niż 2 lata, wyświetl komunikat informujący, że 
+      jest niemowlęciem.</li>
+  <li>Jeżeli osoba ma co najmniej 2 lata, ale mniej niż 4, wyświetl komunikat
+      informujący, że jest dzieckiem, które uczy się chodzić.</li>
+  <li>Jeżeli osoba ma co najmniej 4 lata, ale mniej niż 13, wyświetl komunikat
+      informujący, że jest dzieckiem.</li>
+  <li>Jeżeli osoba ma co najmniej 13 lat, ale mniej niż 20, wyświetl komunikat
+      informujący, że jest nastolatkiem.</li>
+  <li>Jeżeli osoba ma co najmniej 20 lat, ale mniej niż 65, wyświetl komunikat
+      informujący, że jest dorosłym.</li>
+  <li>Jeżeli osoba ma co najmniej 65 lat, wyświetl komunikat informujący, że 
+      jest seniorem.</li>
+</ul>
+<h3 id="1.5.7.exerc">5.7. Ulubione owoce</h3>
+<p>
+Przygotuj listę ulubionych owoców. Następnie utwórz
+serię niezależnych poleceń <em>if</em> sprawdzających obecność określonych 
+owoców na liście.
+</p>
+<ul class="special_list">
+  <li>Utwórz listę o nazwie <em>favorite_fruits</em> i umieść na niej trzy 
+      ulubione owoce.</li>
+  <li>Utwórz pięć poleceń <em>if</em>. Każde powinno sprawdzać obecność na 
+      liście
+      określonego rodzaju owocu. Jeżeli owoc znajduje się na liście, w bloku
+      <em>if</em> należy wyświetlić komunikat w stylu:
+      <code class="code-inline">„Naprawdę lubisz banany!”</code>.</li>
+</ul>
+<h3 id="1.5.8.exerc">5.8. Witaj, administratorze</h3>.
+<p>
+Przygotuj listę przynajmniej pięciu nazw 
+użytkowników, zawierającą między innymi nazwę <em>admin</em>. Wyobraź sobie, że 
+tworzysz kod odpowiedzialny za powitanie użytkownika po jego zalogowaniu się
+w witrynie internetowej. Przeprowadź iterację przez pętlę i dla każdego 
+użytkownika wyświetl powitanie.
+</p>
+<ul class="special_list">
+  <li>Jeżeli nazwa użytkownika to <em>admin</em>, wyświetl powitanie 
+      specjalne w stylu: 
+      <code class="code-inline">„Witaj, admin! Czy chcesz przejrzeć dzisiejszy raport?”.</code>
+  </li>
+  <li>Dla pozostałych użytkowników wyświetl zwykłe powitanie w stylu:
+      <code class="code-inline">„Witaj, Eryk! Dziękujemy, że ponownie się zalogowałeś”</code>.
+  </li>
+</ul>
+<h3 id="1.5.9.exerc">5.9. Brak użytkowników</h3>
+<p>
+Do przygotowanego w poprzednim ćwiczeniu pliku
+<em>hello_admin.py</em> dodaj polecenie <em>if</em> sprawdzające, czy lista 
+użytkowników nie jest pusta.
+</p>
+<ul class="special_list">
+  <li>Jeżeli lista jest pusta, wyświetl komunikat w stylu: „Musimy znaleźć 
+      jakichś użytkowników!”.</li>
+  <li>Usuń wszystkich użytkowników z listy i upewnij się, że powyższy 
+      komunikat został prawidłowo wyświetlony.</li>
+</ul>
+<h3 id="1.5.10.exerc">5.10. Sprawdzanie nazw użytkowników</h3>
+<p>
+Wykonaj poniższe działania w celu
+utworzenia programu symulującego sposób, w jaki witryna internetowa gwa-
+rantuje, że każdy użytkownik będzie miał unikatową nazwę. 
+</p>
+<ul class="special_list">
+  <li>Utwórz listę o nazwie <em>current_users</em> i umieść na niej 
+      przynajmniej pięć nazw użytkowników.</li>
+  <li>Utwórz kolejną listę o nazwie <em>new_users</em>. Upewnij się, że 
+      przynajmniej
+      jedna nazwa użytkownika z nowej listy znajduje się także na liście
+      <em>current_users</em>.</li>
+  <li>Przeprowadź iterację przez nową listę, aby sprawdzić, czy dana nazwa
+      użytkownika została już wcześniej użyta. Jeśli tak, wyświetl 
+      użytkownikowi komunikat o konieczności wyboru innej nazwy. Natomiast 
+      jeśli dana nazwa użytkownika nie została wcześniej użyta, wyświetl 
+      użytkownikowi komunikat informujący o możliwości jej wykorzystania.</li>
+  <li>Upewnij się, że w trakcie porównywania nazw użytkowników wielkość
+      liter nie ma znaczenia. Jeżeli wcześniej użyto nazwy 'Janek', nowy
+      użytkownik nie może wybrać dla siebie nazwy 'JANEK'. (To wymaga
+      utworzenia kopii listy <em>current_users</em> zawierającej zapisane 
+      małymi literami nazwy wszystkich użytkowników).</li>
+</ul>
+<h3 id="1.5.11.exerc">5.11. Liczby porządkowe</h3>
+Liczby porządkowe wskazują położenie elementu
+na liście, na przykład pierwszy, drugi, trzeci. W języku angielskim 
+większość tego rodzaju liczb kończy się na <em>th</em>, poza liczbami 1, 2 i 3.
+</h3>
+<ul class="special_list">
+  <li>Utwórz listę przechowującą liczby od 1 do 9.</li>
+  <li>Przeprowadź iterację przez listę.</li>
+  <li>Wykorzystaj konstrukcję <em>if-elif-else</em> wewnątrz pętli do 
+      prawidłowego
+      wyświetlenia liczb porządkowych w języku angielskim. Wygenerowane
+      dane wyjściowe powinny mieć postać 
+      <code class="code-inline">1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th</code>i
+      a każda liczba powinna znajdować się w osobnym wierszu.</li>
+</ul>
+<h3 id="1.5.12.exerc">5.12. Nadanie stylu konstrukcji if</h3>
+<p>
+Przejrzyj programy utworzone w tym
+rozdziale i upewnij się, że zastosowałeś w nich odpowiednie formatowanie
+testów warunkowych.
+</p>
+<h3 id="1.5.13.exerc">5.13. Twoje pomysły</h3>
+<p>
+Na tym etapie masz już znacznie większe możliwości
+w zakresie programowania niż na początku książki. Powinieneś już wyraźniej
+dostrzegać, jak rzeczywiste sytuacje mogą być modelowane w programach.
+Możesz więc zastanowić się nad problemami, które chciałbyś rozwiązywać
+we własnych programach. Zanotuj nowe idee dotyczące problemów, które
+chciałbyś rozwiązać, gdy zdobędziesz jeszcze większe umiejętności w 
+zakresie programowania. Zastanów się nad grami, które chciałbyś stworzyć, 
+zbiorami danych, które chciałbyś przeanalizować, lub aplikacjami 
+internetowymi, które chciałbyś zbudować.
+</p>
+<h2 id="1.6.ch">Rozdział 6:</h2>
+<h3 id="1.6.1.exerc">6.1. Osoba</h3>
+<p>
+Wykorzystaj słownik do przechowywania informacji o znanej Ci
+osobie. W słowniku powinny znaleźć się informacje takie jak imię, nazwisko,
+wiek i miasto zamieszkania. Powinieneś więc utworzyć klucze 
+<em>first_name</em>,
+<em>last_name</em>, <em>age</em> i <em>city</em>. Następnie wyświetl wszystkie 
+informacje przechowywane w słowniku.
+</p>
+<h3 id="1.6.2.exerc">6.2. Ulubione liczby</h3>
+<p>
+Wykorzystaj słownik do przechowywania ulubionych liczb
+różnych osób. Weź pod uwagę pięć osób i ich imion użyj w charakterze kluczy
+słownika. Następnie ustal ich ulubione liczby i umieść je w słowniku, 
+przypisując każdej osobie po jednej liczbie. Wyświetl imiona wszystkich osób
+i ich ulubione liczby. Jeżeli chcesz mieć więcej frajdy podczas wykonywania 
+tego ćwiczenia, zapytaj przyjaciół o ich ulubione liczby i umieść w 
+programie rzeczywiste dane.
+</p>
+<h3 id="1.6.3.exerc">6.3. Glosariusz</h3>
+<p>
+Słownik <em>Pythona</em> można wykorzystać do przygotowania rzeczy-
+wistego słownika. Jednak w celu uniknięcia niejasności nazwiemy go glosa-
+riuszem.
+</p>
+<ul class="special_list">
+  <li>Wypisz sobie pięć słów z dziedziny programowania, które poznałeś
+      we wcześniejszych rozdziałach. Te słowa będą kluczami w glosariuszu,
+      natomiast wartościami będą znaczenia poszczególnych słów.</li>
+  <li>Każde słowo i jego znaczenie wyświetl w postaci elegancko
+      sformatowanych danych wyjściowych. Możesz w jednym wierszu
+      wyświetlić słowo, dwukropek i później wyjaśnienie danego słowa.
+      Ewentualnie słowo umieść w jednym wierszu, a jego wyjaśnienie
+      w następnym, wciętym wierszu. Do wstawienia pustego wiersza między
+      parami słowo-definicja użyj znaku nowego wiersza (<em>\n</em>).</li>
+</ul>
+<h3 id="1.6.4.exerc">6.4. Glosariusz 2</h3> 
+<p>
+Skoro już wiesz, jak można przeprowadzić iterację przez
+słownik, to zmodyfikuj kod ćwiczenia 6.3 z wcześniejszej części rozdziału. 
+Zastąp serię wywołań <em>print()</em> pętlą przeprowadzającą iterację przez 
+klucze i 
+wartości słownika. Po upewnieniu się, że pętla działa prawidłowo, do 
+glosariusza dodaj kolejnych pięć terminów związanych z <em>Pythonem</em>. 
+Kiedy 
+ponownie uruchomisz program, nowo dodane terminy i ich definicje powinny 
+zostać automatycznie uwzględnione w wyświetlonych danych wyjściowych.
+</p>
+<h3 id="1.6.5.exerc">6.5. Rzeki</h3>
+<p>
+Utwórz słownik zawierający trzy ważne rzeki oraz kraje, przez 
+które one płyną. Jedna z par klucz-wartość może mieć postać 'nil': 'egipt'.
+</p>
+<ul class="special_link">
+  <li>Wykorzystaj pętlę do wyświetlenia zdania o każdej rzece, na przykład:
+      „Nil przepływa przez Egipt”.</li>
+  <li>Wykorzystaj pętlę do wyświetlenia nazw wszystkich rzek przechowywanych
+      w słowniku.</li>
+  <li>Wykorzystaj pętlę do wyświetlenia nazw wszystkich państw
+      przechowywanych w słowniku.</li>
+</ul>
+<h3 id="1.6.6.exerc">6.6. Ankieta</h3>
+<p>
+Użyj kodu znajdującego się w programie <em>favorite_languages.py</em>,
+utworzonym nieco wcześniej w tym rozdziale.
+</p>
+<ul class="special_list">
+  <li>Utwórz listę osób, które powinny wziąć udział w ankiecie dotyczącej
+      ulubionego języka programowania. Umieść na niej pewne osoby, które
+      już znajdują się w słowniku, oraz te, które jeszcze nie zostały zapisane
+      w słowniku</li>
+  <li>Przeprowadź iterację przez listę osób, które powinny wziąć udział
+      w ankiecie. Jeżeli dana osoba już wzięła udział w ankiecie, wyświetl
+      komunikat z podziękowaniem za jej zaangażowanie. Natomiast jeśli
+      dana osoba jeszcze nie udzieliła odpowiedzi w ankiecie, wyświetl
+      komunikat z zaproszeniem do wzięcia w niej udziału.</li>
+</ul>
+<h3 id="1.6.7.exerc">6.7. Osoby.</h3>
+<p>
+Pracę rozpocznij od programu stworzonego w ćwiczeniu 6.1 we
+wcześniejszej części rozdziału. Utwórz dwa nowe słowniki przedstawiające 
+różne osoby, a następnie wszystkie trzy słowniki umieść na liście o nazwie 
+<em>people</em>. Przeprowadź iterację przez listę osób i wyświetl wszystkie 
+informacje o poszczególnych osobach.
+</p>
+<h3 id="1.6.8.exerc">6.8. Zwierzęta.</h3>
+Utwórz kilka słowników i nadaj im nazwy zwierząt. W 
+poszczególnych słownikach umieść informacje o zwierzętach będących ich 
+właścicielami. Następnie te słowniki powinny znaleźć się na liście o nazwie 
+<em>pets</em>. Teraz przeprowadź iterację przez listę i wyświetl wszystkie 
+informacje o poszczególnych zwierzętach.
+</h3>
+
+<h3 id="1.6.9.exerc">6.9. Ulubione miejsca.</h3>
+<p>
+Utwórz słownik o nazwie <em>favorite_places</em>. Pomyśl
+o trzech imionach i użyj ich jako kluczy słownika. Każdej osobie przypisz 
+po trzy ulubione miejsca. Aby ćwiczenie stało się jeszcze bardziej 
+interesujące, możesz poprosić przyjaciół o podanie ulubionych miejsc. 
+Przeprowadź iterację przez słownik i wyświetl imiona wszystkich osób oraz 
+ich ulubione miejsca.
+</p>
+
+<h3 id="1.6.10.exerc">6.10. Ulubione liczby</h3>
+<p>
+Zmodyfikuj program utworzony w ćwiczeniu 6.2 we 
+wcześniejszej części rozdziału. Po zmianach każda osoba może mieć więcej niż
+tylko jedną ulubioną liczbę. Wyświetl wszystkie osoby oraz ich ulubione 
+liczby.
+</p>
+
+<h2 id="1.7.ch">Rozdział 7:</h2>
+<h3 id="1.7.1.exerc">7.1. Wypożyczenie samochodu</h3>
+<p>
+Utwórz program, który pyta użytkownika,
+jakiej marki samochód chciałby wypożyczyć. Następnie wyświetl komunikat
+wraz z podaną nazwą samochodu, na przykład: „Chwileczkę, sprawdzę, czy
+mamy dostępny samochód Subaru”.
+</p>
+<h3 id="1.7.2.exerc">7.2. Stolik w restauracji</h3> 
+<p>
+Utwórz program pytający klienta, na ile osób chce
+zarezerwować stolik. Jeżeli odpowiedzią jest liczba większa niż 8, 
+powinieneś wyświetlić komunikat o konieczności zaczekania na stolik. W 
+przeciwnym razie poinformuj klienta, że stolik jest gotowy.
+</p>
+<h3 id="1.7.3.exerc">7.3. Wielokrotność dziesięciu</h3> 
+<p>
+Poproś użytkownika o podanie dowolnej liczby,
+a następnie sprawdź, czy jest ona wielokrotnością liczby 10.
+</p>
+<h3 id="1.7.4.exerc">7.4. Dodatki do pizzy</h3>
+<p>
+Utwórz pętlę proszącą użytkownika o podanie serii
+dodatków do pizzy. Działanie pętli powinno zostać zakończone, kiedy zostanie
+wpisane słowo 'koniec'. Gdy użytkownik będzie podawał kolejne dodatki,
+pętla powinna wyświetlać komunikat o dodaniu danego składnika do pizzy.
+</p>
+<h3 id="1.7.5.exerc">7.5. Bilety do kina</h3>
+<p>
+Cena biletu do kina jest uzależniona od wieku widza. 
+Jeżeli widz ma poniżej 3 lat, bilet jest bezpłatny. Dla dzieci w wieku od 3
+do 12 lat bilet kosztuje 10 zł. Dla osób wieku powyżej 12 lat cena biletu 
+wynosi 15 zł. Utwórz pętlę proszącą użytkownika o podanie wieku, a następnie
+na podstawie otrzymanych danych wyświetl komunikat zawierający prawidłową 
+cenę biletu.
+</p>
+<h3 id="1.7.6.exerc">7.6. Trzy wyjścia.</h3>
+<p>
+Przygotuj trzy różne wersje ćwiczenia 7.4 lub 7.5, z 
+których każde będzie przynajmniej raz wykonywać poniższe zadania:
+</p>
+<ul class="special_link">
+  <li>Użycie testu warunkowego w pętli <em>while</em> do zatrzymania jej 
+      działania.</li>
+  <li>Użycie zmiennej <em>active</em> do kontroli długości działania pętli 
+      <em>while</em>.</li>
+  <li>Użycie polecenia <em>break</em> do opuszczenia pętli, gdy użytkownik wpisze
+      'koniec'.</li>
+</ul>
+<h3 id="1.7.7.exerc">7.7. Nieskończoność</h3>
+<p>
+Utwórz pętlę działającą w nieskończoność i uruchom
+ją. (W celu zakończenia tej pętli naciśnij klawisze Ctrl+C lub zamknij okno
+terminala wyświetlającego dane wyjściowe programu).
+</p>
+<h3 id="1.7.8.exerc">7.8. Bar</h3>
+<p>
+Przygotuj listę o nazwie <em>sandwich_orders</em> i umieść na niej nazwy 
+różnych kanapek. Następnie przygotuj pustą listę o nazwie 
+<em>finished_sandwiches</em>. Przeprowadź iterację przez listę zamówionych 
+kanapek i 
+wyświetl informację o danym zamówieniu, na przykład: „Przygotowano kanapkę z
+tuńczykiem”. Kiedy kanapka zostanie zrobiona, reprezentujący ją element 
+powinien zostać przeniesiony na listę <em>finished_sandwiches</em>. Gdy lista 
+<em>sandwich_orders</em> będzie już pusta, wyświetl komunikat zawierający listę 
+wszystkich zrobionych kanapek.
+</p>
+<h3 id="1.7.9.exerc">7.9. Brak pastrami</h3>
+<p>
+Wykorzystaj listę <em>sandwich_orders</em> z ćwiczenia 7.8 i 
+upewnij się, że na liście przynajmniej trzykrotnie pojawia się kanapka z 
+pastrami. Gdzieś na początku programu umieść kod wyświetlający komunikat,
+że w barze skończyło się pastrami, a następnie za pomocą pętli <em>while</em>
+usuń 
+wszystkie wystąpienia pastrami z listy <em>sandwich_orders</em>. 
+Upewnij się, że żadna kanapka z pastrami nie zostanie umieszczona na liście 
+<em>finished_sandwiches</em>.
+</p>
+<h3 id="1.7.10.exerc">7.10. Wymarzone wakacje</h3>
+<p>
+Przygotuj program pytający użytkowników o ich
+wymarzone wakacje. Program powinien wyświetlać pytanie w stylu: „Jeżeli
+mógłbyś odwiedzić jedno dowolne miejsce na świecie, gdzie byś pojechał?”.
+Umieść w programie blok kodu odpowiedzialny za wyświetlenie wyników
+przeprowadzonej ankiety.
+</p>
+<h2 id="1.8.ch">Rozdział 8:</h2>
+<h3 id="1.8.1.exerc">8.1. Komunikat</h3>
+<p>
+Utwórz funkcję o nazwie <em>display_messages()</em> wyświetlającą
+jedno zdanie informujące o tym, czego się uczysz w tym rozdziale. Wywołaj 
+przygotowaną funkcję i upewnij się, że komunikat został prawidłowo 
+wyświetlony.
+</p>
+<h3 id="1.8.2.exerc">8.2. Ulubiona książka</h3>
+<p>
+Utwórz funkcję o nazwie <em>favorite_book()</em>, która akcep-
+tuje jeden parametr <em>title</em>. Ta funkcja powinna wyświetlać komunikat w 
+stylu:
+„Jedną z moich ulubionych książek jest Alicja w krainie czarów”. Wywołaj tę
+funkcję i upewnij się, że podałeś tytuł książki jako argument.
+</p>
+<h3 id="1.8.3.exerc">8.3. T-shirt</h3>
+<p>
+Utwórz funkcję o nazwie <em>make_shirt()</em>, akceptującą wielkość
+koszulki oraz tekst, który ma zostać na niej nadrukowany. Funkcja powinna
+wyświetlić zdanie zawierające informacje dotyczące zamówionej koszulki: jej
+rozmiar i tekst do wydrukowania na niej.
+W trakcie pierwszego wywołania funkcji do przygotowania koszulki zastosuj
+argumenty pozycyjne. Natomiast w trakcie drugiego wywołania użyj argumen-
+tów w postaci słów kluczowych.
+</p>
+<h3 id="1.8.4.exerc">8.4. Duże koszulki</h3>
+<p>
+Zmodyfikuj funkcję <em>make_shirt()</em> tak, aby domyślnie były
+przygotowywane duże koszulki z nadrukowanym tekstem „Uwielbiam Pythona”.
+Utwórz koszulki w rozmiarze dużym i średnim (obie z domyślnym tekstem) oraz
+koszulkę w dowolnym rozmiarze i z innym tekstem nadrukowanym na niej.
+</p>
+<h3 id="1.8.5.exerc">8.5. Miasta</h3>
+<p>
+Utwórz funkcję o nazwie <em>describe_city()</em>, akceptującą nazwę
+miasta i kraju. Ta funkcja powinna wyświetlać proste zdanie, takie jak 
+„Warszawa leży w Polsce”. Parametrowi przechowującemu nazwę państwa przypisz
+wartość domyślną. Przygotowaną funkcję wywołaj dla trzech różnych
+miast, z których przynajmniej jedno nie powinno być położone w domyślnie
+zdefiniowanym kraju.
+</p>
+<h3 id="1.8.6.exerc">8.6. Nazwy miast</h3>
+<p>
+Utwórz funkcję o nazwie <em>city_country()</em> pobierającą nazwę
+miasta i kraju, w którym ono leży. Wartością zwrotną funkcji powinien być
+ciąg tekstowy sformatowany w poniższy sposób:
+Santiago, Chile
+Przygotowaną funkcję wywołaj z przynajmniej trzema parami miasto-państwo
+i wyświetl wygenerowaną przez nie wartość.
+</p>
+<h3 id="1.8.7.exerc">8.7. Album</h3>
+<p>
+Utwórz funkcję o nazwie <em>make_album()</em> odpowiedzialną za 
+zbudowanie słownika reprezentującego album muzyczny. Funkcja powinna pobrać
+nazwę zespołu lub artysty oraz tytuł albumu. Wartością zwrotną funkcji 
+powinien być słownik zawierający te dwa fragmenty informacji. Za pomocą 
+przygotowanej funkcji utwórz trzy słowniki przedstawiające różne albumy. 
+Wyświetl każdą wartość zwrotną, aby pokazać, że słowniki prawidłowo 
+przechowują informacje o albumach.
+Wykorzystując wartość specjalną <em>None</em>, do funkcji 
+<em>make_album()</em> dodaj 
+opcjonalny parametr pozwalający na przechowywanie liczby utworów 
+znajdujących się na płycie. Jeżeli wywołanie funkcji będzie zawierało 
+wartość dla liczby utworów, należy ją dodać do słownika informacji o 
+albumie. Zdefiniuj co najmniej jedno nowe wywołanie funkcji obejmujące 
+także liczbę utworów na płycie.
+</p>
+<h3 id="1.8.8.exerc">8.8. Albumy użytkowników</h3>
+<p>
+Pracę rozpocznij od programu utworzonego
+w ćwiczeniu 8.7. Dodaj pętlę while pozwalającą użytkownikom na wprowa-
+dzenie artysty i tytułu płyty. Po zebraniu tych informacji wywołaj funkcję 
+<em>make_album()</em> wraz z podanymi przez użytkownika danymi wejściowymi oraz
+wyświetl słownik utworzony przez program. Upewnij się, że zdefiniowałeś war-
+tość pozwalającą opuścić pętlę <em>while</em>.
+</p>
+<h3 id="1.8.9.exerc">8.9. Komunikaty</h3>
+</p>
+Przygotuj listę zawierającą serię krótkich komunikatów,
+a następnie przekaż ją do funkcji o nazwie <em>show_messages()</em>, która 
+powinna wyświetlić każdy komunikat umieszczony na tej liście.
+</p>
+<h3 id="1.8.10.exerc">8.10. Wysyłanie komunikatów</h3>
+<p>
+Pracę rozpocznij od kopii programu z ćwiczenia 8.9. 
+Następnie utwórz funkcję o nazwie <em>send_messages()</em>, której zadaniem 
+będzie wyświetlenie wszystkich komunikatów, a następnie przeniesienie
+ich na nową listę o nazwie <em>sent_messages</em>. Po wywołaniu funkcji należy 
+wyświetlić obie listy i upewnić się o prawidłowym przeniesieniu komunikatów.
+</p>
+<h3 id="1.8.11.exerc">8.11. Zarchiwizowane komunikaty</h3>
+<p>
+Pracę rozpocznij od kodu utworzonego
+w ćwiczeniu 8.10. Wywołaj funkcję <em>send_messages()</em> wraz z kopią listy 
+komunikatów. Po wywołaniu funkcji wyświetl obie listy, aby pokazać istnienie 
+pierwotnej listy z zachowanymi komunikatami.
+</p>
+<h3 id="1.8.12.exerc">8.12. Kanapki</h3>
+<p>
+Utwórz funkcję akceptującą listę składników, które klient 
+chce umieścić w zamawianej kanapce. Funkcja powinna zawierać jeden parametr
+przechowujący dowolną liczbę argumentów przekazanych w wywołaniu
+funkcji oraz wyświetlać podsumowanie dotyczące zamówionej kanapki. 
+Przygotowaną funkcję wywołaj trzykrotnie, za każdym razem z inną liczbą 
+argumentów.
+</p>
+<h3 id="1.8.13.exerc">8.13. Profil użytkownika</h3>
+<p>
+Pracę rozpocznij od kopii programu <em>user_profile.py</em>
+utworzonego nieco wcześniej w tym rozdziale. Przygotuj własny profil przez
+wywołanie funkcji <em>build_profile()</em>, podaj imię, nazwisko oraz trzy 
+inne pary
+klucz-wartość, które Cię opisują.
+</p>
+<h3 id="1.8.14.exerc">8.14. Samochody</h3>
+<p>
+Utwórz funkcję przechowującą w słowniku informacje
+o samochodzie. Ta funkcja zawsze powinna otrzymywać nazwy marki i modelu
+pojazdu, po którym można podać dowolną liczbę argumentów w postaci
+słów kluczowych. Wywołaj funkcję zawierającą wymagane informacje oraz
+dwie dodatkowe pary nazwa-wartość, na przykład opisujące kolor i 
+wyposażenie dodatkowe. Przygotowana funkcja powinna być wywoływana w sposób
+podobny do przedstawionego poniżej:
+</p>
+<pre class="code-block">
+car = make_car('subaru', 'outback', color='blue', tow_package=True)
+</pre>
+<p>
+Wyświetl zawartość słownika zwróconego przez tę funkcję i upewnij się, że
+wszystkie podane informacje zostały w nim prawidłowo zapisane.
+</p>
+<h3 id="1.8.15.exerc">8.15. Wydruk modeli</h3>
+<p>
+Funkcje z programu <em>print_models.py</em> umieść w 
+oddzielnym pliku o nazwie <em>printing_functions.py</em>. Na początku pliku 
+<em>print_models.py</em> umieść polecenie <em>import</em> i zmodyfikuj plik w 
+taki sposób, aby używać zaimportowanych funkcji.
+</p>
+<h3 id="1.8.16.exerc">8.16. Polecenia importu</h3>
+<p>
+Wykorzystaj utworzony przez siebie program z jedną
+funkcją i przenieś ją do oddzielnego pliku. Zaimportuj tę funkcję w pliku 
+programu głównego, a następnie wywołaj funkcję na wszystkie wymienione poni-
+żej sposoby:
+</p>
+<pre class="code-block">
+import nazwa_modułu
+from nazwa_modułu import nazwa_funkcji
+from nazwa_modułu import nazwa_funkcji as fn
+import nazwa_modułu as mn
+from nazwa_modułu import *
+</pre>
+<h3 id="1.8.17.exerc">8.17. Nadanie stylu funkcjom</h3>
+<p>
+Wybierz trzy dowolne programy utworzone
+w tym rozdziale i upewnij się, że są w nich stosowane przedstawione w tym
+podrozdziale konwencje dotyczące nadawania stylu funkcjom.
+</p>
+<h2 id="1.9.ch">Rozdział 9: </h2>
+<h3 id="1.9.1.exerc">9.1. Restauracja</h3>
+<p>
+Przygotuj klasę o nazwie <em>Restaurant</em>. Metoda <em>__init__()</em>
+w klasie <em>Restaurant</em> powinna przechowywać dwa atrybuty: 
+<em>restaurant_name</em>
+i <em>cuisine_type</em>. Utwórz metodę o nazwie <em>describe_restaurant()</em> 
+wyświetlającą 
+te dwa fragmenty informacji oraz metodę o nazwie <em>open_restaurant()</em>
+wyświetlającą informacje o godzinach pracy restauracji.
+Na podstawie przygotowanej klasy utwórz egzemplarz <em>restaurant</em>. 
+Wyświetl oddzielnie oba atrybuty, a następnie wywołaj obie metody.
+</p>
+<h3 id="1.9.2.exerc">9.2. Trzy restauracje</h3>
+<p>
+Pracę rozpocznij od klasy opracowanej w ćwiczeniu 
+9.1. Utwórz trzy różne egzemplarze na podstawie tej klasy, a następnie 
+wywołaj metodę <em>describe_restaurant()</em> dla każdego egzemplarza.
+</p>
+<h3 id="1.9.3.exerc">9.3. Użytkownicy</h3>
+<p>
+Przygotuj klasę o nazwie <em>User</em>. Zdefiniuj w niej dwa 
+atrybuty (<em>first_name</em> i <em>last_name</em>), a następnie utwórz kilka innych 
+atrybutów, które
+zwykle są przechowywane w profilu użytkownika. Zdefiniuj metodę o nazwie
+<em>describe_user()</em>, wyświetlającą podsumowanie informacji zebranych o 
+użytkowniku. Utwórz jeszcze drugą metodę o nazwie <em>greet_user()</em>, która 
+będzie
+wyświetlała użytkownikowi spersonalizowane powitanie.
+Utwórz kilka egzemplarzy reprezentujących różnych użytkowników, a 
+następnie dla każdego z nich wywołaj obie metody.
+</p>
+<h3 id="1.9.4.exerc">9.4. Liczba obsłużonych</h3>
+<p>
+Pracę rozpocznij od programu utworzonego w 
+ćwiczeniu 9.1. Dodaj atrybut o nazwie <em>number_served</em> o wartości 
+domyślnej 0.
+Następnie na podstawie klasy utwórz egzemplarz o nazwie <em>restaurant</em>. 
+Wyświetl
+liczbę klientów obsłużonych przez restaurację, zmień tę wartość i później
+wyświetl nową.
+Dodaj metodę o nazwie <em>set_number_served()</em>, pozwalającą na 
+zdefiniowanie liczby obsłużonych klientów. Wywołaj tę metodę wraz z różnymi 
+wartościami i je wyświetl.
+Dodaj metodę o nazwie <em>increment_number_served()</em>, pozwalającą na 
+inkrementację wartości wskazującej na liczbę obsłużonych klientów. Wywołaj 
+tę
+metodę dowolną ilość razy, symulując w ten sposób liczbę klientów obsłużonych 
+na przykład w ciągu dnia roboczego.
+</p>
+<h3 id="1.9.5.exerc">9.5. Próby logowania</h3>
+<p>
+Pracę rozpocznij od programu utworzonego w ćwiczeniu 9.3. Do klasy <em>User</em>
+dodaj metodę o nazwie <em>increment_login_attempts()</em>, pozwalający na 
+inkrementację wartości <em>login_attempts</em> o 1. Utwórz drugą
+metodę o nazwie <em>reset_login_attempts()</em>, która będzie zerowała wartość
+<em>login_attempts</em>.
+Utwórz egzemplarz klasy User i kilkukrotnie wywołaj metodę 
+<em>increment_login_attempts()</em>. Wyświetl wartość <em>login_attempts</em>,
+aby mieć pewność o jej 
+prawidłowej inkrementacji. Następnie wywołaj metodę 
+<em>reset_login_attempts()</em>.
+Ponownie wyświetl wartość <em>login_attempts</em> i sprawdź, czy na pewno 
+wynosi 0.
+</p>
+<h3 id="1.9.6.exerc">9.6. Budka z lodami</h3>
+<p>
+Budka z lodami to szczególny rodzaj restauracji. 
+Zdefiniuj klasę o nazwie <em>IceCreamStand</em> dziedziczącą po klasie 
+<em>Restaurant </em>
+utworzonej w ćwiczeniu 9.1 lub 9.4. Dowolna wersja wymienionej klasy będzie 
+się sprawdzać — po prostu wybierz jedną z nich. Dodaj atrybut o nazwie
+<em>flavors</em>, przechowujący listę różnych smaków lodów. Zdefiniuj metodę 
+wyświetlającą dostępne smaki lodów. Utwórz egzemplarz klasy 
+<em>IceCreamStand</em> i wywołaj nową metodę.
+</p>
+<h3 id="1.9.7.exerc">9.7. Admin</h3>
+<p>
+Administrator to specjalny rodzaj użytkownika. Zdefiniuj klasę
+o nazwie <em>Admin</em> dziedziczącą po klasie <em>User</em> utworzonej w 
+ćwiczeniu 9.3 lub 9.5.
+Dodaj atrybut <em>privileges</em> przechowujący listę ciągów tekstowych takich
+jak „może dodać post”, „może usunąć post” czy „może zbanować użytkownika”.
+Zdefiniuj metodę o nazwie <em>show_privileges()</em>, wyświetlającą listę 
+uprawnień administratora. Utwórz egzemplarz klasy <em>Admin</em> i wywołaj 
+nową metodę.
+<p>
+<h3 id="1.9.8.exerc">9.8. Uprawnienia</h3>
+<p>
+Zdefiniuj oddzielną klasę <em>Privileges</em>. Ta klasa powinna
+mieć jeden atrybut (<em>privileges</em>), przechowujący listę ciągów 
+tekstowych, tak jak
+przedstawiłem to w poprzednim ćwiczeniu. Metodę <em>show_privileges()</em> 
+przenieś 
+do nowej klasy. Utwórz egzemplarz klasy <em>Privileges</em> jako atrybut w 
+klasie
+<em>Admin</em>. Następnie utwórz nowy egzemplarz klasy <em>Admin</em> i użyj 
+metody <em>show_privileges()</em> do wyświetlenia uprawnień.
+</p>
+<h3 id="1.9.9.exerc">9.9. Uaktualnienie akumulatora</h3>
+<p>
+Pracę rozpocznij od ostatniej wersji 
+programu <em>electric_car.py</em> utworzonej w tym podrozdziale. Do klasy 
+<em>Battery</em> 
+dodaj
+nową metodę o nazwie <em>upgrade_battery()</em>. Ta metoda powinna sprawdzić
+pojemność akumulatora i ustawić ją na 100, jeśli aktualnie jest inna. Utwórz
+egzemplarz samochodu o napędzie elektrycznym wraz z akumulatorem
+o domyślnej pojemności, wywołaj metodę <em>get_range()</em>, a następnie metodę
+<em>upgrade_battery()</em> i ponownie <em>get_range()</em>. Powinieneś zauważyć 
+zwiększenie zasięgu samochodu.
+</p>
+<h3 id="1.9.10.exerc">9.10. Zaimportowana klasa Restaurant</h3>
+<p>
+Przenieś do modułu ostatnią wersję
+klasy <em>Restaurant</em> i utwórz oddzielny plik importujący tę klasę. Utwórz 
+egzemplarz klasy <em>Restaurant</em>, a następnie wywołaj metodę tej klasy, aby 
+sprawdzić, czy polecenie <em>import</em> działa prawidłowo.
+</p>
+<h3 id="1.9.11.exerc">9.11. Zaimportowana klasa Admin</h3>
+<p>
+Pracę rozpocznij od ćwiczenia 9.8. W 
+jednym module umieść klasy <em>User</em>, <em>Privileges</em> i <em>Admin</em>.
+Przygotuj oddzielny plik,
+utwórz w nim egzemplarz klasy <em>Admin</em> i wywołaj metodę 
+<em>show_privileges()</em>,
+aby sprawdzić, czy wszystko działa prawidłowo.
+</p>
+<h3 id="1.9.12.exerc">9.12. Wiele modułów</h3>
+<p>
+Klasę <em>User</em> umieść w jednym module, natomiast 
+<em>Privileges</em> i <em>Admin</em> w oddzielnym. Następnie w innym pliku 
+utwórz egzemplarz
+klasy <em>Admin</em> i wywołaj metodę <em>show_privileges()</em>, aby 
+sprawdzić, czy wszystko działa prawidłowo.
+</p>
+<h3 id="1.9.13.exerc">9.13. Kości do gry</h3>
+<p>
+Przygotuj klasę <em>Die</em> z jednym atrybutem o nazwie <em>sides</em>,
+którego wartością domyślną będzie 6. Utwórz metodę o nazwie 
+<em>roll_die()</em>,
+wyświetlającą losowo wygenerowaną liczbę z zakresu od 1 do wartości 
+określonej przez liczbę ścianek na kości do gry. Utwórz kość zawierającą sześć 
+ścianek i zasymuluj rzucenie nią 10 razy.
+Później utwórz kości zawierające 10 i 20 ścianek. Każdą nową kością rzuć 10 
+razy.
+</p>
+<h3 id="1.9.14.exerc">9.14. Loteria</h3>
+<p>
+Utwórz listę lub krotkę zawierającą serię dziesięciu liczb i 
+pięciu liter. Losowo wybierz cztery liczby lub litery z listy, a następnie 
+wyświetl
+komunikat informujący, że kupon zawierający liczby lub litery dopasowane
+do wylosowanych wygrywa nagrodę.
+</p>
+<h3 id="1.9.15.exerc">9.15. Analiza loterii</h3> 
+<p>
+Wykorzystaj pętlę do ustalenia, jak trudno jest 
+wygrać
+w loterii, którą modelowałeś w poprzednim ćwiczeniu. Utwórz listę lub
+krotkę o nazwie <em>my_ticket</em>. Następnie zdefiniuj pętlę losującą liczby 
+dopóty,
+dopóki nie zostaną dopasowane do Twojego kuponu. Wyświetl komunikat
+informujący, ile iteracji pętli trzeba było wykonać, zanim padły liczby 
+znajdujące się na Twoim kuponie.
+</p>
+<h3 id="1.9.16.exerc">9.16. Moduł Pythona tygodnia</h3>
+<p>
+Jednym z doskonałych zasobów pomagających w poznaniu biblioteki standardowej 
+<em>Pythona</em> jest witryna <em>Python Module of the Week</em>.
+Przejdź na stronę <em>https://pymotw.com/3/</em> i przejrzyj spis 
+treści.
+Wybierz moduł, który wygląda interesująco, i przeczytaj informacje na jego
+temat. Przejrzyj również dokumentację dotyczącą modułu <em>random</em>.
+</p>
+<h2 id="1.10.ch">Rozdział 10:</h2>
+<h3 id="1.10.1.exerc">10.1. Poznajemy Pythona</h3>
+<p>
+W edytorze tekstu utwórz pusty plik i wpisz w nim
+kilka zdań podsumowujących to, czego się dotąd nauczyłeś o języku 
+<em>Python</em>.
+Każdy wiersz rozpocznij od wyrażenia <em>„W Pythonie można...”</em>. Plik 
+zapisz pod nazwą <em>learning_python.txt</em> w tym samym katalogu, w którym 
+umieszczasz ćwiczenia z tego rozdziału. Przygotuj program odczytujący powyższy
+plik i trzykrotnie wyświetlający jego zawartość. Treść pliku powinna być 
+wyświetlona raz przez odczytanie całego pliku, raz za pomocą iteracji przez 
+obiekt pliku oraz raz przez umieszczenie wierszy na liście, a następnie 
+przetworzenie listy poza blokiem <em>with</em>.
+</p>
+<h3 id="1.10.2.exerc">10.2. Poznajemy C</h3>
+<p>
+Metodę <em>replace()</em> można wykorzystać do zastąpienia
+dowolnego słowa w ciągu tekstowym zupełnie innym słowem. Oto krótki przykład
+pokazujący, jak w zdaniu słowo pies zastąpić słowem kot:
+</p>
+<pre class="code-block">
+&gt;&gt;&gt; message = "Moje ulubione zwierzę to pies."
+&gt;&gt;&gt; message.replace('pies', 'kot')
+'Moje ulubione zwierzę to kot.'
+</pre>
+<p>
+Odczytaj każdy wiersz tekstu w utworzonym wcześniej pliku 
+<em>learning_python.txt</em>,
+a następnie wszystkie wystąpienia słowa <em>Python</em> zastąp nazwą innego 
+języka
+programowania, na przykład <em>C</em>. Każdy zmodyfikowany wiersz wyświetl na
+ekranie.
+</p>
+<h3 id="1.10.3.exerc">10.3. Gość</h3>
+<p>
+Utwórz program, który poprosi użytkownika o podanie imienia.
+Gdy użytkownik je wprowadzi, zapisz to imię w pliku o nazwie 
+<em>guest.txt</em>.
+</p>
+<h3 id="1.10.4.exerc">10.4. Księga gości</h3>
+<p>
+Utwórz pętlę while, w której każdy użytkownik będzie
+musiał podać swoje imię. Gdy użytkownik je wprowadzi, na ekranie wyświetl
+komunikat powitania, a do pliku o nazwie <em>guest_book.txt</em> dodaj wiersz 
+rejestrujący odwiedzenie Twojej strony przez tego użytkownika. Upewnij się, 
+że każdy wpis jest umieszczany w nowym wierszu w pliku.
+</p>
+<h3 id="1.10.5.exerc">10.5. Ankieta dotycząca programowania</h3>
+<p>
+Utwórz pętlę <em>while</em>, w której
+użytkownicy będą musieli udzielić odpowiedzi na pytanie: „Dlaczego lubisz
+programowanie?”. Każdą otrzymaną odpowiedź dodaj do pliku przechowującego 
+wszystkie udzielone odpowiedzi.
+</p>
+<h3 id="1.10.6.exerc">10.6. Dodawanie</h3>
+<p>
+Jeden z najczęściej pojawiających się problemów podczas
+pobierania danych liczbowych polega na tym, że użytkownicy podają tekst
+zamiast liczb. Kiedy tego rodzaju dane wejściowe spróbujesz skonwertować
+na typ <em>int</em>, otrzymasz błąd <em>ValueError</em>. Utwórz program, który
+prosi 
+użytkownika o podanie dwóch liczb. Dodaj je i wyświetl wynik. Przechwyć błąd
+<em>ValueError</em>, jeżeli którakolwiek wartość przekazana w danych 
+wejściowych nie
+jest liczbą, i wyświetl odpowiedni komunikat błędu. Przetestuj program, 
+najpierw podając dwie liczby, a później pewien tekst zamiast liczby.
+</p>
+<h3 id="1.10.7.exerc">10.7. Kalkulator dodawania</h3>
+<p>
+Kod przygotowany w ćwiczeniu 10.6 opakuj
+pętlą <em>while</em>, aby użytkownik mógł kontynuować wprowadzanie liczb nawet
+po popełnieniu błędu i podaniu tekstu zamiast liczby.
+</p>
+<h3 id="1.10.8.exerc">10.8. Koty i psy</h3>
+<p>
+Utwórz dwa pliki o nazwach cats.txt i dogs.txt. W 
+pierwszym
+pliku umieść przynajmniej trzy imiona kotów, natomiast w drugim przynajmniej
+trzy imiona psów. Przygotuj program próbujący odczytać zawartość tych
+plików i wyświetlić ją na ekranie. Zastosuj w kodzie konstrukcję 
+<em>try-except</em>
+aby przechwycić wszelkie błędy typu <em>FileNotFoundError</em> i wyświetlić 
+użytkownikowi odpowiedni komunikat błędy, gdy żądany plik nie istnieje. Jeden z 
+utworzonych wcześniej plików przenieś do innego katalogu w systemie i 
+upewnij się, że opracowany blok except w programie działa prawidłowo.
+</p>
+<h3 id="1.10.9.exerc">10.9. Ciche koty i psy</h3>
+<p>
+Blok <em>except</em> w programie utworzonym w poprzednim
+ćwiczeniu zmodyfikuj w taki sposób, aby brak pliku powodował jedynie ciche
+niepowodzenie.
+</p>
+<h3 id="1.10.10.exerc">10.10. Najczęściej występujące słowa.</h3>
+<p>
+Odwiedź witrynę projektu Gutenberg
+(http://www.gutenberg.org/) i wybierz kilka innych książek, które chciałbyś 
+przeanalizować. Pobierz pliki tekstowe tych dzieł lub niezmodyfikowany zwykły
+tekst skopiuj z przeglądarki internetowej do pliku tekstowego w komputerze.
+Za pomocą metody <em>count()</em> możesz sprawdzić, ile razy dane słowo lub 
+wyrażenie występuje w ciągu tekstowym. Na przykład w przedstawionym poniżej
+fragmencie kodu sprawdzamy, ile razy słowo za występuje w ciągu tekstowym:
+</p>
+<pre class="code-block">
+&gt;&gt;&gt; line = "Za górami, za lasami, za dolinami pobili się dwaj górale
+ciupagami."
+&gt;&gt;&gt; line.count('za')
+2
+&gt;&gt;&gt; line.lower().count('za')
+3
+</pre>
+<p>
+Zwróć uwagę na to, że konwersja ciągu tekstowego na zapisany małymi 
+literami (do tego służy funkcja <em>lower()</em>, którą poznałeś już wcześniej) 
+powoduje
+przechwycenie wszystkich wystąpień sprawdzanego słowa niezależnie od sposobu 
+jego formatowania.
+Utwórz program odczytujący pobrane wcześniej z projektu Gutenberg pliki 
+tekstowe, a następnie określający, ile razy słowo the występuje w każdym z nich.
+Otrzymany wynik będzie jedynie przybliżony, ponieważ uwzględnia również
+słowa zawierające 'za', np. 'zachód' lub 'zabawa'. Spróbuj zliczyć 
+wystąpienia 'za ' (wraz ze spacją w ciągu tekstowym) i zobacz, o ile mniejsza 
+będzie to liczba.
+</p>
+<h3 id="1.10.11.exerc">10.11. Ulubiona liczba</h3>
+<p>
+Utwórz program, który prosi użytkownika o podanie
+ulubionej liczby. Za pomocą funkcji <em>json.dump()</em> zapisz tę liczbę w 
+pliku. 
+Następnie utwórz oddzielny program odczytujący ulubioną liczbę użytkownika i
+wyświetlający komunikat w stylu: 
+<code class="code-inline">„Znam Twoją ulubioną liczbę, to _____”.</code>
+</p>
+<h3 id="1.10.12.exerc">10.12. Zapamiętana ulubiona liczba</h3>
+<p>
+Oba programy utworzone w poprzednim 
+ćwiczeniu połącz w jednym pliku. Jeżeli ulubiona liczba została zapisana
+w pliku, wyświetl ją użytkownikowi. W przeciwnym razie poproś użytkownika
+o podanie ulubionej liczby i zapisz ją w pliku. Uruchom ten program 
+dwukrotnie i upewnij się, że działa prawidłowo.
+</p>
+<h3 id="1.10.13.exerc">10.13. Weryfikacja użytkownika.</h3>
+<p>
+W ostatniej wersji programu 
+<em>remember_me.py</em> przyjęto założenie, że użytkownik już wcześniej podał 
+swoje 
+imię, lub też program został uruchomiony po raz pierwszy. Powinniśmy 
+zmodyfikować ten program na wypadek, gdyby bieżący użytkownik nie był tą 
+osobą, która ostatnio korzystała z tego programu.
+W funkcji <em>greet_user()</em>, zanim za pomocą odpowiedniego komunikatu 
+powitasz istniejącego już użytkownika, zapytaj go, czy podane imię jest 
+poprawne.
+Jeżeli nie jest, należy wywołać funkcję <em>get_new_username()</em> w celu 
+użycia prawidłowego imienia.
+</p>
+<h2 id="1.11.ch">Rozdział 11:</h2>
+<h3 id="1.11.1.exerc">11.1. Miasto, państwo</h3>
+<p>
+Przygotuj funkcję akceptującą dwa parametry: <em>nazwy</em>
+<em>miasta</em> i <em>państwa</em>. Wartością zwrotną tej funkcji powinien być
+pojedynczy
+ciąg tekstowy w postaci Miasto, Państwo, na przykład Santiago, Chile. Gotową
+funkcję umieść w module o nazwie <em>city_functions.py</em>.
+Utwórz plik o nazwie <em>test_cities.py</em> przeznaczony do przetestowania 
+przygotowanej wcześniej funkcji (pamiętaj o konieczności zaimportowania 
+modułu unittest oraz funkcji, która ma zostać sprawdzona). Następnie w pliku
+<em>test_cities.py</em> zdefiniuj funkcję o nazwie <em>test_city_country()</em>
+odpowiedzialną
+za sprawdzenie, czy wywołanie utworzonej w poprzednim ćwiczeniu funkcji,
+na przykład z wartościami <em>santiago</em> i <em>chile</em>, spowoduje wygenerowanie
+oczekiwanego ciągu tekstowego. Uruchom plik <em>test_cities.py</em> i upewnij 
+się, że test <em>test_city_country()</em> zostaje zaliczony.
+</p>
+<h3 id="1.11.2.exerc">11.2. Populacja</h3>
+<p>
+Zmodyfikuj przygotowaną wcześniej funkcję, aby wymagała
+podania trzeciego argumentu — populacji (<em>population</em>). Teraz wartością
+zwrotną funkcji powinien być ciąg tekstowy w postaci Miasto, Państwo - 
+populacja xxx, na przykład Santiago, Chile - populacja 5000000. Ponownie 
+uruchom <em>test_cities.py</em>. Upewnij się, że tym razem test zdefiniowany w 
+metodzie <em>test_city_country()</em> będzie niezaliczony.
+Zmodyfikuj funkcję, aby parametr population był opcjonalny. Ponownie 
+uruchom <em>test_cities.py</em> i upewnij się, że również teraz test 
+zdefiniowany w metodzie <em>test_city_country()</em> zostanie zaliczony.
+Utwórz drugi test o nazwie <em>test_city_country_population()</em>, 
+sprawdzający, czy można wywołać funkcję z wartościami <em>'santiago'</em>, 
+<em>'chile'</em> i 
+<em>'population=5000000'</em>. Raz jeszcze uruchom 
+<em>test_cities.py</em> i upewnij się, że 
+nowy test został zaliczony.
+</p>
+<h3 id="1.11.3.exerc">11.3. Pracownik</h3>
+<p>
+Przygotuj klasę o nazwie <em>Employee</em>. Metoda <em>__init__()</em>
+powinna pobierać imię, nazwisko i roczne wynagrodzenie, a następnie 
+zapisywać te informacje w postaci atrybutów. Utwórz metodę o nazwie 
+<em>give_raise()</em>, która spowoduje zwiększenie wynagrodzenia domyślnie o 
+5000 zł,
+choć zaakceptuje także inną kwotę.
+Przygotuj zestaw testów dla klasy <em>Employee</em>. Utwórz dwie metody testowe
+<em>test_give_default_raise()</em> i <em>test_give_custom_raise()</em>. 
+Wykorzystaj metodę
+<em>setUp()</em>, aby uniknąć konieczności tworzenia nowego egzemplarza klasy
+<em>Employee</em> w każdej metodzie testowej. Wykonaj zestaw testów i upewnij 
+się, że oba testy zostaną zaliczone.
+</p>
+<h1 id="2.part">Część II - Aplikacje internetowe</h1>
+<h2 id="2.1.ch">Rozdział 18:</h2>
+<h3 id="2.1.1.exerc">18.1. Nowe projekty</h3>
+<p>
+Aby jeszcze lepiej poznać możliwości oferowane przez
+framework <em>Django</em>, utwórz kilka pustych projektów i zobacz, z czego się 
+składają. Utwórz nowy katalog o prostej nazwie, takiej jak <em>snap_gram</em>
+lub <em>insta_chat</em>
+(na zewnątrz katalogu <em>learning_log</em>), przejdź do nowego katalogu w 
+powłoce
+i utwórz środowisko wirtualne. Zainstaluj <em>Django</em> i wydaj polecenie 
+<code class="code-inline">django-admin.py startproject snap_gram .</code> 
+(upewnij się, że umieściłeś kropkę na końcu polecenia).
+Zajrzyj do plików i katalogów utworzonych przez powyższe polecenie i 
+porównaj je z zawartością projektu <em>Learning Log</em>. Procedurę powtórz 
+kilkukrotnie, aż będziesz wiedzieć, co <em>Django</em> tworzy w nowym projekcie. 
+Następnie usuń katalogi niepotrzebnych Ci projektów.
+</p>
+<h3 id="2.1.2.exerc">18.2. Krótkie wpisy</h3>
+<p>
+Metoda <em>__str__()</em> w modelu <em>Entry</em> aktualnie powoduje
+dołączenie wielokropka do każdego egzemplarza klasy <em>Entry</em>, gdy 
+<em>Django</em>
+wyświetla go w witrynie administracyjnej bądź w powłoce. Do wymienionej
+metody dodaj polecenie <em>if</em>, które spowoduje dodanie wielokropka tylko 
+dla
+wpisów dłuższych niż 50 znaków. Za pomocą witryny administracyjnej dodaj
+wpis krótszy niż 50 znaków i sprawdź, czy w trakcie jego wyświetlania jest
+dołączany wielokropek.
+</p>
+<h3 id="2.1.3.exerc">18.3. API Django</h3>
+<p>
+Podczas tworzenia kodu pozwalającego uzyskać dostęp do
+danych w projekcie przygotowujesz tak zwane zapytanie. Przejrzyj dostępną
+na stronie <em>https://docs.djangoproject.com/en/2.2/topics/db/queries/ </em>
+dokumentację dotyczącą tworzenia zapytań pobierających dane. 
+Większość informacji na podanej stronie będzie dla Ciebie nowością, ale 
+staną się użyteczne, gdy zaczniesz pracować nad własnymi projektami.
+</p>
+<h3 id="2.1.4.exerc">18.4. Pizzeria</h3>
+<p>
+Utwórz nowy projekt o nazwie pizzeria wraz z aplikacją o 
+nazwie <em>pizzas</em>. Zdefiniuj model <em>Pizza</em> wraz z atrybutem 
+<em>name</em>, który będzie 
+przechowywał wartości takie jak hawajska lub mięsna. Zdefiniuj drugi model 
+o nazwie <em>Topping</em> wraz z atrybutami <em>pizza</em> i <em>name</em>. 
+Atrybut <em>pizza</em> powinien 
+być kluczem zewnętrznym dla modelu <em>Pizza</em>, natomiast atrybut 
+<em>name</em> powinien 
+przechowywać wartości takie jak ananas, bekon i sos.
+Zarejestruj oba modele w witrynie administracyjnej. W tej witrynie wprowadź
+pewne nazwy pizzy i dodatków. Za pomocą powłoki przejrzyj wprowadzone
+dane.
+</p>
+<h3 id="2.1.5.exerc">18.5. Jadłospis</h3> 
+<p>
+Rozważ aplikację ułatwiającą użytkownikom przygotowanie
+jadłospisu na cały tydzień. Utwórz nowy katalog o nazwie <em>meal_planner</em> 
+i rozpocznij w nim pracę nad nowym projektem <em>Django</em>. Następnie utwórz 
+nową
+aplikację o nazwie <em>meal_plans</em>. Przygotuj prostą stronę główną dla tego 
+projektu.
+</p>
+<h3 id="2.1.6.exerc">18.6. Strona główna pizzerii</h3>
+<p>
+Dodaj stronę główną do projektu pizzerii, nad którym pracę rozpocząłeś w 
+ćwiczeniu 18.4.
+</p>
+<h3 id="2.1.7.exerc">18.7. Dokumentacja szablonów</h3> 
+<p>
+Przejrzyj dokumentację szablonów <em>Django</em>,
+którą znajdziesz na stronie 
+<em>https://docs.djangoproject.com/en/2.2/ref/templates/</em>.
+Zawsze możesz do niej powrócić, gdy będziesz pracować nad własnymi projektami.
+</p>
+<h3 id="2.1.8.exerc">18.8. Strony pizzerii.</h3>
+<p>
+Do projektu pizzerii utworzonego w ćwiczeniu 18.6
+dodaj stronę wyświetlającą nazwy dostępnych rodzajów pizzy. Następnie
+połącz nazwę każdej pizzy ze stronę wyświetlającą dostępne dodatki do 
+pizzy. Upewnij się, że użyłeś dziedziczenia szablonów, aby efektywnie 
+tworzyć strony.
+</p>
+<h2 id="2.2.ch">Rozdział 19:</h2>
+<h3 id="2.2.1.exerc">19.1. Blog</h3>
+<p>
+Rozpocznij pracę nad nowym projektem <em>Django</em> o nazwie <em>Blog</em>.
+W tym projekcie utwórz aplikację o nazwie <em>blogs</em>, zdefiniuj w niej 
+model
+<em>BlogPost</em>. Model powinien mieć kolumny takie jak <em>title</em>, 
+<em>text</em> i <em>date_added</em>.
+Utwórz superużytkownika dla projektu, a następnie wykorzystaj witrynę 
+administracyjną do przygotowania kilku krótkich postów. Strona główna 
+powinna wyświetlać wszystkie posty w kolejności chronologicznej.
+Przygotuj jeden formularz pozwalający na tworzenie nowych postów oraz
+drugi przeznaczony do edycji już istniejących. Wypełnij formularze i 
+upewnij się, że działają prawidłowo.
+</p>
+<h3 id="2.2.2.exerc">19.2. Konta bloga.</h3>
+<p>
+Do projektu bloga zapoczątkowanego w ćwiczeniu 19.1
+dodaj systemu rejestracji i uwierzytelniania użytkowników. Upewnij się, że
+zalogowany użytkownik ma wyświetloną na ekranie swoją nazwę użytkownika,
+natomiast niezarejestrowany otrzymuje dostęp do strony pozwalającej mu na
+dokonanie rejestracji.
+</p>
+<h3 id="2.2.3.exerc">19.3. Refaktoryzacja</h3>
+<p>
+W pliku <em>views.py</em> mamy dwa miejsca, w których 
+sprawdzamy, czy użytkownik będący właścicielem tematu to aktualnie zalogowa
+ny użytkownik. Kod odpowiedzialny za tego rodzaju sprawdzenie umieść w 
+funkcji o nazwie <em>check_topic_owner()</em> i wywołuj ją, gdy zajdzie 
+potrzeba.
+</p>
+<h3 id="2.2.4.exerc">19.4. Ochrona strony new_entry.</h3>
+<p>
+Użytkownik może dodać nowy wpis do
+tematu należącego do innego użytkownika. W tym celu wystarczy podać adres
+<em>URL</em> wraz z identyfikatorem tematu, którego właścicielem jest inny 
+użytkownik. Zastosuj ochronę przed tego rodzaju atakami i sprawdź przed 
+zapisaniem nowego wpisu, czy bieżący użytkownik jest właścicielem tematu, 
+do którego ma zostać dodany ten wpis.
+</p>
+<h3 id="2.2.5.exerc">19.5. Ochrona bloga</h3>
+<p>
+W budowanym projekcie bloga upewnij się, że każdy
+post będzie powiązany z określonym użytkownikiem. Zagwarantuj, że 
+wszystkie posty są dostępne publicznie, ale tylko zarejestrowani 
+użytkownicy mogą dodawać nowe posty i edytować te istniejące. Zanim 
+zostanie przetworzony formularz, w widoku pozwalającym użytkownikowi na 
+edycję postu sprawdź, czy użytkownik edytuje własny post.
+</p>
+<h2 id="2.3.ch">Rozdział 20:</h2>
+<h3 id="2.3.1.exerc">20.1. Inne formularze</h3>
+<p>
+Style <em>Bootstrapa</em> zastosowaliśmy na stronach <em>login</em>
+i <em>add_topic</em>. Wprowadź podobne zmiany w pozostałych stronach opartych na
+formularzach: <em>new_entry</em>, <em>edit_entry</em> i <em>register</em>.
+</p>
+<h3 id="2.3.2.exerc">20.2. Nadanie stylu blogowi</h3>
+<p>
+Wykorzystaj bibliotekę <em>Bootstrap</em> do nadania 
+stylów projektowi bloga, który utworzyłeś w ćwiczeniach do poprzedniego 
+rozdziału.
+</p>
+<h3 id="2.3.3.exerc">20.3. Wdrożenie bloga</h3>
+<p>
+Przeprowadź wdrożenie w <em>Heroku</em> projektu bloga,
+nad którym pracujesz. Aby zapewnić wdrożonej aplikacji względne 
+bezpieczeństwo, upewnij się, że przypisałeś opcji <em>DEBUG</em> wartość 
+<em>False</em>, aby w przypadku
+problemów użytkownicy nie widzieli wyświetlonej pełnej strony błędu 
+<em>Django</em>.
+</p>
+<h3 id="2.3.4.exerc">20.4. Więcej błędów 404</h3>
+<p>
+Funkcja <em>get_object_or_404()</em> powinna być używana
+również w widokach generowanych przez funkcje <em>new_entry()</em> i 
+<em>edit_entry()</em>.
+Wprowadź odpowiednie zmiany, a następnie przetestuj je, podając adres 
+<em>URL</em>
+taki jak <em>http://localhost:8000/new_entry/999/</em> i sprawdzając, czy na 
+pewno otrzymujesz komunikat błędu o kodzie <em>404</em>.
+</p>
+<h3 id="2.3.5.exerc">20.5. Rozbudowa aplikacji Learning Log</h3>
+<p>
+Dodaj jedną funkcję do aplikacji
+Learning Log, a następnie przekaż zmiany do serwera produkcyjnego. Spróbuj
+wprowadzić niewielką zmianę, na przykład nieco obszerniejszy opis 
+przeznaczenia projektu wyświetlany na stronie głównej. Następnie postaraj 
+się dodać trochę bardziej zaawansowaną funkcję, na przykład możliwość 
+publicznego udostępnienia tematu przez jego właściciela. Taka zmiana będzie
+wymagała użycia atrybutu o nazwie <em>public</em> jako części modelu 
+<em>Topic </em>
+(wartością domyślną wymienionego atrybutu powinno być <em>False</em>) oraz 
+elementu 
+formularza na stronie <em>new_topic</em> pozwalającego użytkownikowi na 
+oznaczenie 
+tematu jako prywatnego lub publicznego. 
+Następnie trzeba będzie przeprowadzić migrację
+projektu i zmodyfikować kod w pliku <em>views.py</em>, aby tematy publiczne mogły
+być wyświetlane również przez nieuwierzytelnionych użytkowników. Pamiętaj
+o migracji bazy danych w serwerze produkcyjnym po przekazaniu 
+uaktualnionego projektu do <em>Heroku</em>.
+</p>
+                       </div>
+            </div>
+                                       </body>
+       </html>
diff --git a/articles/terminallog/index.html b/articles/terminallog/index.html
new file mode 100755 (executable)
index 0000000..7ca1321
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+                       <div class="main">
+                               <ul class="special_list">
+          <li><a href="BASH_bushido.html">BASH bushido</a></li>
+          <li><a href="Git_-_podstawy_systemu_kontroli_wersji.html">Git - podstawy systemu kontroli wersji</a></li>
+          <li><a href="konfiguracja_HAProxy_dla_HTTP_i_HTTPS.html">Konfiguracja HAProxy dla HTTP i HTTPS</a></li>
+          <li><a href="laboratorium_sieci_VPN.html">Laboratorium sieci VPN</a></li>
+          <li><a href="sieci_VPN.html">Sieci VPN</a></li>
+          <li><a href="ściąga_z_PYTHONga.html">Ściąga z PYTHONga</a></li>
+          <li><a href="RedHat_-_RHCSA.html">Red Hat Enterprise Linux 9 - RHCSA</a></li>
+          <li><a href="cwiczenia_python.html">Python. Ćwiczenia.</a></li>
+                               </ul>
+                       </div>
+                       <p class="footer">
+                               2022; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/jak_działa_linux.html b/articles/terminallog/jak_działa_linux.html
new file mode 100644 (file)
index 0000000..04f0301
--- /dev/null
@@ -0,0 +1,2122 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <style>
+                               .code-block {
+                                       display: block;
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                                       text-align: left;
+                               }
+                               .code-inline {
+                                       background-color: silver;
+                                       font-family: monospace;
+                                       font-weight: bolder;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+        p { text-align: justify; }
+        .toc { list-style-type: none; }
+                       </style>
+               </head>
+               <body style="font-family: monospace;" >
+<pre>
+     _       _          _     _       _         _     _                  ___ 
+    | | __ _| | __   __| |___(_) __ _| | __ _  | |   (_)_ __  _   ___  _|__ \
+ _  | |/ _` | |/ /  / _` |_  / |/ _` | |/ _` | | |   | | '_ \| | | \ \/ / / /
+| |_| | (_| |   <  | (_| |/ /| | (_| | | (_| | | |___| | | | | |_| |>  < |_| 
+ \___/ \__,_|_|\_\  \__,_/___|_|\__,_|_|\__,_| |_____|_|_| |_|\__,_/_/\_\(_)
+</pre>
+<p style="margin: 0; padding: 0; outline: 0; font-size: 18pt;">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+                       <div style="margin-left: auto; margin-right: auto; width: 80%;">
+        <h1>Jak działa Linux</h1>
+        <div>
+          <h2>Spis treści</h2>
+          <ul class="toc">
+            <li><a href="#1.howlinuxismade">1. Budowa systemu Linux<a>
+              <ul class="toc">
+                <li><a href="#1.1.hardware">1.1. Sprzęt</a>
+                  <ul class="toc">
+                    <li><a href="#1.1.1.ram">1.1.1. Pamięć operacyjna</a>
+                  </ul>
+                </li>
+                <li><a href="#1.2.kernel">1.2. Jądro</a>
+                <li><a href="#1.3.userspace">1.3. Przestrzeń użytkownika</a>
+                <li><a href="#1.4.users">1.4. Użytkownicy</a>
+              </ul></li>
+              <li><a href="#2.linuxbasics">2. Podstawy obsługi Linuksa</a>
+                <ul class="toc">
+                  <li><a href="#2.1.shells">2.1. Powłoka</a></li>
+                  <li><a href="#2.2.shellusage">2.2. Korzystanie z powłoki</a>
+                    <ul class="toc">
+                      <li><a href="#2.2.1.catcommand">2.2.1. Polecenie cat</a></li>
+                      <li><a href="#2.2.2.stdinstdout">2.2.2. Standardowe wejście i standardowe wyjście</a></li>
+                    </ul></li>
+                  <li><a href="#2.3.basicscommands">2.3. Podstawowe polecenia</a></li>
+                  <li><a href="#2.4.commandsworksondir">2.4. Polecenia działające na katalogach</a>
+                    <ul class="toc">
+                      <li><a href="#2.4.1.globbing">2.4.1. Nazwy wieloznaczne</a></li>
+                    </ul></li>
+                  <li><a href="#2.5.proxycommands">2.5. Polecenia pośredniczące</a></li>
+                  <li><a href="#2.6.passwdandchsh">2.6. Zmiana hasła i powłoki</a></li>
+                  <li><a href="#2.7.dotfiles">2.7. Plik z kropką</a></li>
+                  <li><a href="#2.8.shellandenvvars">2.8. Zmienne środowiskowe i powłoki</a></li>
+                  <li><a href="#2.9.path">2,9, Ścieżka poleceń</a></li>
+                  <li><a href="#2.10.specialchars">2.10. Znaki specjalne</a></li>
+                  <li><a href="#2.11.commadlineedit">2.11. Edycja wiersza poleceń</a></li>
+                  <li><a href="#2.12.texteditors">2.12. Edytory tekstu</a></li>
+                  <li><a href="#2.13.gettinghelp">2.13. Uzyskiwanie pomocy</a></li>
+                  <li><a href="#2.14.shellio">2.14. Wejście i wyjście powłoki</a>
+                    <ul class="toc">
+                      <li><a href="#2.14.1.stderr">2.14.1. Standardowy strumień błędów</a></li>
+                      <li><a href="#2.14.2.stdin">2.14.2. Przekierowanie standardowego wejścia</a></li>
+                    </ul></li>
+                  <li><a href="#2.15.readingerrors">2.15. Odczytwanie komunikatów o błędach</a></li>
+                  <li><a href="#2.16.manipulatingprocesses">2.16. Przeglądanie procesów i manipulowanie nimi</a>
+                    <ul class="toc">
+                      <li><a href="#2.16.1.processkilling">2.16.1. Przerywanie działania procesów</a></li>
+                      <li><a href="#2.16.2.jobcontrol">2.16.2. Kontrola zadań</a></li>
+                      <li><a href="#2.16.3.processinbg">2.16.3. Procesy działające w tle</a></li>
+                    </ul></li>
+                  <li><a href="#2.17.filemodeandpermissions">2.17. Tryb pliku i uprawnienia</a>
+                    <ul class="toc">
+                      <li><a href="#2.17.1.modifypermissions">2.17.1. Modyfikacja uprawnień</a></li>
+                      <li><a href="#2.17.2.sylinks">2.17.2. Dowiązania symboliczne</a></li> 
+                    </ul></li>
+                  <li><a href="#2.18.archvesandcompression">2.18. Archiwizowanie i kompresowanie danych</a>
+                    <ul class="toc">
+                      <li><a href="#2.18.1.tarprogram">2.18.1. Program tar</a></li>
+                      <li><a href="#2.18.2.gzipprogram">2.18.2. Program gzip</a></li>
+                      <li><a href="#2.18.3.compressedarchives">2.18.3. Skompresowane archiwa</a></li>
+                      <li><a href="#2.18.4.othercommpression">2.18.4. Inne metody kompresji</a></li>
+                    </ul></li>
+                  <li><a href="#2.19.filesystemhierarchy">2.19. Hierarchia katalogów</a>
+                    <ul class="toc">
+                      <li><a href="#2.19.1.othermainsubdirs">2.19.1. Pozostałe katalogi główne</a></li>
+                      <li><a href="#2.19.2.usrdirectory">2.19.2. Katalog /usr</a></li>
+                      <li><a href="#2.19.3.kernelplace">2.19.3. Umiejscowienie jądra w systemie</a></li>
+                    </ul></li>
+                  <li><a href="#2.20.runitasroot">2.20. Uruchamianie poleceń przez superużytkownika</a>
+                    <ul class="toc">
+                      <li><a href="#2.20.1.sudoersfile">2.20.1. Plik /etc/sudoers</a></li>
+                    </ul></li>
+                  <li><a href="#2.21.summary">2.21. Podsumowanie</a></li>
+                </ul></li>
+          </ul>
+        </div>
+        <p>
+          Opisywany tutaj materiał będzie kompatybilny z dystrybucjami 
+          pochodnymi od GNU/Linux Debian zarówno tymi opartymi na 
+          <em>systemd</em> jak <em>sysvinit</em> oraz tymi z rodziny
+          <em>RHEL</em>/<em>Fedora</em>/<em>CentOS</em>. 
+        </p>
+        <p>
+          GNU/Linux czy raczej sam Linux? Sama nazwa, jest już tematem dość
+          kontrowersyjnym. Ludzie związani z projektem GNU twierdzą, że ta
+          pierwsza liczba jest właściwa ponieważ wskazuje ona na to, że isotne
+          elemnty projektu GNU zostały wykorzystane do stworzenia tego systemu.
+          W mowie potocznej jednak przyjęło się użycie tej drugiej nazwy. Jest
+          to jedno, łatwe do zapamiętania słowo. Jeśli mówimy następujące
+          zdanie wyrażające chęć zainstalowania na jakiejś maszynie omawianego
+          tutaj systemu, mówimy że "zainstalujemy jakiegoś Linuksa". Słowo
+          "jakiegoś" zostało tu użyte w kontekscie wyboru konkretnej
+          dystrybucji. Co to dystrybucja wyjaśnie za chwilę. Bez projektu GNU
+          niebyło by Linuksa. Wydaje mi się, że każdy kto jest nieco bardziej
+          związany z tym środowiskiem o tym wie. Ja również jestem tego świadom
+          dla tego też w tym dokumencie użyje nazwy Linux. Poprostu.
+        </p>
+        <h1 id="1.howlinuxismade">1. Budowa systemu Linux</h1>
+        <p>
+          Nie zagłebiając się w szczegóły, to Linux składa się z 
+          <strong>jądra</strong> oraz
+          <strong>przestrzeni użytkownika</strong>. Oba kompomenty rezydują w 
+          pamięci więc
+          wiele, nie które teksty popularno-naukowe mogą włączać pamięć lub
+          ogólnie sprzęt do składowych systemu operacyjnego Linux, w mojej
+          opinii jest raczej cecha wykorzystywanych przez nas komputerów
+          konwencjonalnych. 
+        </p>
+        <p>
+          Mówiąc o jądrze możemy wskazać konktretny program, konkretny plik.
+          W przypadku przestrzeni użytkownika, w systemie nie istnieje żaden
+          namacalny byt cyfrowy jak w przypadku jądra. Przestrzeń użytkownika
+          jest bowiem <strong>warstwą abstrakcji</strong> - czyli terminem,
+          bądź założeniem wykorzystywanym w celu określenia czynności, funkcji,
+          zjawiska bez wdawania się w szczegóły. Przestrzeń użytkownika jest
+          miejscem uruchamiania <strong>procesów</strong> użytkownika. Procesy
+          to nic innego jak wystąpienia programów uruchomionych przez
+          użytkownika. Nie wszystkie procesy są programami użytkownika w
+          dosłownym tych słów znaczeniu. Część tych procesów to programy
+          wspomagające wykorzystanie komputera i jego zasobów. Bez nich systemy
+          operacyjne dalej mogły by spełniać swoją rolę, jednak nie miały by
+          powszechnie znanej nam dzisiaj formy. Przestrzeń użytkownika  składa 
+          się z wielu ogólno dostępnych kompnentów ich istnienie w danej wersji
+          systemu oraz ich konfiguracja sprawia, iż nie mamy doczynienia z
+          gotowym jednolitym produktem, ale z dystrybucją. Z jedną z wersji, 
+          gdzie ktoś
+          wziął jądro, które jest ogolno dostępne i skomponował przestrzeń
+          użytkownika. Obecnie na rynku mamy dostępnych ok. 600 dystrybucji.
+          Wiekszość z nich to pochodne innych, oryginalnych rozwiązań
+          rozwijanych przez setki osób na całym świecie. Kilka takich głównych
+          dystrybucji, znajduje się w tabeli poniżej. Przejrzałem większość z
+          nich, a z częsci osobiście korzystałem. 
+        </p>
+        <table border="1">
+          <thead>
+            <th>Logo</th>
+            <th>Nazwa</th>
+            <th>Opis</th>
+          </thead>
+          <tbody>
+            <tr>
+              <td><img src="https://i.ibb.co/GspTqqK/linux-mint-logo32.png" alt="linux-mint-logo32" border="0"></td>
+              <td>Linux Mint</td>
+              <td>
+                Dystrybucja bardzo przyjazna użytkownikowi. Wykorzystywana 
+                przez nowych niedoświadczonych użytkowników system Linux. 
+                Pod czas
+                instalacji mogą być instalowane nie wolne moduły oraz nie
+                wolne oprogramownie. Jej głównym zadaniem jest sprzyjanie
+                użytkownikowi i umożliwienie mu wykorzystanie Linuksa przy
+                codziennym wykorzystaniu komputera. Mint rozwijany jest przez
+                społeczność zebraną wokół niego.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/ckrkfjX/ubuntu-logo32.png" alt="ubuntu-logo32" border="0"></td>
+              <td>Ubuntu</td>
+              <td>
+                  Podobnie jak Linux Mint, Ubuntu również jest skierowane dla
+                  osób ceniących sobie wygodne i prostę rozwiązania. Jest
+                  przyjazna użytkownikowi, ma nieco bardziej konserwatywne
+                  podejście do ideii wolnego oprogramowania, jądro może
+                  zawierać nie wolne moduły, jednak zamknięte oprogramowanie
+                  nie jest domyślnie instalowane. Ubuntu rozwijane jest przez 
+                  firmę
+                  Canonical. Jej technologię są wdrażane do Ubuntu, dzięki
+                  czemu może ona uchdzić za system klasy <em>enterprise</em> 
+                  wśród
+                  dystrybucji opartych o GNU/Linux Debian. Poza wersją na
+                  komputery biurkowe istnieją również wersja skierowana
+                  na serwery oraz inne wersje z preinstalowanymi różnymi
+                  środowiskami graficznymi czy wersja skierowana do obróbki
+                  multimediów zawierająca pozwalające do tego oprogramowanie.
+                  Społeczność zebrana
+                  wokół systemu Linux zarzuca jej siłowe próby wdrożenia
+                  manedżera oprogramowania <em>Snap</em>, rozwijanego przez tę 
+                  firmę
+                  przez co może ona pretendować do stopniowego zarzucenia
+                  klasycznego schematu dystrybucji pakietów rozwijanego wraz
+                  z GNU/Linux Debian.
+              </td> 
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/v4026kk/fedora-logo32.png" alt="fedora-logo32" border="0"></td>
+              <td>Fedora Linux</td>
+              <td>
+                  Fedora jest dystrybucją skierowaną do różnej maści
+                  użytkowników, ponieważ istnieje w kilku głównych wersjach.
+                  oraz wiele wersji pobocznych tzw. <em>spins</em>. Fedora ma
+                  najprzyjźniejszy instalator chyba ze wszystkich możliwych
+                  dystrybucji. Wymaga on głównie wybrania miejsca instalacji
+                  i kliknięcia przycisku dalej. Fedora została stworzona i jest
+                  rozwiajana przez firme Red Hat Inc. (obecnie IBM) jako
+                  <em>upstream</em> (poligon doświadczalny dla zmian), dla 
+                  glównego produktu tej firmy Red Hat Enterprise Linux - 
+                  płatnej dystrybucji skierowanej do środowisk produkcyjnych 
+                  (100$ rocznie). Jest to system o dużej stabilości ze
+                  wsparciem dla najnowszego sprzetu. Fedora również
+                  charakteryzuje się wprowadzeniej jako pierwsza środowiska
+                  GNOME w najnowszej wersji 41 oraz innych nowych technologi
+                  wśród otwartego oraz wolnego oprogramowania. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/Q965txs/debian-logo32.png" alt="debian-logo32" border="0"></td>
+              <td>GNU/Linux Debian</td>
+              <td>
+                  Debian jest jedną z pierwszy dostępnych dystrybucji, początek
+                  jej istnienia jest datowany na 1993 rok. Dystrybucja 
+                  konserwatywna, posiadała w pierwszych latach swojego 
+                  istnienia aprobatę FSF (Free Software Fundation). Jednak
+                  została ona wycofana, za zezwolenie na instalację zamkniętego
+                  oprogramowania. Kernel przygotowywany przez twórców tej
+                  dystrybucji pozbawiony jest tzw. blobów binarnych (nie
+                  wolnych prekompilowanych modułów, używanych przy budowaniu
+                  jądra.) Bloby najczęściej dotyczą sterowników sprzętu.
+                  Dystrybucja charkteryzuje się wysoką stabilnościa
+                  porównywalną z RHEL, wsparciem dla starszego sprzętu. Jedną
+                  z cech, która może odstraszać potencjalnych użytkowników
+                  od niej jest długi cykl wydawniczy (co dwa lata) oraz
+                  używanie sprawdzone oprogramowania czy technologii (pozostaje
+                  dość mocno w tyle jeśli chodzi o najnowsze wersje
+                  oprogramowania). Wydaje mi się, że niema
+                  stabilniejszego gotowego rozwiązania niż GNU/Linux Debian.
+                  Debian wymaga nieco większego zaawansowania niż dystrybucje
+                  podane do tej pory. Stosowany jest częściej w środowiskach
+                  produkcyjnych niż np. Ubuntu. Rozwój Debiana opiera się
+                  na zaangażowaniu społeczności z całego świata.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/MpCcKqy/arch-linux-logo32.png" alt="arch-linux-logo32" border="0"></td>
+              <td>Arch Linux</td>
+              <td>
+                  Dystrybucja skierowana do zaawansowanych użytkowników.
+                  Charakteryzuje się wysoką konfigurowalnością oraz
+                  dostępnością najnowszych wersji oprogramowania. Nie posiada
+                  oficjalnego instalatora, choć można pobrać skrypt z sieci.
+                  Instalacji dokonuj się ręcznie, wpisującac kolejne polecenia
+                  z podręcznika instalacji w środowisku LiveCD, gdzie
+                  przygotowuje się dysk, pobiera się pakiety i je konfiguruje.
+                  Instalacja i konfiguracji Arch Linux nie jest tak
+                  pracochłonna jak innych dystrybucji, można by powiedzieć,
+                  meta-dystrybucji. Dość ciekawą cechą jest społeczność zebrana
+                  wokół niej, która przechwalająca się swoją wyższością na
+                  innymi (ponieważ przebrneli przez proces instalacji) 
+                  używając frazy "I use Arch BTW.". Dystrybucja rozwijana
+                  jest przez społeczność na całym świecie.
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/vz98yMx/void-linux-logo32.png" alt="void-linux-logo32" border="0"></td>
+              <td>Void Linux</td>
+              <td>
+                  Nie zależna dystrybucjna, trochę odmienna od inny dystrybucji
+                  głównego nurtu. Systemd zastąpiono programem <em>runit</em>,
+                  zamiast OpenSSL, użyto projektu OpenBSD LibreSSL jak jedyna
+                  z dystrybucji Linuksa. Kernel Void-a pozbawiony jest blobów,
+                  a domyślna instalacja zawiera tylko wolne oprogramowanie,
+                  posiada on jednak oficjalne repozytorium z zamkniętym
+                  oprogramowaniem. Instalacja pakietów opiera się stworzonym
+                  dla Void menedżerze pakietów XBPS. Pakiety są wydawane stylu
+                  <em>rolling release</em>, co daje szybkie i stabline
+                  aktualizacje. Obok standardowej biblioteki języka C -
+                  GNU libc, mamy również bibliotekę <em>musl</em>. Za pomoca
+                  programu <em>xbps-src</em> możemy tworzyć z kodu źródłowego
+                  własne pakiety XBPS. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/0QsPfPh/gentoo-linux-logo32.png" alt="gentoo-linux-logo32" border="0"></td>
+              <td>Gentoo Linux</td>
+              <td>
+                  Gentoo jest dystybucją na tyle zaawansowaną, że można by się
+                  pokusić o nazwanie jej meta-dystrybucją. Jest ona bowiem
+                  jedną z najbardziej konfigurowalnych dystrybucji. Jedną z
+                  ciekawszych czynności, jakie należy wykonać podczas
+                  instalacji, to ręczna kompliacja jądra. Dystrybucja
+                  skierowana do jeszcze bardziej zaawansowanych użytkowników
+                  niż w przypadku Arch Linux. Instalacja Gentoo na maszynie
+                  wirtualnej wraz z poradnikiem, zajeło mi to jakieś dwie
+                  godziny. 
+              </td>
+            </tr>
+            <tr>
+              <td><img src="https://i.ibb.co/hKwFYQh/lfs-logo32.jpg" alt="lfs-logo32" border="0"></td>
+              <td>Linux from scratch</td>
+              <td>
+                  LFS to w zasadzie projekt, a niżejli sama dystrybucja.
+                  Umożliwia on stworzenie oraz skonfigurowanie własnej
+                  dystrybucji. Na stronie projektu zawarte są wskazówki, co
+                  należy zrobić, aby stworzyć rozwiązanie najbardziej
+                  elastyczne dla siebie. LFS z pewnością może nosić miano
+                  meta dystrybucji.
+              </td>
+            </tr>
+          </tbody>
+        </table> 
+        <p>
+          W powyższej tabeli przedstawiłem  dystrybucje, na które
+          warto zwrócić uwagę. Teraz prawdopodobnie czekać będzie Cię duży
+          dylemat, którą wybrać. W pierwszej kolejności ważny jest sprzęt,
+          na którym będziemy z tego systemu korzystać. Część sprzętu, 
+          z którego chcemy korzystać może 
+          nie działać <em>out of box</em>, wowczas potrzebne będą sterowniki,
+          które mogą być własnościowe (nie wolne, generalnie być zamkniętym 
+          oprogramowaniem), jeśli zależy nam na prywatności, to lepiej upewnić
+          się z jakiego rodzaju sprzętem będzie mieć doczynienia, ponieważ 
+          każde zamknięte oprogramowanie można teoretycznie uznać za
+          oprogramowanie szkodliwe. Dobrym wyborem może być zakup Thinkpada z
+          przed 2008 roku. Wówczas będziemy mogli bez obaw wybrać Debiana i
+          zainstalować np. XFCE (to dość lekkie środowisko graficzne, nadające
+          się do codziennej pracy, bez zniechęcania się). Kolejną rzeczą do
+          wyboru dystrybucji jest zapał do pracy. Mimo iż opisując dystrybucje
+          napisałem że ta jest dla początkujących, a ta dla zaawansowanych to 
+          żadna z
+          nich nie jest ani dla jednych ani dla drugich. Obsługa czego kolwiek
+          związanego z komputerami wymaga przeczytania dokumentacji ze
+          zrozumieniem i umiejętności radzenie sobie z ewentualnymi problemami.
+          Dlatego dlaczego by nie wybrać Gentoo, zainstalować go 
+          z poradnikiem, skonfigurować, a wrazie problemów użyć Googla, lub
+          poprość kogoś ze społeczności o pomoc.  
+        </p>
+        <p>
+          Dość częstym zjawiskiem, wśród społeczności użytkowników Linuksa jest
+          tzw. <em>distro-hopping</em>, czyli przesiadanie się z jednej
+          dystrybucji na drugą. Jest to normalne zjawisko, chciaż można
+          powszechną opinia jego jest raczej negatywna, głównym argumentem
+          oponetów jest stwierdzenie, że przez to nie uczymy się niczego. Moim
+          zdaniem, możemy dojść do wniosku, że tak naprawdę nie ma dystrybucji
+          tylko produkt w ciągłej ewolucji z dostępnym takim a takim
+          oprogramowaniem. Nie mam mendżera pakietów, mam program do instalacji
+          i konfiguracji oprogramowania, nieważne czy jest apt, dnf, yum czy
+          pacman. Mam stronę podręcznika i znajduj sobie potrzebne opcje. Mam
+          dostęp do internetu, i wystarczy wyszukać konkretną potrzebną 
+          czynność np.: "Remove packages with all dependencies pacman". I mam
+          gotowy wynik. Wiele miesięcy błądziłem słuchając mendrców jak RMS
+          (<em>Richard Matthew Stallman</em>). Myślcie samodzielnie, 
+          przeskakujcie z distro na distro i bawcię się dobrze.
+        </p>
+        <h2 id="1.1.hardware">1.1. Sprzęt</h2>
+        <p>
+          Sprzęt sam w sobie nie mozę wchodzić z skład systemu operacyjnego,
+          to jego elementy jak pamieć operacyjna, procesor czy pamięć masowa
+          odgrywają w nim bardzo ważna rolę.
+        </p>
+        <h3 id="1.1.1.ram">1.1.1. Pamięć operacyjna</h3>
+        <p>
+          W działaniu systemów operacyjnych takich jak Linux, najważniejszym
+          komponentem sprzętowym może być pamięć operacyjna, ponieważ to w
+          niej rezyduje jądro oraz przestrzeń użytkownika. Dane zapisane w
+          pamięci nie są niczym innym jak zbiorem zer i jedynek określanych
+          mianem <strong>bitów</strong> (najmniejsze przetwarzanej ilości
+          informacji). Procesy oraz jądro są jednymi z takich zbiorów. Takie
+          zbiory określa się mianem <strong>obrazu</strong>. 
+        </p>
+        <h2 id="1.2.kernel">1.2. Jądro</h2>
+        <p>
+          Jądro Linux jest to nadrzędy proces w całym systemie, realizuje swoje
+          działania w czterech obszarch funkcjonalności systemu operacyjnego.
+        </p>
+        <ul>
+          <li><strong>Zarządzanie procesami</strong> - jądro jest
+            odpowiedzialne za uruchamianie, wstrzymywanie, ponowne uruchomienie
+            oraz kończenie pracy procesów. Korzystając ze współczesnych
+            systemów operacyjnych możemy mieć wrażenie uruchomione przez nas
+            programy (a co za tym idzie ich procesy) mogą działać jednocześnie.
+            Dzieje się tak dlatego, iż jądro uruchamia kod procesu na ułamek
+            sekundy, po upłynięciu danego przez jądro <strong>wycinka czasu</strong>
+            stan procesora wykonującego kod danego procesu zapisywany jest
+            w pamięci, a jądro wybiera kolejny proces i ładuje stan procesora
+            po czym wznawia jego wykonanie. Tych czynności jest znacznie więcej
+            zostało tu wymionionych. Te
+            czynności nazywane są <strong>przełączaniem kontekstu</strong>.
+            Na współczesnych procesorach dzieje się to tak szybko, że możemy
+            mieć złudzenie <strong>wielozadaniowości</strong>. W przypadku 
+            maszyn wielordzeniowych jak i wieloprocesorowych jądro nie musi
+            zwalniać wykorzystywanego procesora (rdzenia), ale robi to aby
+            jak najlepiej wykorzystać zasoby.</li>
+          <li><strong>Zarządzanie pamięcią</strong> - każdy proces jest obrazem
+            w pamięci, każdy proces również potrzebuje pamięci na swoje
+            obliczenia. Zadaniem jądra jest przydzielanie, zwalnianie jak i
+            ochrona (przed tym aby proces nie uzyskał dostępu do obszaru
+            innego procesu) przekazanych procesom obszarów. Czynności z tym
+            związane są dość złożone, ale jądro może posiłkować się 
+            rozszerzenim MMU we współczesnych procesorach. Pozwala ono podczas
+            dzielenia pamięci wykorzystać metodę <strong>pamięci wirtualnej</strong>,
+            polegającej na zamianie adresów pamięci, przez co proces jest
+            skonfigurowany, że "tak jakby" miał do dyspozycji całą pamięć
+            fizyczną maszyny. Zamiana adresów wiąże się z potrzebą posiadania
+            map (czy też tabel), pozwalających na odzorowanie adresów, co
+            dokłada czynność aktualizacji mapy podczas przełączania kontekstu.
+            Mapy adresów nazywane są <strong>tablicami stron</strong>.
+          <li><strong>Sterowniki urządzeń</strong> - zadaniem sterowników
+            jest dostarczenie identycznego interfejsu do komunikacji z
+            poszczególnymi urządzeniami zainstalowanymi w komputerze. Za racji
+            to iż swobodny dostęp do sprzetu jest potencjalnie niebezpieczny,
+            to jaka kolwiek próba komunikacji z urządzeniem odbywać się
+            zawsze będzie za pośrednictwem jądra systemu. Sterowniki w systemie
+            Linux są częścią jądra, nie oznacza to jednak, że nie możemy
+            jakiegoś brakującego do instalować. Sterowniki są przechowywane w
+            postaci modułów, które są ładowane podczas uruchamiania jądra, a
+            nie które znich mogą być ładowane podczas pracy systemu.</li>
+          <li><strong>Wywołania systemowe</strong> - są to funkcje udostępnione
+            przez jądro procesom użytkownika. Wywołania realizują zadania,
+            które są trudne do zrealizowania przez procesy użytkownika lub w
+            ogóle nie wykonalne. Przykładem wykonywania wywołań systemowych
+            jest obsługa plików (otwieranie, odczyt czy zapis), innymi
+            bardzo często wykorzystywanymi wywołaniami są <em>fork()</em> oraz
+            <em>exec()</em>, wykonywane są za każdym wydanym poleceniem w
+            powłoce.</li> 
+        </ul>
+        <p>
+          Inną ciekawą cechą jądra są <strong>pseudourządzenia</strong>.
+          Procesy widzą takie urządenia jak każde inne, jednak występują on
+          wyłącznie w warstwie programowej, dzięki temu nie muszą być częścią
+          jądra, ale ze względów praktycznych się je tam umieszcza. Inna
+          implementacja urządzenia <em>/dev/random</em> - służacego
+          do generowania liczb pseudolosowych, które jest urządzeniem 
+          programowym mogłoby nie być zbyt bezpieczne.
+        </p>
+        <h2 id="1.3.userspace">1.3. Przestrzeń użytkownika</h2>
+        <p>
+          Przestrzeń użytkownika formalnie jest obszarem pamięci, w którym
+          spedzimy 99% czasu pracy na Linuksie. Wewnątrz przestrzeni
+          użytkownika znajdują się procesy definiujące dystrybucje wykonujące
+          różne zadania dla użytkownika, teoretycznie są one wobec siebie
+          równe, to jednak przestrzeń użytkownika można podzielić na trzy
+          warstwy, na której warstwie będzie znajdować się proces zależy jak
+          bardzo skomplikowane zadania wykonuje. Przeglądarka sieci WWW, może
+          się taka nie wydawać ale to potężny subsystem więc będzie znajdować
+          na najwyższej warstwie, z kolei proces służący za rejestrowanie
+          logów, tzw. protokół diagnostyczne będzie znajdować się na najniższej
+          warstwie blisko jądra, ponieważ nie jest on zbyt skomplikowany w
+          porównaniu do na przykład przeglądarki, warstwa środkowa
+          zarezerowana jest dla różnej maści serwerów. Najproście rzecz ujmując
+          podstawowe usługi znajdują się na najniższej warstwie, usługi
+          pomocnicze na warstwie środkowej, a aplikacje, które kontroluje już
+          sam użytkownik będą znajdować się na samej górze. Procesy mogą
+          komunikować się z innymi procesami o ile te znajdują się na tym
+          samym lub niższym poziomie. Używanie tego rozdzaju podziału, może
+          być kłopotliwe ponieważ obecne serwery nie są już tak prostym
+          oprogramowaniem więc powinny znajdować się tej samej warstwie co
+          przeglądarka czy klient pocztowy, jednak to te aplikacje mogą
+          wykorzystywać serwery do realizacji zadań użytkownika, więc ich
+          miejsce jest raczej na warstwie centralnej (środkowej).
+        </p>
+        <h2 id="1.4.users">1.4. Użytkownicy</h2>
+        <p>
+          Użytkownicy w Linksie są odwzorowaniem rzeczywistych obiektów, czyli
+          <em>encją</em>. Użytkownicy mają prawo do uruchamiania procesów oraz
+          posiadnia (bycia właścielem) plików. Jądro nie rozpoznaje
+          użytkowników po ich nazwach, tak jak mają w zwyczaju to ludzie,
+          używa ono identyfikatorów <strong>userid</strong> w skrócie
+          <strong>UID</strong>. Identyfikatory są przedstawiane za pomocą 
+          liczb. 
+        </p>
+        <p>
+          Użytkownicy istnieją wyłącznie po to aby wyznaczać granice. Każdy
+          proces ma swojego właściela, dlatego też mówi się że proces
+          uruchamia się z uprawnieniami takiego a takiego użytkownika.
+          Użytkownicy mogą uruchamiać i konczyć procesy w własnych granicach
+          (tylko te, których są właścicielami), przez co nie mogą wpływać na
+          procesy innych użytkowników. Poza procesami, użytkownicy mogą 
+          tworzyć własne pliki, których automatycznie stają się właścicielami.
+          Mogą oni decydować czy chcą się nimi dzielić, ustalając im
+          odpowiednie uprawnienia.
+        </p>
+        <p>
+          Poza użytkownikami przypisanymi do konkretnych osób (raczej
+          spotkamy jednego), istnieje kilku dodatkowych specjalnych 
+          użytkowników, głównie mają oni na celu ograniczenie uprawnień
+          serwerów. Po za tymi specjalnymi istnieje jeszcze użytkownik
+          <strong>root</strong>, którego nie tyczą się zapisane powyżej
+          ograniczenia dlatego jest on nazywany <em>superużytkownikiem</em>.
+        </p>
+        <p>
+          Osoba pracująca na koncie użytkownika <em>root</em>, nazywana jest
+          <em>administratorem systemu</em>. <em>Root</em> może kończyć
+          procesy innych użytkowników, przeglądać cudze pliki czy instalować
+          oprogramowanie z repozytorium. Praca na tym koncie jest dość
+          niebezpieczna z punktu widzenia systemu, ponieważ ten użytkownik
+          jest wstanie wykonać czynności prowadzące do zniszczenia całego
+          systemu. Na Linuksie <em>root</em> ma do tego pełne prawo, dlatego
+          projektancji dystrybucji starają się ograniczyć konieczność pracy
+          z wykorzystaniem tego użytkownika.
+        </p>
+        <p>
+          Innym tworem podobnym to użytkowników są <strong>grupy</strong>.
+          Grupy są zbiorem użytkowników, a ich zadaniem jest współdzielenie
+          plików wewnątrz jednej grupy, między jej użytkownikami.
+        </p>
+        <h1 id="2.linuxbasics">2. Podstawy obsługi Linuksa</h1>
+        <p>
+          W tym rozdziale przedstawione zostaną podstawy obsługi systemu
+          Linux, oczywiście z poziomu powłoki, ponieważ inne sposóby
+          zależą w dużej mierze od programów, które do tego celu będziemy
+          wykorzystywać. Takich programów może być kilka, powłok
+          również dostępnych jest kilka rodzajów, jednak sam program powłoki
+          nie będzie wpływać na prezentowane w tym rozdziale czynności. Ten
+          rozdział zaczniem od tego czy jest powłoka.
+        </p>
+        <h2 id="2.1.shells">2.1. Powłoka</h2>
+        <p>
+          <strong>Powłoka</strong> jest chyba jednym z najistoniejszych 
+          komponentów systemu
+          Linux, pozwala ona na uruchamianie róznych poleceń wydawanych przez
+          użytkownika. Powłoki są również małymi środowiskami programistycznymi.
+          Nie które narzędzia systemowe są <strong>skryptami powłoki</strong> - 
+          plikami tekstowymi zawierającymi zbiór wykonywanych kolejno (jedno po
+          drugim) poleceń powłoki.
+        </p>
+        <p>
+          Pierwotną powłoką była <strong>powłoka Bourna</strong>, opracowana
+          jeszcze dla systemu UNIX w laboratoriach <em>Bell Labs</em>. Mimo
+          niezbyt częstego wykorzystywania, powłoka ta jest stałym kompenetem
+          nie tylko systemu Linux, ale i innych systemów uniksopodbnych.
+          Obecnie wykorzystywaną powłoką jest <strong>BASH</strong> - 
+          ulepszona wersja oryginalnej powłoki. Korzystając z róznych
+          dystrybucji, domyślna powłoka może być inna. Ten materiał zakłada
+          wykorzystanie powłoki BASH, szczególnie w rozdziale poświęconym 
+          skryptom powłoki.
+        </p>
+        <h2 id="2.2.shellusage">2.2. Korzystanie z powłoki</h2>
+        <p>
+          Dostęp do powłoki może odbywać się w dwojaki sposób wykorzystać
+          możemy wbudowaną w każdą dystrybucję konsole, nie zależnie od
+          instalacji wybranej przez nas dystrybucji. Jeśli jest to dystrybucja
+          skierowana do komputery biurkowe, to możemy skorzystać z wbudowanego
+          programu <em>terminal</em>. Po uruchomieniu okna powłoki, w prawym
+          górnym rogu pojawi się <strong>symbol zachęty</strong>. Jest to ciąg
+          znaków wskazujący wiersz, w którym będziemy wprowadzać polecenia.
+          Znak zachęty może przyjmować różną formę:
+        </p>
+        <ul>
+          <li><code class="code-inline">użytkownik@host:ścieżka$</code> - 
+            <code class="code-inline">użytkownik</code> - nazwa użytkownika,
+            <code class="code-inline">host</code> - nazwa komputera,
+            <code class="code-inline">ścieżka</code> - obecna ścieżka
+            (czym jest ścieżka, będzie za chwilę). Tego typu symbol zachęty
+            stosowany jest w dystrybucjach opartych na GNU/Linux Debian takich
+            Linux Mint (Mint oparty jest na Ubuntu, a Ubuntu na GNU/Linux
+            Debian) czy Ubuntu.</li>
+          <li><code class="code-inline">[użytkownik@host:katalog]$</code> -
+            <code class="code-inline">użytkownik</code> i
+            <code class="code-inline">host</code> podobnie jak wyżej,
+            <code class="code-inline">katalog</code> - katalog w którym się
+            obecnie znajdujemy, z tego typu znakiem zachęty spotkamy się
+            w dystrybucjach RHEL/Fedora/CentOS oraz Arch Linux.</li>
+          <li><code class="code-inline">bash-wersja$</code> - Originalny symbol
+            zachęty powłoki BASH, <code class="code-inline">wersja</code>
+            przedstawia wersję wykorzystywanej powłoki, spotkamy go
+            w ręcznych instalacjach powłoki (kompilacji kodu źródłowego)</li>
+          <li><code class="code-inline">$</code> - symbol zachęty
+            wykorzystywany w celu zaoszczędzenia miejsca w wierszu polecenia.</li>
+        </ul>
+        <p>
+          W tych symbolach jeden element jest stały jest to znak dolara
+          (<strong>$</strong>), oznacza on że polecenia wydawane będą jako
+          zwykły użytkownika, innym symbolem jest znak krzyżyka
+          (<strong>#</strong>), który mówi nam że polecenia będą uruchamiane
+          przez superużytkownika. Najprostsze polecenie jakie możemy wydać
+          jest użycie polecenia <strong>echo</strong>, które zwraca na
+          standardowe wyjście podajny mu jako argument ciągu znaków:
+        </p>
+<pre class="code-block">
+$ echo Witaj świecie.
+</pre>
+        <p>
+          W przykładach w tym materiale, jeśli polecenia ma zostać wydane z
+          uprawnieniami zywkłego użytkownika, przed poleceniem będzie
+          pojawiać się znak dolara (<strong>$</strong>), a jeśli polecenie ma 
+          być uruchomione z wyższymi uprawnieniami, będą one poprzedzone 
+          znakiem krzyżyka (<strong>#</strong>) oznaczający uprawnienia 
+          użytkownika <em>root</em>.
+        </p>
+        <h3 id="2.2.1.catcommand">2.2.1. Polecnie cat</h3>
+        <p>
+          Polecenie <strong>cat</strong> wypisuje na standardowe wyjście
+          podane w argumentach pliki jeden po drugim dokonując tym samym
+          połączenia (konkatenacji - stąd nazwa polecenia) na jednym
+          strumieniu zawartości tych wszystkich plików.
+        </p>
+<pre class="code-block">
+$ cat plik1 plik2 plik3 ...
+</pre>
+        <h3 id="2.2.2.stdinstdout">2.2.2. Standardowe wyjście i standardowe
+        wejście</h3>
+        <p>
+          Użyłem powyższego polecenia <em>cat</em>, aby nakreślić kontekst dla
+          omówienia dwóch podstawowcyh strumieni. Linux wykorzystuje strumień
+          wejściowy do odczytu danych, a strumień wyjściowy do ich zapisu. 
+          Źródłem strumienia wejściowego może być plik, urządzenie, terminal czy
+          strumień wyjściowy innego procesu. 
+        </p>
+        <p>
+          Strumień wejściowy możemy zaobserować poprzez uruchomienie polecenia
+          <em>cat</em> bez żadnego pliku. Program nie zwróci od razu znaku
+          zachęty, ponieważ oczekuje na dane. Możemy wpisać co kolwiek, a po
+          naciśnięciu klawisza <em>enter</em> polecenie powtórzy ten wpisany
+          tekst. Z racji tego iż nie podaliśmy mu żadnego pliku polecenie
+          zaczęło korzystać ze strumienia <strong>standardowego wejścia</strong>,
+          przekazanego
+          mu przez jądro, w tym przypadku był to terminal, którym zostało
+          uruchomione to polecenie. Aby zakończyć to polecenie należy wciśnąć
+          kombinacje klawiszy <em>Ctrl+d</em>, która oznacza koniec 
+          danych ze standardowego wejścia. 
+        </p>
+        <p>
+          Ze <strong>standardowym wyjściem</strong> jest podobnie, jądro
+          przezkazuje strumień standardowego wyjścia procesom, do którego
+          mogą one zapisywać swoje dane. Polecenie <em>cat</em> zawsze 
+          wypisuje swoje
+          dane na standardowe wyjście, które przez uruchomienie polecenia w
+          terminalu jest do niego podłączone. Dzięki temu mogliśmy zobaczyć
+          wypisywane przez polecenie dane.
+        </p>
+        <p>
+          Standardowe wyjście oraz standardowe wejście możemy zapisać
+          skrótowo <strong>stdout</strong> oraz <strong>stdin</strong>.
+          Takich nazw również należy się spodziewać w wszelakiej dokumentacji.
+        </p>
+        <p>
+          Prócz wspomanianych strumieni istnieje jeszcze trzeci strumień
+          wejścia-wyjścia - <strong>standardowy strumień błędów</strong>.
+          Opiszę go nieco później.
+        </p>
+        <p>
+          Strumienie są dość elastycznym mechanizem, można je zmusić do
+          odczytywania i zapisywania danych z innych miejsc niż terminal.
+          O przekierowaniach strumienii będzie nieco poźniej w tym rozdziale.
+        </p>
+        <h2 id="2.3.basicscommands">2.3. Podstawowe polecenia</h2>
+        <p>
+          Poniżej znajduje się pogrupowane przedstawienie najbardziej
+          podstawowych poleceń niezbędnych do pracy w powłoce systemu Linux.
+        </p>
+        <ul>
+          <li>polecenie <strong>ls</strong> - wypisuje zawartość katalogu.
+            Najważniejsze opcje:
+            <ul>
+              <li><strong>-a</strong> - powoduje wyświetlenie wszystkich
+              elementów, łącznie z tzw. <em>dot-files</em> (plikami ukrytymi,
+              plikami konfiguracyjnymi</li>
+              <li><strong>-l</strong> - wyświetlenie zwartości katalogu w
+              postaci kilku kolumnowej tabeli zawierającej m.in uprawnienia,
+              czas ostatniej modyfikacji plików, wielkość czy przypisanie 
+              pliku, katalogu do użytkownika oraz grupy.
+            </ul></li>
+          <li>polecenie <strong>cp</strong> - kopiujej pliki
+            Najważniejsze opcje:
+            <ul>
+              <li><strong>-p</strong> - zachowuje atrybuty kopiowanych plików,
+                na przykład takie jak uprawnienia czy przypisanego właściela i
+                grupę</li>
+              <li><strong>-r</strong> - kopiowanie rekurencyjne, kopiuje całe
+                katalogi wraz z podkatalogami oraz ich zawartością.</li>
+              <li><strong>-v</strong> - włącza komunikaty diagostyczne,
+                polecenie wypisuje co, gdzie kopiuje. Normalnie program nie
+                zwraca nic poza znakiem zachęty po zakończonym kopiowaniu.</li>
+            </ul></li>
+          <li>polecenie <strong>mv</strong> - w najprostszym przypadku
+            polecenie służy do zmiany nazwy pliku, jednak gdy drugim
+            argumentem będzie katalog, plik zostanie przeniesiony do tego
+            katalogu. Najważniejsze opcje:
+            <ul>
+              <li><strong>-v</strong> - włącza komunikaty diagnostyczne,
+                identycznie jak w przypadku <em>cp</em>.</li>
+            </ul></li>
+          <li>polecenie <strong>touch</strong> - aktualizuje czas modyfikacji
+            pliku, jeśli plik nie istnieje to zostanie utworzony pusty plik o
+            podanej w argumencie nazwie.</li>
+          <li>polecenie <strong>rm</strong> - polecenie służy do kasowania
+            plików. Kombinacja opcji <strong>-rf</strong> wykorzystywana jest
+            kasowania całych katalogów z podkatalogami. Najważniejsze opcje:
+            <ul>
+              <li><strong>-r</strong> - umożliwia, kasowanie rekurencyjne,
+                całych katalogów z podkatalogami.</li>
+              <li><strong>-f</strong> - przed każdym kasowaniem pliku polecenie
+                pyta czy jesteśmy pewni, że chcemy skasować ten plik. Ta opcja
+                pomija to pytanie wymusząjąc tak jakby kasowanie.</li>
+            </ul></li>
+          <li>polecenie <strong>echo</strong> - polecenie wypisuje ciąg znaków
+            podany jako argument na standardowe wyjście. Najważniejsze opcje:
+            <ul>
+              <li><strong>-n</strong> - ta opcja wyłącza przechodzenie
+                do nowej linii, po wypisaniu ciągu znaków.</li> 
+            </ul></li>  
+        </ul>
+        <h2 id="2.4.commandsworksondir">Polecenia działające na katalogach</h2>
+        <p>
+          Uniksy w tym i Linux, korzystają ze standardu hierarchi katalogów,
+          aby utrzymać w porządku dane przestrzeni użytkownika. Za początkowy
+          katalog uznaje się <strong>katalog główny</strong> oznaczany prawym 
+          ukośnikiem lub
+          slashem (<strong>/</strong>), wewnątrz tego katalogu znajdują się
+          pod katalogi, przechowujące konkretny rodzaj czy typ plików zgodny
+          z ich przeznaczeniem.
+        </p>
+        <p>
+          Droga do konkretnego katalogu nosi nazwę <strong>ścieżki</strong>.
+          Jeśli ścieżki zaczynają się od <em>/</em>, czyli od katalogu głównego
+          mamy doczynienia ze <strong>ścieżką bezwzględną</strong>. Elementy 
+          katalogów na
+          ścieżkach katalogi mogą być również wyrażane z pomocą jednej lub 
+          dwóch kropek.
+          Dwie kropki (<strong>..</strong>) oznaczają katalog nadrzędny
+          względem aktualnego katalogu, zaś jedna kropka oznacza
+          (<strong>.</strong>) aktualny katalog. Ścieżki nie zawierające
+          slasha na początku, czyli nie zaczynające się od katalogu głównego
+          są wówczas określane mianem <strong>ścieżki względnej</strong>.
+        </p>
+        <ul>
+          <li>polecenie <strong>cd</strong> - polecenie służy do zmiany
+            aktualnego katalogu, jako argument przyjmuje katalog, do którego
+            checemy przejść, równie dobrze możemy przenieść się w dowolne
+            miejsce w systemie plików (w katalogu głównym) podając jako
+            argument ścieżkę. Nie podanie argumentu spowowduje przejście do
+            katalogu domowego użytkownika.</li>
+          <li>polecenie <strong>mkdir</strong> - polecenie tworzy nowy katalog.
+            Jako argument przyjmuje nazwę katalogu lub ścieżkę. Najważniejsze 
+            opcje:
+            <ul>
+              <li><strong>-p</strong> - opcja tworzy katalogi nadrzędne podane
+                w ścieżce o ile te nie istnieją. Za pomocą odpowiednich
+                podstawień powłoki oraz tej opcji można tworzyć całe struktury
+                katalogowe.</li>
+            </ul></li>
+          <li>polecenie <strong>rmdir</strong> - usuwa katalog po warunkiem, że
+            jest on pusty. W przeciwnym razie polecenie zwróci błąd. Chcąc
+            usuwać całe katalogi z danymi oraz podkatalogami należy użyć
+            polecenia <em>rm -rf</em>.</li>
+        </ul>
+        <h3 id="2.4.1.globbing">2.4.1. Nazwy wieloznaczne.</h3>
+        <p>
+          Dzięki możliwością powłoki możemy porównywać proste wzorce z nazwami
+          plików w obrębie aktualnego katalogu roboczego (katalogu w którym
+          się znajdujemy) czynność ta nazywana jest rozwijaniem nazw lub
+          <em>globbingiem</em>. Jednym z elementów biorących udział w 
+          rozwiązywaniu nazw jest gwiazdka (<strong>*</strong>) oznaczająca
+          dowolną ilość dowolnych znaków. Dla przykładu poniższe polecenie:
+        </p>
+<pre class="code-block">
+$ echo *
+</pre>
+        <p>
+          Zwróci nazwy wszystkich plików i katalogów  znajdujących się w 
+          katalogu. Innym
+          znakiem wykorzystywanym przy nazwach wieloznacznych jest
+          znak zapytania (<strong>?</strong>) reprezentuje on jeden dowolny
+          znak, dla wzorca <em>b?at</em> pasującymi nazwami mogą być
+          <em>blat</em> oraz <em>brat</em>. Rozwinięcia nazw dokonuje powłoka
+          przed uruchomieniem, więc jeśli chcemy aby, któreś ze znaków 
+          wieloznacznych trafiło do polecnie to należy umieść je w pojedyńczych
+          cudzysłowach.
+        </p>
+        <h2 id="2.5.proxycommands">2.5. Polecenia pośredniczące</h2>
+        <ul>
+          <li>polecenie <strong>grep</strong> - wyszukuje wzorzec
+          w podanym pliku. Polecenie to korzysta z systemu wzorców nazwanych
+          <strong>wyrażeniami regularnymi</strong>. Najważniejszymi opcjami:
+          <ul>
+            <li><strong>-i</strong> - wyłącza rozróżnianie małych i
+            wielkich liter.</li>
+            <li><strong>-v</strong> - podwoduje odwrócenie wyszukiwania,
+            zwracane są wyniki nie pasujące do wzorca.</li>
+            <li><strong>-e</strong> - wykorzystuje rozszerzony zestaw 
+            instrukcji pozwalajacych na tworzenie wyrażeń regularnych.</li>
+            <li><strong>-o</strong> - opcja powoduje zwrócenie dokładnie
+            tylko tych znaków pasujących do wzorca. Normalnie polecenie zwraca
+            linię z elementami pasującymi do wzorca, w przypadku wielu plików
+            zwraca również nazwę pliku.</li>
+          </ul>
+          Tworzenie wyrażeń regularnych oraz więcej opcji tego polecenia
+          znajduje się na stronie podręcznika uruchamianej poleceniem:
+<pre class="code-block">
+$ man grep
+</pre>
+          Do najważniejszych wyrażeń, które każdy powinien znać należą:
+          <ul>
+            <li><strong>.*</strong> - oznaczające dowolną ilość dowolnych
+              znaków.</li>
+            <li><strong>.</strong> - oznacza jeden dowolny znak.</li>
+          </ul></li>
+          <li>polecenie <strong>less</strong> - wypisuje dane z pliku, lub
+            ze strumienia wykorzysując podział na strony. Jedna strona to jeden
+            ekran. Następne strony są wyświetlane za naciśnięciem <em>spacji</em>
+            stronę możemy cofnąć klawiszem <em>b</em>, zakończyć przeglądanie
+            danych klawiszem <em>q</em>. Dane możemy przeglądać linia po linii
+            używając strzałek. Możliwe jest również wyszukiwanie fraz w danych
+            za pomocą <em>/</em> (wyszukiwanie w przód) lub za pomocą 
+            <em>?</em> (wyszukiwanie w tył).</li>
+          <li>polecenie <strong>pwd</strong> - wyświetla obecny katalog
+            roboczy powłoki (świeżkę na której się znajdujemy). Polecenie
+            niepozorne choć przydatne, ze względu na dowiązania symboliczne
+            (będzie o nich w dalszej części materiału), które mogą przesłaniać
+            ścieżkę wyświetlaną w znaku zachęty. Najważnejsza opcja jest
+            uruchamiana, gdy nie ma żadnej opcji, więc jej opis pominę.
+            Warto dodać, że obecne systemy posiadają polecenie <em>pwd</em>
+            wbudowane w powłokę. Dlatego też opcja <strong>-P</strong>
+            rozwijająca fizyczne ścieżki nie jest automatycznie uruchamiana
+            w przypadku poprostu wydania polecenia <em>pwd</em>, prawdziwe
+            polecenie <em>pwd</em> uruchamiamy:
+<pre class="code-block">
+$ /usr/bin/pwd
+</pre>
+          </li>
+          <li>polecenie <strong>diff</strong> - wszukuje różnice pomiędzy
+            dowoma plikami tekstowymi. Polecenie to posiada wiele różnych opcji
+            formatowania danych wyjściowych, najbardziej czytelnym pozostaje
+            chyba użycie opcji <strong>-u</strong>. Polecenie wykorzystywane
+            programistów oraz system kontroli wersji git.</li>
+          <li>polecenie <strong>file</strong> - polecenie zwraca format pliku
+            podanego jako argument. W uniksach nie potrzeby stosowania
+            rozszerzeń plików, więc to polecenie może pomóc nam dowiedzieć
+            się co zawiera plik.</li>
+          <li>polecenie <strong>find</strong> i <strong>locate</strong> -
+            polecenia te służą do wyszukiwania plików w systemie. Polecenie
+            <em>find</em> wymaga podania katalogu po nazwie polecenia, nazwy
+            wyszukiwanego pliki po opcji <strong>-name</strong> oraz opcji
+            <strong>-print</strong>, która powoduje wyświetlenie na strumieniu
+            standardowego wyjścia nazw plików pasujących do wzorca podanego w
+            opcji <em>-name</em>. Polecenie <strong>locate</strong> na podobne
+            zastosowanie jak <em>find</em> działa jednak od niego szybciej
+            ponieważ bazuje na indeksie przygotowywanym co jakiś czas przez
+            system operacyjny. Może być ono bezużyteczne, kiedy szukamy nowych
+            plików, gdyż mogą być one nie ujęte jeszcze w indeksie.</li>
+          <li>polecenie <strong>head</strong> i <strong>tail</strong> -
+            te polecenia służa do prezentowania wycinka danych czy to ze
+            strumienia lub z pliku. W przypadku polecenia <em>head</em>
+            prezentowane jest <em>n</em> pierwszych linii, domyslnie 10;
+            z kolei polecenie tail prezentuje <em>n</em> koncowych linii.
+            Liczbę linii podajemy bezpośrednio po znaku myślnika
+            (<strong>-</strong>). Z tych dwóch poleceń polecenie <em>tail</em>
+            ma nieco większe zastosowanie niż polecenie <em>head</em>. Mozemy
+            wywołać to polecenie aby wyświetlić dane od linii, numer linii
+            podajemy po znaku plusa (<strong>+</strong>), inna właściwością
+            chyba najważniejszą jest wyświetlanie danych na żywo, używając
+            opcji <strong>-f</strong>, a następnie nazwy pliku lub myślnika
+            gdy dane pochodzą ze strumienia wyjściowego innego polecenia.</li>
+          <li>polecenie <strong>sort</strong> - układa wiersze z pliku
+            tekstowego w porządku alfabetycznym, jeśli na początku wierszy
+            znajdują się liczby to aby je posortować należy użyć opcji
+            <strong>-n</strong>, aby odwrócić sortowanie możemy użyć opcji
+            <strong>-r</strong>.</li>
+        </ul>
+        <h2 id="2.6.passwdandchsh">2.6. Zmiana hasła i powłoki</h2>
+        <p>
+          W celu zmiany hasła należy użyć polecenia <strong>passwd</strong>.
+          Polecenie poprosi o podanie obecnego hasła, po zatwierdzeniu go
+          zostaniemy poproszeni o nowe hasło i jego potwierdzenie (wpisanie
+          ponowne nowego hasła).
+        </p>
+        <p>
+          Zmiana aktywnej powłoki odbywa się za pomocą polecenia
+          <strong>chsh</strong>, albo użyć poleceń odpowiadających nazwom
+          innych powłok, kolejno <strong>ksh</strong> - Korn SHell,
+          <strong>tcsh</strong> - TENEX C SHell. Użycie tych poleceń w 
+          aktywnej powłoce, spowoduje uruchomienie podpowłoki. Zamkniecie
+          jej spowoduje powrót do pierwotnej powłoki.
+        </p>
+        <h2 id="2.7.dotfiles">2.7. Pliki z kropką</h2>
+        <p>
+          Przeglądając pliki nawet w własnym katalogu domowym możemy znaleźć
+          pliki, których nazwa zaczyna się od kropki. Nie które źródła mówią
+          tym o że te pliki są ukryte. Do takich wniosków może dojść,
+          ponieważ te pliki nie są domyślnie wyświetlane przez polecenie
+          <em>ls</em> bez opcji <em>-a</em> lub przez menedżery plików dostępne
+          w desktopowych wersja Linuksa. Jednak te pliki nie różnia się niczym
+          od inny plików, poza właśnie tym przypadkiem opisanym powyżej.
+          Oprócz plików, nazwy katalogów również mogą zaczynać się od kropki.
+          Za pomocą prostego wzorca możemy wyświetlić wszystkie <em>dot-files</em>,
+          jeśli wsród nich trafi się katalog, wówczas zostanie wyświetlona jego
+          nazwa a pod nią jego zawartość. 
+        </p>
+<pre class="code-block">
+$ ls .??*
+</pre>
+        <h2 id="2.8.shellandenvvars">2.8. Zmienne środowiskowe i powłoki</h2>
+        <p>
+          Powłoka może przechowywać zmienne tymczasowe, które mogą przechowywać
+          różne wartości, mogą one kontrolować zachowanie samej powłoki jedną
+          z takich zmiennych jest zmienna <strong>PS1</strong> zawierająca
+          znak zachęty. Takie zmienne najczęsćiej wykorzystywane są w 
+          skryptach powłoki i nazywane są <strong>zmiennymi powłoki</strong>.
+          Definicja zmiennych tego składa się z nazwy zmiennej, operatora
+          przypisania (znaku równości <strong>=</strong>) oraz wartości samej
+          zmiennej.
+        </p>
+<pre class="code-block">
+$ zmienna=12
+</pre>
+        <p>
+          Odwołać się do wartości zmiennej możemy w dowolnym momencie, podając
+          jej nazwę poprzedzoną znakiem dolara (<strong>$</strong>).
+        </p>
+<pre class="code-block">
+$ echo $zmienna
+</pre>
+        <p>
+          <strong>Zmienna środowiskowa</strong> jest podobna do zmiennej
+          powłoki, ale nie jest ściśle związana z powłoką, bowiem do pamięci
+          zmiennych środowiskowych systemach uniksopodobnych mają wszystkie
+          aplikacje, system operacyjny przezkazuje je do każdego programu
+          uruchomionego w powłoce, programy te nie mają jednak dostępu do
+          zmiennych powłoki. Zmienne środowiskowe definiuje się w ten sam 
+          sposób
+          jak zmienne powłoki, jedna aby taka zmienna stała się zmienną
+          środowiskową musi zostać przeniesiona do pamięci tych zmiennych
+          za pomocą polecenia <strong>export</strong>.
+        </p>
+<pre class="code-block">
+$ zmienna=21
+$ export zmienna
+</pre>
+        <p>
+          Nie które programy mogą wykorzystywać zmienne środowiskowe do
+          własnej konfiguracji. Dla przykładu niektóre programy uruchamiane
+          w powłoce korzystają ze zmiennej środowiskowej <em>EDITOR</em>
+          definiujące domyślny program do edycji plików tekstowych.
+          Wykorzystanie zmiennych środowiskowych zapewne jest opisane w
+          na stronie podręcznika programu.
+        </p>
+        <h2 id="2.9path">2.9. Ścieżka poleceń</h2>
+        <p>
+          Istnieje specjalna zmienna środowiskowa <strong>PATH</strong>,
+          przechowywująca katalogi, w których to powłoka będzie szukać
+          programów odpowiadających wpisanym poleceniom. Jeśli wśród
+          przeszukiwanych katalogów znajduje się kilka programów o tej samej
+          nazwie to powłoka uruchomi pierwszy przez nią znaleziony. Ścieżki
+          katalogów w tej zmiennej odzielone są dwukropkiem (<strong>:</strong>).
+          Posiadając swoje programy, możemy również umieść katalog z nim
+          wewnątrz zmiennej <em>$PATH</em>. Opcje dodanie katalogu są dwie
+          i mogą mieć wpływ na funkcjonowanie systemu. Możemy dodać nasz
+          katalog na początku zmiennej, wówczas powłoka zacznie od niego
+          poszukiwania, jednak należy pamiętąc przy tym, aby nazwy programów
+          nie pokrywały się istniejącymi dotychczas poleceniami.
+        </p>
+<pre class="code-block">
+$ PATH=kat:${PATH}
+</pre>
+        <p>
+          Na powyższym przykładzie <code class="code-inline">kat</code>, to 
+          nasz katalog z oprogramowaniem. Możemy jednak skorzystać
+          bezpieczeniejszego rozwiązania - dopisać nasz katalog na końcu listy
+          katalogów zmiennej <em>PATH</em>, wówczas nawet jeśli nasz program 
+          będzie
+          nazywać się jak jedno z instniejących już poleceń w systemie, nie
+          będzie miało to wpływu na działanie systemu.
+        </p>
+<pre class="code-block">
+$ PATH=${PATH}:kat
+</pre>
+        <p>
+          Na powyższych przykładach użyłem znaku dolara wraz z nawiasami
+          klamrowymi. Jest to sposób na separacje nazwy zmiennej od innych
+          znaków, po to aby powłoka nie potraktowała jak w przykładzie powyżej
+          ciągu znaków ":kat" jak części nazwy zmiennej. Przedstawione w
+          przykładach polecenia są nie groźne, jeśli uszkodzimy zawartość
+          zmiennej <em>PATH</em>, to należy zamknąć okno terminala i otworzyć
+          nowe. 
+        </p>
+        <h2 id="2.10.specialchars">2.10. Znaki specjalne</h2>
+        <p>
+          W systemach uniksopodbnych wiele znaków ma szczególne znaczenie.
+          Poniżej znajduje się tabela przedstawiająca wykorzystwane podczas
+          używania systemu znaki specjalne.
+        </p>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Znak</th>
+              <th>Nazwa</th>
+              <th>Opis</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><strong>*</strong></td>
+              <td>gwiazdka</td>
+              <td>Wyrażenie regularne, znak nazwy wieloznacznej</td>
+            </tr>
+            <tr>
+              <td><strong>.</strong></td>
+              <td>kropka</td>
+              <td>Aktualny katalog, ogranicznik nazwy pliku lub hosta</td>
+            </tr>
+            <tr>
+              <td><strong>!</strong></td>
+              <td>wykrzyknik</td>
+              <td>Negacja, historia poleceń</td>
+            </tr>
+            <tr>
+              <td><strong>|</strong></td>
+              <td>potok</td>
+              <td>Potoki poleceń</td>
+            </tr>
+            <tr>
+              <td><strong>/</strong></td>
+              <td>slash</td>
+              <td>Ogranicznik katalogów, polecenie szukania</td>
+            </tr>
+            <tr>
+              <td><strong>\</strong></td>
+              <td>backslash</td>
+              <td>Literały, makra (nigdy katalogi)</td>
+            </tr>
+            <tr>
+              <td><strong>$</strong></td>
+              <td>dolar</td>
+              <td>Oznaczenie zmiennych, koniec wiersza</td>
+            </tr>
+            <tr>
+              <td><strong>'</strong></td>
+              <td>pojedynczy cudzysłów</td>
+              <td>Ciągi znaków literałów</td>
+            </tr>
+            <tr>
+              <td><strong>`</strong></td>
+              <td>lewy cudzysłów</td>
+              <td>Podmiana polecenia</td>
+            </tr>
+            <tr>
+              <td><strong>"</strong></td>
+              <td>podwójny cudzysłów</td>
+              <td>Ciągi znaków pseudoliterałów</td>
+            </tr>
+            <tr>
+              <td><strong>^</strong></td>
+              <td>daszek</td>
+              <td>Negacja, początek wiersza</td>
+            </tr>
+            <tr>
+              <td><strong>~</strong></td>
+              <td>tylda</td>
+              <td>Negacja, skrót katalogu</td>
+            </tr>
+            <tr>
+              <td><strong>#</strong></td>
+              <td>krzyżyk</td>
+              <td>Komentarze, dyrektywy preprocesora, podmiany</td>
+            </tr>
+            <tr>
+              <td><strong>[]</strong></td>
+              <td>nawiasy kwadratowe</td>
+              <td>Zakresy</td>
+            </tr>
+            <tr>
+              <td><strong>{}</strong></td>
+              <td>nawiasy klamrowe</td>
+              <td>Bloki poleceń, zakresy</td>
+            </tr>
+            <tr>
+              <td><strong>_</strong></td>
+              <td>podkreślenie</td>
+              <td>Prosty zamiennik spacji</td>
+            </tr>
+          </tbody>
+        </table>
+        <p>
+          Często możemy napotkać symbol daszka (<strong>^</strong>) zastępujący
+          klawisz <em>Control</em>, przez co zapis <em>^C</em> jest równe
+          kombinacji klawiszy <em>Ctrl+C</em>.
+        </p>
+        <h2 id="2.11.commandlineedit">2.11. Edycja wiersza poleceń</h2>
+        <p>
+          Znak zachęty wskazuje wiersz polecenia, który możemy edytować
+          przesuwając kursor za pomocą strzałek. Chcąc powtórzyć jakąś czynność
+          nie musimy pisać na nowo tego polecenia, możemy wybrać je z historii
+          poleceń za pomocą strzałek w góre i w dół. Warto jednak obsługę
+          wiersza poleceń za pomocą strzałek odstawić na bok. Wykorzystując
+          skróty z poniższej tabeli, możemy nimi śmiało zastąpić strzałki. 
+          Istnieją ku temu dwa powody. 
+        </p>
+        <ul>
+          <li>Nie wszystkie klawiatury posiadają strzałki, lub ich użycie jest
+            strasznie nie konfortowe.</li>
+          <li>Wiele programów uniksowych (w tym i linuksowych) obsługuje się
+            za pomocą tzw. biblioteki <strong>GNU Readline</strong> (skróty
+            klawiszowe w tabeli poniżej), a nie za pomocą strzałek.</li>
+        </ul>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Klawisze</th>
+              <th>Operacja</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+               <td><em>Ctrl+b</em></td>
+               <td>Przesunięcie kursora w lewo</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+f</em></td>
+              <td>Przesunięcie kursora w prawo</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+p</em></td>
+              <td>Powrót do poprzedniego polecenia (lub przesunięcie kursora
+                w górę)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+n</em></td>
+              <td>Przejście do następnego polecenia (lub przesunięcie klawisza
+                w dół)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+a</em></td>
+              <td>Przesunięcie kursora na początek wiersza</td> 
+            </tr>
+            <tr>
+              <td><em>Ctrl+e</em></td>
+              <td>Przesunięcie kursora na koniec wiesza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+w</em></td>
+              <td>Usunięcie słowa poprzedzjącego kursor</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+u</em></td>
+              <td>Usunięcie tekstu od kursora do początku wiersza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+k</em></td>
+              <td>Usunięcie tekstu od kursora do końca wiersza</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+Y</em></td>
+              <td>Wyklejanie usuniętego tekstu (na przykłda usuniętego
+                poleceniem <em>Ctrl+u</em>)</td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+h</em></td>
+              <td>Substytut klawisza <em>Backspace</em></td> 
+            </tr>
+            <tr>
+              <td><em>Ctrl+d</em></td>
+              <td>Substytut klawisza <em>delete</em></td>
+            </tr>
+            <tr>
+              <td><em>Ctrl+j, Ctrl+m</em></td>
+              <td>Substytut klawisza <em>enter</em></td>
+            </tr>
+          </tbody>
+        </table>
+        <h2 id="2.12.texteditors">2.12. Edytory tekstu</h2>
+        <p>
+          Na Linuksie mamy podobną ilość edytorów tekstowych do wyboru jak w
+          przypadku systemów MS Windows czy Apple macOS. Jak nie więcej.
+          Co ciekawe macOS, również jest system uniksopodobnym. Więc to co
+          zostało omówione w tym rozdziale również będzie kompatybilne z tym
+          systemem. Wracając jednak do edytorów tekstu. Tak naprawdę to
+          istnieją dwa, na które warto zwrócić uwagę, oba są standardem jeśli
+          chodzi o edycje tekstu i oba wymagają nauki obsługi. Wybór
+          pozostawiam do roztrzygniecia Tobie. 
+        </p>
+        <ul>
+          <li><strong>GNU Emacs</strong> - edytor w którym można zrobić
+            wszystko, od pisania tekstów do wykorzystania go jako menedżer
+            okien. Jego obsługa nie jest zbyt szybka i często by się
+            wydawało proste czynności wymagają użycia kliku poleceń. Wydaje
+            mi się, że nie ma bardziej rozbudowanego uniksowego programu.
+            Pomoc w obsłudze tego edytora, możemy uruchomić naciskając
+            <em>Ctrl+H</em> następnie klawisz <em>t</em>.</li>
+          <li><strong>VIm</strong> - szybki edytor uruchamiany w terminalu,
+            choć można zainstalować wersję graficzną. Obsługuje się go trochę 
+            jak grę. VIm, jest nieco bardziej intuicyjny od Emacsa. Warto
+            dodać, że edytor ten bywa domyślnie doinstalowywany do wielu
+            dystrybucji jak i innych systemów uniksowych, choć tam może
+            występować w podstawowej wersji <strong>Vi</strong>. Chcąc
+            nauczyć się edytora <em>Vim</em>, możemy skorzystać z
+            z instalowanego wraz z edytorem tutoriala, uruchamianego poleceniem
+            <strong>vimtutor</strong>.</li>
+        </ul>
+        <p>
+          Jeśli potrzebujemy edytora, który jest wstanie zatąpić nam
+          środowisko graficzne, wybierzmy edytor <em>Emacs</em>. Jeśli jednak 
+          chcemy
+          poprostu edytować pliki, w każdym możliwym środowisku wybierzmy
+          edytor <em>Vim</em>. Osobiście jestem przyzwyczajony już do edytora
+          <em>Vim</em>.
+        </p>
+        <h2 id="2.13.gettinghelp">2.13. Uzyskiwanie pomocy</h2>
+        <p>
+          Dystrybucje Linuksa są rozporowadzane z dużą ilością różnej
+          dokumentacji. Informacje temat poleceń możemy znaleźć na stronach
+          podręcznika, wydając polecenie <strong>man</strong> i podając jako
+          argument interesujące nas polecenie. Na przykład:
+        </p>
+<pre class="code-block">
+$ man ls
+</pre>
+        <p>
+          W ten sposób uruchomimy stronę podręcznika polecenia <em>ls</em>.
+          Większosć stron podręcznika podaje suche informacje na temat
+          polecenia, nie ma co tam szukać jakiś samouczków. Opcje podawana są
+          usystematyzowany sposób (najczęściej alfabetyczny), nie które
+          strony podręcznika mogą zawierać przykłady.
+        </p>
+        <p>
+          Strony podręcznika możemy przeszukać pod kątem słowa kluczowego, za
+          pomocą opcji <strong>-k</strong>, polecenia <em>man</em>. Wynikiem
+          tego polecenie jest lista poleceń, oraz krótki opis zawierający
+          podane słowo kluczowe, ciekawa jest liczba podana w nawiasie obok
+          nazwy polecenia, jest to <strong>numer rozdziału</strong>.
+        </p>
+        <p>
+          Strony podręcznika są podzielone rozdziały oznaczone numerami, każdy
+          z nich zawiera innego rodzaju strony podręcznika. Rozdziały
+          zostały opisane w tabeli poniżej. 
+        </p>
+        <table border="1">
+          <thead>
+            <tr>
+              <th>Rozdział</th>
+              <th>Opis</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><strong>1</strong></td>
+              <td>Polecenia użytkownika</td>
+            </tr>
+            <tr>
+              <td><strong>2</strong></td>
+              <td>Niskopoziomowe wywołania systemowe</td>
+            </tr>
+            <tr>
+              <td><strong>3</strong></td>
+              <td>Dokunentacja wysokopoziomowych bibliotek Uniksa</td>
+            </tr>
+            <tr>
+              <td><strong>4</strong></td>
+              <td>Informacje o interfejsach urządzeń i sterownikach</td>
+            </tr>
+            <tr>
+              <td><strong>5</strong></td>
+              <td>Opisy plików (konfiguracji systemu)</td>
+            </tr>
+            <tr>
+              <td><strong>6</strong></td>
+              <td>Gry</td>
+            </tr>
+            <tr>
+              <td><strong>7</strong></td>
+              <td>Formaty plików, konwencje i kodowaniaa (ASCII, przyrostki itd)</td>
+            </tr>
+            <tr>
+              <td><strong>8</strong></td>
+              <td>Polecenia systemowe i serwery</td>
+            </tr>
+          </tbody>
+        </table>
+        <p>
+          Jak uzupełnienie tego materiału świetnie sprawdzą się rodziały
+          1,5,7 i 8. Wywołanie konkretnej strony a danego rozdziału wymaga
+          podania jego numeru jak pierwszego argumentu, wówczas polecenie
+          będzie wszukać informacji na temat podanego słowa w danym rodziale.
+          Świetnym przykładem może być, chęć sprawdzenia na stronach
+          podręcznika pliku <em>/etc/passwd</em>. Należy wydać polecenie:
+        </p>
+<pre class="code-block">
+$ man 5 passwd
+</pre>
+        <p>
+          Dość często wykorzystywanym sposóbem na uzyskanie informacji o
+          poleceniach mogą być same polecenia, sprawdźmy czy możemy je
+          uruchomić z opcją <strong>-h</strong> lub <strong>--help</strong>.
+        </p>
+        <p>
+          Projekt GNU jakiś czas temu zadecydował, że będzie używać innego
+          formatu plików pomocy niż strony podręcznika, format nazywana jest
+          <strong>info</strong> lub <strong>texinfo</strong>. Format ten
+          zawiera więcej informacji choć jest od niego bardziej skomplikowany.
+          Przypomina prostą stronę internetowa, otworzoną w terminalowej
+          przeglądarce. Tego typu pliki pomocy uruchamiane są za pomocą
+          polecenia <strong>info</strong>, po czym podaje mu się jako argument
+          interesujące nas polecenie. 
+        </p>
+        <p>
+          Nie które z pakietów umieszczają swoją dokumentację w katalogu
+          <em>/usr/share/doc</em> nie zwracając uwagi na format. Warto
+          pamiętać o tych miejscach szukając pomocy, oczywiście pozostaje na
+          do dyspozycji jeszcze internet.
+        </p>
+        <h2 id="2.14.shellio">2.14. Wejście i wyjście powłoki</h2>
+        <p>
+          Omawiając po krótce powłokę, wspomniałem o strumieniach standardowego
+          wejścia i wyjścia. Wiele poleceń używa wyjścia aby wypisywać
+          wyniki działa lub komunikaty diagonstyczne. Jeśli nie chcemy ich
+          widzieć lub nie nadąrzymy ich analizować możemy je przekierować
+          na przykład do pliku, za pomocą znaku przekierowania (<strong>&gt;</strong>).
+        </p>
+        <p>
+          Używając tego znaku musimy omówić sobie jedną ważną rzecz, znak ten
+          powoduje nadpisanie wszystkiego co znajduje się w pliku. Tego typu
+          czynność nazywana jest <strong>wymazywaniem</strong>
+          (ang. <em>clobbering</em>). Możemy jednak zablokwać to działanie
+          za pomocą odpowiednich ustawień powłoki, dla BASH wystarczy użyć
+          polecenia <code class="code-inline">set -C</code>. Poza blokowaniem
+          wymazywania, istnieje jeszcze jeden znak przekierowania, który
+          powoduje dopisanie przekierowanego wyjścia do pliku:
+          <strong>&gt;&gt;</strong>.
+        </p>
+        <p>
+          Za pomocą przekierowań możemy w prosty sposób połączyć wyjście
+          jednego polecenia z wejściem innego. Służy temu znak <strong>potoku</strong>
+          (<strong>|</strong>). Postawienie ponowej kreski, pomiędzy
+          poleceniami w wierszu polecenia połączy wyjście pierwszego z wejściem
+          drugiego.
+        </p>
+        <h3 id="2.14.1.stderr">2.14.1 Standardowy strumień błędów</h3>
+        <p>
+          Korzystając powyższych znaków przekierowania polecenia, dane
+          wyjściowe programów zostaną przekierowane np. do pliku. Ale
+          komunikaty diagnostyczne nadal są wyświetlane. Dzieje się to dlatego
+          iż komunikaty diagnostyczny wykorzystują trzeci dodatkowy strumień
+          <strong>standardowy strumień błędów</strong> zapisywany skrótowo
+          <strong>stderr</strong>, który podobnie do <em>stdout</em> jest
+          podłączony do terminala.
+        </p>
+        <p>
+          Do przekierowania tego strumienia musimy użyć identyfikatorów
+          strumienii jest to liczba, którą posługuje się jądro do rozrózniania
+          strumieni. W fachowej
+          literaturze bądź dokumentacji możemy natknąć się na termin
+          <strong>deskryptor pliku</strong>. Taki identyfikator dla <em>stderr</em>
+          ma wartość <strong>2</strong>, a dla <em>stdout</em> <strong>1</strong>.
+          Chcąc przekierować <em>stderr</em> do innego pliku musimy podać jego
+          identyfikator przed znakiem przekierowania. Innym przypadkiem jest
+          przekierowanie <em>stderr</em> do tego samego pliku co <em>stdout</em>,
+          wówczas najprostszym sposób jest podłączenie strumienia błedów do
+          standardowego wyjścia za pomocą znaku <strong>&gt;&amp;</strong>
+          podając przekierowywany strumień po lewej stronie znaku (przed nim)
+          a strumień docelowy po prawej (za nim).
+        </p>
+<pre class="code-block">
+$ ls /ffffffff &gt;p 2&gt;&amp;1
+</pre>
+        <h3 id="2.14.2.stdin">2.14.2. Przekierowanie standardowego wejścia</h3>
+        <p>
+          Przekierowanie standardowego wejścia występuję dość rzadko ponieważ
+          większość poleceń przyjmuje plik jako argument, jednak może zdarzyć
+          się potrzeba przekierowania wejścia do polecenia. Służy temu
+          <strong>znak przekierowania wejścia</strong> <strong>&lt;</strong>.
+        </p>
+        <h2 id="2.15.readingerrors">2.15. Odczytywanie komunikatów o błędach</h2>
+        <p>
+          Prędzej czy później gdzieś podczas naszej pracy z powłoką zdarzy
+          się błąd. Ważne jest aby umieć go odczytać i prawidłowo z
+          interpretować.
+        </p>
+        <p>
+          Sam komunikat składa się przeważnie z nazwy polecenia oraz
+          komunikatu błędu, w nie których przypadkach w komunikacie
+          znajduje się nazwa pliku, jednak dotyczy specyficznych komunikatów
+          o błędach. Poniżej znajduje się
+          lista, błędów z którym będziemy się spotykać podczas pracy z systemem 
+          Linux. 
+        </p>
+        <ul>
+          <li><strong>No such file or directory</strong>
+            (<em>nie ma takiego pliku lub katalogu</em>) - występuje gdy
+            plik lub katalog podany jak argument nie istnieje. Innym powodem
+            występowania takiego błędu może być błędnie zapisana nazwa
+            polecenia w skrypcie.</li>
+          <li><strong>File exists</strong> (<em>plik istnieje</em>) - ten
+            problem występuje w momencie gdy próbujemy stworzyć katalog o
+            nazwie pliku, który już istnieje.</li>
+          <li><strong>Not a directory</strong> (<em>nie jest katalogiem</em>),
+            <strong>Is a directory</strong> (<em>jest katalogiem</em>) - błąd
+            występuje w momencie gdy probujemy użycie pliku jak katalogu lub
+            katalogu jak pliku.</li>
+          <li><strong>No space left on device</strong> (<em>brak miejsca w 
+            urządzeniu</em>) - Na pamięci masowej, której próbujemy zapisać
+            dane brakuje wolnego miejsca.</li>
+          <li><strong>Permission denied</strong> 
+            (<em>niewystarczające uprawnienia</em>) - pojawienie się tego błędu
+            może mieć dwa powody, pierwszy to zapis lub odczyt informacji z
+            pliku, do którego nie mamy żadnych uprawnień; drugim jest próba
+            uruchomienia pliku/programu bez ustawionego bitu wykonania. O
+            uprawnieniach będzie w dalszej części tego rodziału.</li>
+          <li><strong>Operation not permitted</strong> (<em>brak zezwolenia
+            na wykonanie operacji</em>) - błąd występuje w momencie gdy
+            spróbujemy zakończyć proces nie należący do nas.</li>
+          <li><strong>Segmentation fault</strong> (<em>błąd segmentacji</em>) - 
+            błąd programisty. Program, który uruchomiliśmy próbował
+            użyskać dostęp do wycinka pamięci, którego nie miał żadnych
+            uprawnień i jego działanie zostało przerwane przez jądro. 
+            Najczęsciej polskie tłumaczenie tego błędu to
+            <em>Naruszenie ochrony pamięci</em>.</li>
+          <li><strong>Bus Error</strong></li>  (<em>błąd magistrali</em>) błąd
+            podobny do <em>Naruszenia ochrony pamięci</em>, jednak w tym
+            przypadku chodzi o dostęp do pamięci w sposób niewłaściwy, a nie
+            dostęp do innego obszaru pamięci.</li>
+        </ul>
+        <p>
+          Jeśli natrafimy na jeden z dwóch ostatnich błędów, to przyczyną mogą
+          być dane przekazane do programu, których on się nie spodziewał.
+        </p>
+        <h2 id="2.16.manipulatingprocesses">2.16. Przeglądanie procesów i
+          manipulowanie nimi</h2>
+        <p>
+          Każdy proces jest programem. Jądro pododobnie jak użytkowników 
+          procesy widzi za pomocą liczbowych identyfikator - 
+          <strong>process ID</strong> - <strong>PID</strong>. Za pomocą
+          polecenia <strong>ps</strong> możemy wylistować wszystkie procesy
+          uruchomione w powłoce. Domyślnie wynik polecenia podzielony jest na
+          cztery kolumny.
+        </p>
+        <ul>
+          <li><strong>PID</strong> - identyfikator procesu</li>
+          <li><strong>TTY</strong> - urządzenie terminala, na którym działa
+            dany proces.</li>
+          <li><strong>STAT</strong> - stan procesu, np. <strong>S</strong>
+            oznacza uśpieje procesu, zaś <strong>R</strong> - jego dzialanie.
+            Wszystkie oznaczenia znajdują się na stronie podręcznika 
+            polecenia.</li>
+          <li><strong>CMD</strong> - treść polecenia, warto jednak zaznaczyć,
+            że procesy mogą ją zmieniać.</li>
+             
+        </ul>
+        <p>
+          Polecenie <em>ps</em>, możemy obsługiwać za pomocą opcji zapisanych w
+          trzech stylach, jednak najbardziej powszechnym jest styl BSD, i to
+          zapis opcji w tym stylu przedstawie.
+        </p>
+        <ul>
+          <li><strong>ps x</strong> - wyświetla wszystkie procesy uruchomione
+            przez aktualnego użytkownika.</li>
+          <li><strong>ps ax</strong> - wyświetla wszystkie procesy działące
+            w systemie.</li>
+          <li><strong>ps u</strong> - wyświetla bardziej szczegółowe informacje
+            o procesach.</li>
+          <li><strong>ps w</strong> - podaje pełne nazwy poleceń, nie
+            ograniczając się do pojedyńczego wiersza.</li>
+        </ul>
+        <p>
+          Tak jak w przypadku innych poleceń, w poleceniu <em>ps</em>, również
+          możemy łączyć opcje, dla przykładu chcąc wyświetlić wszystkie
+          procesy w systemie wraz ze szczegółami należy wydać polecenie
+          <code class="code-inline">ps aux</code>.
+        </p>
+        <p>
+          Wyświetlenie informacji na temat, konkertnych procesów polega na
+          podaniu po opcjach identyfikatora procesu. 
+        </p>
+        <h3 id="2.16.1.processkilling">2.16.1. Przerywanie działania procesów</h3>
+        <p>
+          Możemy zakończyć działanie procesu poprzez wysłanie do niego
+          <strong>sygnału</strong> za pomocą polecenia <strong>kill</strong>.
+          Wykorzystują to polecenie, jądro systemu proszone jest wysłanie 
+          sygnału do wybranego procesu. Domyślnie wysyłanym sygnałem jest 
+          <strong>TERM</strong>, a polecenie do swojego działania potrzebuje
+          tylko identyfikatora <em>PID</em>. 
+        </p>
+        <p>
+          Proces możemy zatrzymać wysyłając do niego sygnał <strong>STOP</strong>.
+          po nazwie sygnału podajemy <em>PID</em>, tak zatrzymany proces da się
+          wznowić za pomocą sygnału <strong>CONT</strong>. Nazwy sygnałów
+          podajemy po myślniku (<strong>-</strong>).
+        </p>
+        <p>
+          Naciśnięcie kombinacji <em>Ctrl+c</em> podczas działania programu w
+          powłoce, jest równoznaczne z wysłaniem sygnału <strong>INT</strong>
+          (ang. <em>Interrupt</em> - przerwanie).
+        </p>
+        <p>
+          Jedną z metod zakończenia procesu jest natychmiastowe zakończenie
+          jego pracy oraz usunięcie go siłą z pamięci, jest to osiągalne
+          poprzez wysłanie do niego sygnału <strong>KILL</strong>. Jest to
+          ostateczność, gdy dany proces nie odpowiada na inne sygnały. Inne
+          sygnały dają procesom możliwość poprzątania po sobie.
+        </p>
+        <p>
+          Oczywiście nie należy przerywać pracy dowolnym procesom, kiedy nie
+          wiemy co robią.
+        </p>
+        <h3 id="2.16.2.jobcontol">2.16.2. Kontrola zadań</h3>
+        <p>
+          Powłoki posiadają mechanizm dzięki, któremu możemy zatrzymywać oraz
+          wznawiać prace procesów za pomocą kombinacji <em>Ctrl+z</em> oraz
+          poleceniami <strong>fg</strong>, <strong>bg</strong>. Ten mechanizm
+          nazywa się <strong>kontolą zadań</strong>. Podczas działania procesu
+          w powłoce, możemy wysłać sygnał <strong>TSTP</strong> (podobny do
+          sygnału STOP), a następnie kiedy zechcemy do niego wrócić to
+          wystarczy wydać polecenie <em>fg</em>, które wznowi działanie
+          polecenia w terminalu, lub polecenia <em>bg</em> wznawiającego
+          działanie procesu w tle.
+        </p>
+        <p>
+          Podobne działanie ma program <em>GNU Screen</em>, który jest
+          multiplekserem terminala, a co najlepsze jesteśmy wstanie odłączyć
+          sesję programu od pierwszego planu i pozostanie ona w
+          niezmienionej postaci, tak długo jak włączony jest komputer.
+        </p>
+        <h3 id="2.16.3.processinbg">2.16.3. Procesy działające w tle</h3>
+        <p>
+          Uruchamiając polecenie w powłoce dostęp do znaku zachęty, a co za tym
+          idzie wolnego wiersza polecenia otrzymujemy dopiero po zakończeniu
+          działania programu. Jednak możemy odłożyć wykonanie polecenia do tła,
+          poczym od razu uzyskamy dostęp znaku zachęty. Jest to przydatna
+          funkcją, gdy uruchamiamy polecenie, którego wykonanie może
+          zająć trochę czasu. Wykonanie odkładamy do tła dopisując
+          ampersand (<strong>&amp;</strong>) na końcu polecenia (jako ostatni
+          argument). Działanie takiego programu
+          może trwać nawet po naszym wylogowaniu. Jeśli proces zakończy
+          działanie zostaniemy o tym poinformowani.
+        </p>
+        <p>
+          Problem związanym z procesami działającymi w tle jest, możliwe
+          pobieranie informacji z standardowego wejścia. Jeśli nie
+          przewidzieliśmy takiego zachowania programu, to wówczas może zostać
+          on zatrzymany lub zakończony. Można go wznowić za pomocą polecenia
+          <em>fg</em> o ile został zatrzymany. Innym problemem jest wypisywanie
+          danych przez proces w tle na standardowe wyjście oraz strumień błędów.
+          Przed uruchomieniem takiego polecenia należy przekierować te
+          strumienie, ponieważ podczas pracy w terminalu z innymi aplikacjami
+          dane ze strumieni mogą zaburzać ich wyświetlanie. Jeśli powłoka 
+          będzie dziwnie się zachowywać, wystarczy wydać polecenie 
+          <strong>reset</strong> i wszystko wróci do normy.
+        </p>
+        <h2 id="2.17.filemodandpermissions">2.17. Tryb pliku i uprawnienia</h2>
+        <p>
+          Każdy plik na Uniksie (więc na Linuksie też), posiada komplet
+          <strong>uprawnień</strong> określajacy czy można go odczytać, 
+          zapisać do niego lub go
+          uruchomić. Pierwsza kolumna wyniku polecenia <code class="code-inline">ls -l</code>
+          zawiera tryb pliku. Dane trybu możemy podzielić na cztery części
+          <strong>Typ</strong>, <strong>Uprawnienia użytkownika (właściciela)</strong>,
+          <strong>Uprawnienia grupy</strong>, <strong>Uprawnienia pozostałych
+          użytkowników.</strong>.
+        </p>
+        <p>
+          Pierwszy znak to typ pliku, jesli występuję w nim myślnik (<strong>-</strong>),
+          to mamy doczynienia ze zwykłym plikiem, innym typem pliku może być
+          litera <strong>d</strong> oznaczająca katalog.
+        </p>
+        <p>
+          Pozostałe znaki, definiują uprawnienia. Dzieli się je na trzy grupy
+          wypisane powyżej, po trzy znaki na każdą z nich. W grupie (zestawie
+          uprawnień, przeznaczonym dla konkretnej grupy lub osoby) mogą
+          wystąpić 4 rodzaje znaków.
+        </p>
+        <ul>
+          <li><strong>r</strong> - oznacza, że plik można czytać.</li>
+          <li><strong>w</strong> - oznacza, że do pliku można pisać.</li>
+          <li><strong>x</strong> - oznacza, że plik można uruchomić.</li>
+          <li><strong>-</strong> - oznacza, brak uprawnienia.</li>
+        </ul>
+        <p>
+          Mówiąc o użytkowniku w pierwszym rodziale, wspomniałem że może być
+          on właścicielem pliku i do niego należy pierwszy zestaw uprawnień.
+          Drugi zestaw określa uprawnienia dla grupy, jaka została przypisana
+          temu plikowi, z tych uprawnień będzie korzystać każdy użytkownik tej
+          grupy, próbujący uzyskać dostęp do pliku. Trzeci grupa, należy do
+          pozostałych użytkowników systemu. Użytkownika <em>root</em> nie
+          obejmują żadne z powyższych grup, choć to może zależć od konfiguracji
+          systemu, mimo to superużytkownik może sobie zmieniać dowolnie
+          uprawnienia.
+        </p>
+        <p>
+          Nie wymieniony na powyższej liście dodatkowym bitem (o uprawnieniach
+          możemy mówić jak o bitach, np. "potrzebuje bitu odczytu aby odczytać
+          dane z pliku") jest bit <strong>s</strong> - wybierz identyfikator
+          użytkownika. Pojawia się on zamiast bitu wykonywania <em>x</em> i
+          tyczy się wyłącznie plików wykonywalnych. Programy z ustawionym tym
+          bitem zawsze uruchamiają się z uprawnieniami ich właściciela bez
+          znaczenia, kto uruchamia ten program. Wiele programów korzysta z tego
+          rozwiązania, aby uzyskać uprawnienia superużytkownika i móc zapisywać
+          dane w różnych plikach systemowych.
+        </p>
+        <h3 id="2.17.1.modifypermissions">2.17.1. Modyfikacja uprawnień</h3>
+        <p>
+          Do zamiany uprawnień wykorzystamy polecenie <strong>chmod</strong>,
+          jako pierwszy podaje się zbiór uprawnień, a następnie bit uprawnienia
+          ze znakiem "+" jeśli chcemy dodać ten bit lub "-" jeśli chcemy ten 
+          bit
+          usunąć. Zbiór uprawnień podajemy za pomocą pierwszych liter 
+          angielskich
+          nazw <strong>u</strong> (ang. <em>user</em>)- użytkownika/właściciel,
+          <strong>g</strong> (ang. <em>group</em>) - grupa, 
+          <strong>o</strong> (ang. <em>others</em>)- pozostali użytkownicy 
+          systemu.
+        </p>
+<pre class="code-block">
+$ chmod go+r test.sh
+</pre>
+        <p>
+          Zbiory uprawnień można łączyć ze sobą, tak jak na powyższym
+          przykładzie lub jeśli chcemy dodać bit do wszystkich zbiorów to
+          możemy je pominąć jak na poniższym przykładzie.
+        </p>
+<pre class="code-block">
+-rw-r--r-- 1 xf0r3m xf0r3m 26 03-08 13:13 test.sh
+$ chmod +x test.sh
+-rwxr-xr-x 1 xf0r3m xf0r3m 26 03-08 13:13 test.sh
+</pre>
+        <p>
+          Przy plikach osobistych, nie warto dawać za dużych oprawnień
+          pozostałym użytkownikom. Chociaż obecnie może mieć to jedynie
+          znaczenie, gdy z serwera korzysta wielu wyspecjalizowanych 
+          użytkowników.
+        </p>
+        <p>
+          Innym sposobem na zmianę uprawnień jest użycie liczb, gdzie każda
+          z trzech liczb określa uprawnienia dla jednego zbioru. Liczby te są
+          sumami bitów, które reprezentowane są przez poszczególne wartości.
+        </p>
+        <ul>
+          <li><em>r</em> - <strong>4</strong></li>
+          <li><em>w</em> - <strong>2</strong></li>
+          <li><em>x</em> - <strong>1</strong></li>
+          <li><em>-</em> - <strong>0</strong></li>
+        </ul>
+<pre class="code-block">
+$ chmod 644 test.sh 
+</pre>
+        <p>
+          Uprawnienia właściciela mają wartość <code class="code-inline">6</code>.
+          co jest równe <em>4+2</em> - <em>u+rw</em>, grupa oraz pozostali mają
+          <code class="code-inline">4</code> co jest identyczne z zapisem
+          <em>go+r</em>. Liczby wykorzysywane tutaj pochodzą z oktalnego 
+          systemu liczbowego. 
+        </p>
+        <p>
+          Zmiana uprawnień nosi nazwę <strong>bezwzględnej</strong>, ponieważ
+          zmieniane są uprawnienia wszystkich grup.
+        </p>
+        <p>
+          Odnośnie uprawnień to istnieje bardzo ważna zależność pomiędzy bitami
+          odczytu oraz wykonania. Nadając katalogowi domowemu uprawnienia
+          <em>rwxr--r--</em> czy <em>744</em>. Pozostali użytkownicy będą
+          mogli odczytać zawartości katalog, ale nie uzyskają dostępu do pliku
+          podając go w jakimś poleceniu na ścieżce, do tego potrzebny jest 
+          jeszcze bit wykonania. 
+        </p>
+        <p>
+          Za pomocą polecenia <strong>umask</strong>, możemy zdefiniować
+          domyślne uprawnienia dla plików. Polecenie to przyjmuje jako 
+          argument te uprawnienia w postaci bezwględnej, które mają zostać
+          usunięte z nowoutworzonych plików i katalogów. Wydanie polecenia
+          umask:
+        </p>
+<pre class="code-block">
+$ umask 022
+</pre>
+        <p>
+          Spowoduje, że nowoutworzone pliki i katalogi będą mięc uprawnienia
+          w postaci <em>rwxr-xr-x</em> lub <em>755</em>. Może wydawać się zbyt
+          liberalne, więc możemy ustawić argument polecenia nas <em>077</em>, 
+          wówczas
+          wszystkie utworzone pliki i katalogi będą wyłącznie dla nas. 
+          Polecenie
+          <em>umask</em>, czesto występuje w plikach konfiguracyjnych powłoki.
+        </p>
+        <h3 id="2.17.2.symlinks">2.17.2. Dowiązania symboliczne</h3>
+        <p>
+          Dowiązanie syboliczne to jest alias będący plikiem wskazującym na
+          inny pliki lub katalog. Można uciec się do jednego słowa, że
+          dowiązanie symboliczne jest poprostu skrótem.
+        </p>
+        <p>
+          Jeśli dowiązanie wskazuje na katalog, to przejście do dowiązania
+          przeniesie nas w miejsce, na które wskazuje. Cel dowiązania nie
+          musi nawet istnieć, jeśli jednak spróbuje przejść pod takie
+          dowiązanie wówczas uzyskamy typowy błąd, o tym że katalog nie
+          istnieje. Dowiązania uniemożliwają również sprawdzenie 
+          charakterystyki
+          wskazywanego elementu, nie będzie wiadomo czy jest to plik, katalog
+          czy inne dowiązanie. Wiele połączonych ze sobą dowiązań symbolicznych
+          nazywane jest <strong>łańcuchem dowiązań</strong>
+        </p>
+        <p>
+          Dowiązania symboliczne tworzone są za pomocą polecenia <strong>ln</strong>
+          z opcją <strong>-s</strong> (<strong>Ważne, aby użyć tej opcji</strong>).
+          Argumentami jest na początku <strong>cel</strong> a poźniej nazwa
+          dowiązania. Zachowanie kolejności argumentów jest ważne, ponieważ
+          możemy utworzyć dowiązanie, które prowadzi do nikąd i wprowadza
+          bałagan (być może w plikach systemowych).
+        </p>
+        <p>
+          Mimo swoich wad dowiązanią są wygodną metodą na współdzielenie plików
+          oraz dodatkowo rozwiązują kilka drobnych problemów.
+        </p>
+        <h2 id="2.18.archivesandcompression">2.18. Archiwizowanie i
+        kompresowanie danych</h2>
+        <p>
+          Przesyłając duża ilość małych plików przez sieć czy tez na pamięć
+          masową, możemy odczuć że trwa to wieki, na pewno trwa to dłużej niż
+          przesłanie jednego dużego pliku. Tutaj przedstawię sposoby na
+          stworzenie
+          jednego większego pliku z całego katalogu, przy czym użyjemy jeszcze
+          kilku algorytmów kompresii, przez co zaoszczędzimy na czasie i trochę
+          na zajmowanym miejscu. 
+        </p>
+        <h3 id="2.18.1.tarprogram">2.18.1. Program tar</h3>
+        <p>
+          Pierwsze narzędzie będzie służyć do tworzenia archiwum. Archiwa
+          łączą pliki i katalogi w jeden plik. <strong>Tar</strong> jest 
+          standardowym program do archiwizacji na uniksach. 
+          Tworzenie archwium za pomocą <em>tar</em> wymaga kilku
+          opcji. Natomiast składania polecenia jest następująca:
+        </p>
+<pre class="code-block">
+$ tar -cvf archiwum.tar plik1 plik2...
+</pre>
+        <p>
+          Opcja <code class="code-inline">-c</code> mówi programowi, że
+          tworzone będzie nowe archiwum, opcja <code class="code-inline">-v</code>
+          włącza komunikaty diagnostyczne wyświetlać one będą po kolei pakowane
+          do archiwum pliki; opcja <code class="code-inline">-f</code>
+          przekazuje programowi informacje o tym, że archwium będzie plikiem.
+          Domyślnie <em>tar</em> tworzył archiwa na taśmach. Obecnie pominięcie
+          tej opcji kończy pracę programu z komunikatem o błędzie. Możemy 
+          natomiast użyć <em>stdout</em> podajac zamiast nazwy archiwum
+          myślnik (<strong>-</strong>). Póki co to archiwum nie jest jeszcze 
+          skompresowane.
+        </p>
+        <h4>Rozpakowywanie pliku</h4>
+        <p>
+          Rozpakowawanie różni się tylko jedną opcją - zamiast <em>-c</em> jest
+          <strong>-x</strong>. Następnie podajemy pozostałe opcje, a na końcu
+          nazwę pliku archiwum.
+        </p>
+        <h4>Wyświetlenie zawartości archiwum</h4>
+        <p>
+          Wypakowanie całego archiwum może nie być do końca porządane, załóżmy
+          że potrzebujemy tylko jednego pliki. Za pomocą polecenia <em>tar</em>
+          z odpowiednim przełącznikiem możemy wyświetlić listę plików w 
+          archiwum. Zamiast <em>-x</em>, używamy
+          <strong>-t</strong> reszta pozostaje taka sama, jeśli archiwum jest
+          duże to możemy podłączyć wyjście <em>tar</em> potokiem do polecenia
+          <em>less</em>. Samego wypakowania dokonujemy podając wypakowywanego
+          pliku za nazwą archiwum.
+        <p>
+        <p>
+          Ostanią dość istotną opcję jest <strong>-p</strong>, która powoduje
+          zachowanie oryginalnych atrybutów plików, jakie miały podczas
+          pakowania. Kiedy superużytkownika używa <em>tar</em>, ta opcja jest
+          domyślnie włączona.
+        </p>
+        <h3 id="2.18.2.gzipprogram">2.18.2. Program gzip</h3>
+        <p>
+          Program <strong>gzip</strong> (<em>GNU zip</em>) jest standardowym 
+          narzędziem kompresującym w systemach uniksowych. Pliki skompresowane
+          za jego pomocą otrzymują rozszerzenie <strong>.gz</strong>.
+          Dekompresuje się je za pomocą polecenia <strong>gunzip</strong>, jako
+          argument podaje się nazwę pliku. Natomiast kompresji dokonuje za
+          pomocą polecenia <strong>gzip</strong>, podając plik do 
+          skompresowania jako argument. 
+        </p>
+        <h3 id="2.18.3.compressedarchives">2.18.3. Skompresowane archiwa
+          <em>tar.gz</em></h3>
+        <p>
+          Obsługę skompresowanych archwów przy użyciu <em>gzip</em>,
+          rozpoczniemy od rozpakowania takiego archiwum. Nie ma sensu używania
+          do tego dwóch osobnych poleceń, jest to z resztą marnowanie zasobów.
+          Chcąc rozpakować skompresowane <em>gzip</em> archiwum, należy użyć
+          polecenia <em>tar</em> a po opcji
+          <em>-x</em> dodać, opcję <em>-z</em> następnie pozostałe czyli
+          <em>-vf</em> i na końcu podać nazwę archiwum. Tak jak na przykładzie: 
+        </p>
+<pre class="code-block">
+$ tar -xzvf archiwum.tar.gz
+</pre>
+        <p>
+          Przy tego typu archiwach, możemy spodziewać się rozszerzenia
+          <strong>.tgz</strong>. Są to te same archiwa, jak te mające 
+          rozszerzenie <em>tar.gz</em>.
+        </p>
+        <p>
+          Przy wyświetlaniu zawartości takiego archiwum, zamieniamy opcję
+          <strong>-x</strong> na <strong>-t</strong>. A chcąc takie archwiwum
+          utworzyć to opcję <strong>-x</strong> na opcję <strong>-c</strong>
+          oraz podać katalog lub listę plików, która ma zostać umieszczona w
+          archiwum po jego nazwie.
+        </p>
+        <h3 id="2.18.4.othercompression">2.18.4. Inne metody kompresji</h3>
+        <p>
+          Poza archiwami spakowanymi za pomocą <em>gzip</em>, możemy też
+          spotkać archiwa spakowane za pomocą <strong>bzip2</strong> oraz
+          <strong>xz</strong>. W przypadku <em>bzip2</em>, to programem
+          dekompresującym jest <strong>bunzip2</strong>, a opcją programu
+          <em>tar</em> jest <strong>-j</strong> (mała litera j). Jeśli
+          natrafimy na archiwum skompresowane <em>xz</em>, to programem
+          dekompresującym jest <strong>unxz</strong>, a opcją programu
+          <em>tar</em> jest <strong>-J</strong> (wielka litera j). 
+        </p>
+        <p>
+          Część dystrybucji wyposażona jest w program <em>unzip</em>
+          pozwalający na rozpakowanie plików <em>.zip</em> przygotowanych
+          pod systemem MS Windows, jak i samo rozpakowywujących się plików
+          <em>.exe</em>. 
+        </p>
+        <h2 id="2.19.filesystemhierarchy">2.19. Hierarchia katalogów</h2>
+        <p>
+          Struktura katalogów głównego, jest utworzona na
+          podstawie <strong>standardu hierarchii systemu plików</strong>,
+          określającego jakie podkatalogi ma zawierać katalog główny, oraz
+          co te podkatalogi mają przechowywać. Poniżej opisano na ten czas
+          najważniejsze z nich.
+        </p>
+        <ul>
+          <li><strong>/bin</strong> - przechowuje pliki binarne przygotowane
+            przez kompilator języka C, w nowocześniejszych systemach mogą to 
+            być
+            skrypty powłoki. W nim przechowywane są te najprostsze polecenia
+            jak <em>cp</em>.</li>
+          <li><strong>/dev</strong> - przechowuje pliku urządzeń.</li>
+          <li><strong>/etc</strong> - katalog zawierający najważniejsze pliki
+            konfiguracji systemu. Znajdują się tutaj pliki haseł, konfiguracji
+            uruchamiania systemu, urządzeń, sieci i innych elementów systemu.</li>
+          <li><strong>/home</strong> - zbiorczy katalog, katalogów domowych
+            użytkowników. Standard wśród wszystkich nowoczesnych uniksów.</li>
+          <li><strong>/lib</strong> - katalog przechowywujący biblioteki.
+            Te pliki przechowują kod, który może być wykorzystywany przez 
+            pliki wykonywalne. Biblioteki możemy podzielić na statyczne lub
+            współdzielone. Tylko biblioteki współdzielone powinny znajdować
+            się w tym katalogu, pozostałe pliki tego typu znajdują się
+            w katalogu <em>/usr/lib</em>.</li>
+          <li><strong>/proc</strong> - udostępnia statystyki o systemie w 
+            postaci interfejsu plików i katalogów.
+          </li>
+          <li><strong>/sys</strong> - ten katalog jest podobny do katalogu
+            <em>/proc</em>, z tym, że tworzy interfejs dla urządzeń oraz
+            systemu. Wiecej informacji na ten temat, znajduje się w następnym
+            rozdziale.
+          </li>
+          <li><strong>/sbin</strong> - w tym katalogu zapisane są systemowe
+            pliki wykonywalne. Programy znajdujące się w katalogach
+            <em>/sbin</em> przeznaczone są do zarządzania systemem, dlatego
+            ten katalog nie występuje na ścieżce zwykłego użytkownika a wiele
+            narzędzi będzie działać tylko z kontem <em>root</em>.
+          </li>
+          <li><strong>/tmp</strong> - w tym katalogu możemy umieszczać pliki
+            tymczasowe, którymi nikt się nie będzie przejmować. Każdy
+            użytkownik może zapisywać i odczytywać pliki z katalogu w tym
+            katalogu, ale nikt nie ma dostępu do plików zapisanych przez innych
+            użytkowników. Nie które programy wykorzystują, ten katalog jako
+            przestrzeń roboczą. Nie należy zapisywać ważnych danych do tego
+            katalogu, gdyż jego zawartość jest przez wiekszość dystrybucji 
+            czyszczona podczas uruchamiania systemu, inne mogą usuwać 
+            starsze pliki co jakiś czas.</li>
+          <li><strong>/usr</strong> - W tym katalogu znajdziemy rozbudowaną,
+            strukturę katalogów, bardzo podobną to katalogu głównego. W tym
+            katalogu zapisana jest większa części systemu Linux.</li>
+          <li><strong>/var</strong> - podkatalog zawierający "zmienne" dane
+            zapisywane przez programy w czasie swojego działania. Tutaj 
+            znajdują się m.in. pliki dzienników systemowych.</li>
+        </ul>
+        <h3 id="2.19.1.othermainsubdirs">2.19.1. Pozostałe katalogi główne</h3>
+        <ul>
+          <li><strong>/boot</strong> - przechowuje plik ładujące jądro systemu
+          w czasie uruchamiania komputera. W większości dystrybucji w tym
+          katalogu przechowywane są właściwe pliki jądra oraz początkowego
+          systemu plików w pamięci RAM. Początkowy system plików pamięci RAM
+          zostanie omówiony w dalszej materiału.</li>
+          <li><strong>/media</strong> - w wielu dystrybucjach jest to główny
+          punkt przyłączania wszystkich mediów wymiennych, takich jak
+          karty pamięci Flash.</li>
+          <li><strong>/opt</strong> - może przechowywać dodatkowe
+          oprogramowanie firm trzecich. W wielu systemach katalog <em>/opt</em>
+          nie jest wykorzystywany.</li>
+        </ul>
+        <h3 id="2.19.2.usrdirectory">2.19.2. Katalog /usr</h3>
+        <p>
+          To właśnie w katalogu <em>/usr</em> znajduje się większość programów
+          i danych przestrzeni użytkownika, a są one rozlokowane po jego
+          podkatalogach. Poniżej znajduje się opis co znajduje się w 
+          poszczególnych podkatalogach tego katalogu:
+        </p>
+        <ul>
+          <li><strong>bin</strong> - większość, jak nie wszystkie
+            ogólnodostępne programy w systemie.</li>
+          <li><strong>include</strong> - przechowuje pliki nagłówkowe
+            wykorzystywane przez kompilator języka C.</li>
+          <li><strong>info</strong> - zawierają strony dokumentacji
+            <em>GNU</em> info.</li>
+          <li><strong>local</strong> - miejsce gdzie administratorzy mogą
+            mogą instalować swoje oprogramowanie, katalog ten może zawierać
+            podobną identyczną strukturę, jak katalog <em>/usr</em> lub
+            katalog główny.</li>
+          <li><strong>man</strong> - przechowuje strony podręcznika
+            systemowego.</li>
+          <li><strong>share</strong> - kiedyś ten katalog był katalogiem
+            współdzielonym między komputerami, obecnie stracił na znaczeniu.
+            Mimo to dalej przechwouje informacje, przeważnie są to pliki ikon, 
+            pliki zawierające znaki
+            towarowe dystrybucji oraz inne dane z których może korzystać wiele
+            programów. Ten katalog może zawierać podkatalogi takie jak
+            <em>man</em> oraz <em>info</em>.</li>
+        </ul>
+        <h3 id="2.19.3.kernelplace">2.19.3. Umiejscowanie jądra w systemie</h3>
+        <p>
+          Wspomniałem już że plik jądra znajduje się w katalogu <em>/boot</em>,
+          plik ten rozpoczyna się od nazwy <strong>vmlinuz</strong>, po tych
+          znakach
+          mogą wystąpić inne inforamcje oznaczające jego wersje. Po załadowaniu
+          jądra przez program rozruchowy, sam plik przestaje być
+          potrzebny. W trakcie pracy systemu operacyjnego jądro wykorzystuje
+          najróżniejsze ładowane i usuwane dodatkowo modułu. <strong>Ładowane
+          moduły jądra</strong> umieszczane są w katalogu <em>/lib/modules</em>.
+        </p>
+        <h2 id="2.20runitasroot">2.20. Uruchamianie poleceń przez superużytkownika</h2>
+        <p>
+          Korzystając z linuksa na naszym osobistym komputerze, przyjdzie taki
+          moment że będziemy musieli skorzystać z konta użytkownika 
+          <em>root</em>. Aby to zrobić możemy przelogować się na jego konto
+          wykonać potrzebne czynności a następnie się wylogować. Ta czyność
+          przyniosła by zamierzony efekt ale nie jest bez wad. Dlatego też
+          możemy skorzystać z polecenia <strong>sudo</strong>, które
+          pozwoli, na uruchomienie polecenia podanego jako arugment 
+          z uprawnieniami
+          superużytkownika. Jeśli polecenie nie występuje w systemie, to jest
+          dobry czas aby przelogować się na użytkownika <em>root</em>, i je
+          zainstalować. Polecenie po zainstalowaniu nie zadziała samo w sobie
+          potrzebne jest jeszcze określenie, którzy użytkownicy mogą używać
+          tego polecenia i co za jego pomocą mogą zrobić. Za to odpowiada
+          pliki <strong>/etc/sudoers</strong>.
+        </p>
+        <h3 id="2.20.1.sudoersfile">2.20.1. Plik /etc/sudoers</h3>
+        <p>
+          Samo polecenie sudo ma bardzo duża ilość opcji, jednak na tym
+          etapie nie skorzystamy z większości z nich. Najprostszym sposobem
+          na konfiguracje pliku <em>/etc/sudoers</em> jest odnalezienie w pliku
+          linii rozpoczynającej się pod słowa <em>root</em> a następnie
+          pod tą linią wpisać linię rozpoczynjącą się nazwy użytkownika oraz
+          dopisaniu kilku opcji, tak jak na poniższym przykładzie.
+        </p>
+<pre class="code-block">
+user ALL=(ALL) ALL
+</pre>
+        <p>
+          Pierwsze <code class="code-inline">ALL</code>, oznaczna dowolny
+          komputer. Drugie
+          <code class="code-inline">(ALL)</code> w nawiasach oznacza, że możemy
+          wydać polecenie jako dowolny użytkownik, być może spotkamy się
+          z takim zapisem w nawiasie (<em>ALL:ALL</em>), oznacza ono dowolnego
+          użytkownika i dowolną grupę. Trzecie <code class="code-inline">ALL</code>
+          oznacza dowolne polecenie.
+        </p>
+        <p>
+          Jeśli drażnić nas będzie ciągłe wpisywanie haseł, to możemy przed
+          trzecim <em>ALL</em> w konfiguracji umieścić opcję 
+          <strong>NOPASSWD</strong>, pamiętając aby pomiędzy te opcje wstawić
+          dwukropek (<strong>:</strong>) bo tak naprawdę określamy jakie
+          polecenia mają być uruchamiane bez podawania hasła.
+        </p>
+        <h2 id="2.21.summary">2.21. Podsumowanie</h2>
+        <p>
+          Po przeczytaniu tego rodziały wydaje mi się, że każdy ma solidne
+          podstawy obsługi systemu Linux z poziomu powłoki. Powłoka jest
+          jednym ze stałych komponentów dystrybucji, a wiele z nich dalej
+          obstaje przy BASH-u, jako domyślnej powłoce.
+        </p>
+        <h1 id=3.devices">3. Urządzenia</h1>
+        <p>
+          Odkąd powstał system Linux, w sposobach prezentowania urządzeń
+          użytkownikowi zachodziło wiele zmian. Na początku tego rodziału
+          omówimy sobie tradycjny system <strong>sysfs</strong>. Aby potem
+          zająć się opisem systemu <strong>udev</strong>, pozwalającego 
+          program przestrzeni użytkownika automatycznie konfigurować oraz
+          używać nowych urządzeń. Poznamy zasady, zgodnie z którymi jądro
+          wysyła do procesów komunikaty przy użyciu systemu <em>udev</em>
+          oraz dowiemy się w jaki sposób one reagują na nie.
+        </p>
+        <h2 id="3.1.devicefiles">3.1. Pliki urządzeń</h2>
+        <p>
+          Jądro udostępnia wiele urządzeń pod postacią plików, co daje nam
+          możliwość prostej manipulacji nimi. Te pliki są często nazywane
+          <strong>węzłami urządzeń</strong>. Korzystać z urządzeń możemy
+          za pomocą zwykłych operacji na plikach. Tego typu rozwiązanie nie
+          jest bez wad dlatego też nie wszystkie urządzenia lub ich funkcje
+          są udostępnianie w ten sposób.
+        </p>
+        <p>
+          Pliki urządzeń są przechowywane w katalogu <strong>/dev</strong>.
+          A najprostszym sposobem interakcji z urządziem jest przekierowanie
+          wyniku jakiegoś polecenia do urządzenia <strong>/dev/null</strong>.
+          Urządzenie to jest miejscem na nie potrzebne nam dane ze strumieni,
+          ponieważ co kolwiek trafi do tego urządzenia, jest przez jądro
+          poprostu ignorowane.
+        </p>
+        <p>
+          Wyświetlając sobie zawartość katalogu w bardziej szczegółowej liście
+          może zauważyć dziwne oznaczenia w trybie pliku. Litery te określają
+          rodziaje urządzeń a wśród nich możemy wyszczególnić:
+        </p>
+        <ul>
+          <li><strong>Urządzenia blokowe - b</strong> - Procesy mogą odczytywać
+            dane z urządzeń blokowych przy użyciu bloków o stałej wielkości.
+            Pamięci masowe są przykładem urządzeń blokowych. Łatwo dzieli się 
+            je na bloki, a ogólna wielkość
+            takiego urządzenia jest stała i można ją zindeskować co daje
+            możliwość jądru na dostępu do dowolnego bloku danych.</li>
+          <li><strong>Urządzenia znakowe - c</strong> - Urządzenia znakowe
+            działają w oparciu o strumienie danych. Do takich urządzeń można
+            zapisywać i odczytywać pojedyńcze znaki. Jądro zazwyczaj wykonuje
+            operacje odczytu i zapisu na fizycznym urządzeniu. Drukarki są 
+            przykładami urządzeń znakowych. Warto wspomnieć, że jądro nie
+            jest w stanie ponownie odczytać danych ze strumienia po przekazaniu
+            ich dalej.</li>
+          <li><strong>Urządzenia potokowe - p </strong> - tzw.
+            <strong>nazwane potoki</strong> są to urządzenia podobne do
+            urządzeń znakowych z tą jednak różnicą, że na drugim końcu
+            strumienia wejścia-wyjścia nie znajduje się fizyczne urządzenia ale
+            inny proces.</li>
+          <li><strong>Urządzenia gniazdkowe - s</strong> - tzw. <strong>gniazda</strong>
+            są interfejsami specjalnego przeznaczenia i służa komunikacji
+            międzyprocesowej. Mogą występować poza katalogiem <em>/dev/</em>.</li>
+        </ul>
+        <p>
+          Inną dość rzucającą się w oczy informacją na listingu katalogu, są
+          dwie liczy odzielone przecinkiem zamiast rozmiaru pliku, jest
+          <strong>numer główny</strong> i <strong>numer poboczny</strong>.
+          Te numer ułatwiają jądru identyfikacje urządzeń. Dla przykładu
+          partycje tego samego dysku mają ten sam <em>numer główny</em> ale
+          inny <em>numer poboczny</em>.  
+        </p>
+        <p>
+          Nie wszystkie urządzenia mają swoje pliki, takim przykładem są
+          interfejsy sieciowe. Jądro wykorzystuje dla nich inny interfejs
+          wejścia-wyjścia.
+        </p>
+        <h2 id="3.2.sysfsdevicepath">3.2. Ścieżka urządzeń sysfs</h2>
+        <p>
+          Ze względu na uproszczoną interakcje z urządzeniami poprzez 
+          odwołowywanie się do pliku w katalogu <em>/dev/</em> oraz fakt, że
+          jądro systemu nadaje plikom z tego katalogu nazwy na podstawie
+          koleności wykrywania urządzenie pod czas uruchamiania systemu
+          Wewnątrz jądra zaimplementowano interfejs <strong>sysfs</strong>,
+          który jest ujednoliconym sposobem prezentacji urządzeń bazującym
+          na atrybutach sprzętowych, mający formę struktury katalogów i plików.
+          Główny katalogiem tego system jest katalog <strong>/sys/devices</strong>.
+          Przykładowa ścieżka dla pierwszego dysku SATA mającego swój plik
+          <em>/dev/sda</em> może wyglądać następująco:
+        </p>
+<pre class="code-block">
+/sys/devices/pci0000:00/0000:00:1f:2/host0/target0:0:0/0:0:0:0/block/sda
+</pre>
+        <p>
+          Warto tutaj zaznaczyć iż, scieżki systemu <em>sysfs</em> nie służą 
+          uzyskaniu dostępu do urządzeń, umożliwają przeglądanie informacji
+          oraz zarządzanie urządzeniami. Dane zawarte na plikach na ścieżkach
+          <em>sysfs</em> powinny być odczytywane przez programy nie przez
+          ludzi.
+        </p>
+        <p>
+          Chcąc sprawdzić scieżkę <em>sysfs</em> dla dowolnego urządzenia z
+          katalogu <em>/dev</em> należało by programu system <em>udev</em>
+          <strong>udevadm</strong>.
+        </p>
+<pre class="code-block">
+$ udevadm info --query=all --name=/dev/sda
+</pre>
+        <p>
+          Wykonując to polecenie dowiemy się przy okazji ile danych można 
+          uzyskać informacji z systemu <em>udev</em>.
+        </p> 
+        <h2 id="3.3.ddcommand">3.3. Polecenie dd</h2>
+        <p>
+          Polecenie jest dość prostym, aczkolwiek przydatnym narzędziem jeśli
+          choodzi o prace z urządzeniami znakowymi czy blokowymi. Jedyną
+          rzeczą, którą robi to polecenie jest odczyt danych z pliku 
+          wejściowego lub ze strumienia i zapisanie go do wyjściowego pliku
+          lub strumienia, przy okazji dokonując pewnych konwersji. Najczęsciej
+          używane przeze mnie polecenie znajduje się poniżej. 
+        </p>
+<pre class="code-block">
+$ sudo dd if=/dev/zero bs=1M of=/dev/sdX count=1
+</pre>
+        <p>
+          Polecenie wykorzystuje uprawnienia superużytkownika, aby uzyskać
+          dostęp do urządzenia blokowego. Samo polecenie zapisuje jeden
+          blok o wielkości 1M za pomocą zer z pliku <em>/dev/zero</em> 
+          (nieskończony strumień zer), co powoduje usunięcie tablicy partycji.
+        </p>
+        
+      </div>
+                       <p style="margin: 15px; padding: 0; outline: 0;">
+                               2022; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/konfiguracja_HAProxy_dla_HTTP_i_HTTPS.html b/articles/terminallog/konfiguracja_HAProxy_dla_HTTP_i_HTTPS.html
new file mode 100755 (executable)
index 0000000..804119e
--- /dev/null
@@ -0,0 +1,380 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       <style>
+                               .code-block {
+                                       text-align: left;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+                       </style>
+               </head>
+               <body>
+<pre>
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+                       <p class="header_link">
+                               &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+                       </p>
+                       <div class="main">
+                               <h1 class="title">Konfiguracja HAProxy dla HTTP 
+                                       oraz HTTPS</h1>
+                               <p>
+                               <strong>HAProxy</strong> jak podaje Wikipedia jest
+                               load-balancerem oraz serwerem proxy dla połączeń TCP oraz
+                               aplikacji HTTP. Dla mnie jest program, który zrobił robotę
+                               jeśli chodzi o hosting aplikacji internetowych na
+                               kontenerach. Bez <em>HAProxy</em>, aplikacje WWW na
+                               innych fizycznych serwerach musiały mieć odzielny publiczny
+                               adres IP. To się zmieniło, właśnie dzięki temu oprogramowaniu. Ten
+                               materiał pojawia się na "terminallog", bo jest o stricte
+                               jednym programie bez wskazania konkrenej platformy czy
+                               systemu operacyjnego.
+                               </p>
+                               <p>
+                               Ja <em>HAP-a</em> konfigurowałem na Ubuntu 18.04 oraz 20.04. 
+                               Jednak, tak jak już wspomniałem możemy sobie nawet go 
+                               skonfigurować na OpenBSD. Mój wybór wtedy padł na Ubuntu, gdyż
+                               dopiero co zaznajomiłem się technologią kontenerów LXD.
+                               </p>
+                               <p>
+                               Przejdźmy może już do konfiguracji. Ten materiał będzie
+                               składał się w bardzo dużej części z listingów plików konfiguracyjnych
+                               oraz ich opisów. Takie informacje na szybko, bez zbędnej
+                               teorii.
+                               </p>
+                               <p>
+                               Rozpoczniemy od proxy dla HTTP, poniżej znajduje się 
+                               konfiguracja dostarczana wraz z pakietem.
+                               </p>
+<pre class="code-block">
+global
+       log /dev/log    local0
+       log /dev/log    local1 notice
+       chroot /var/lib/haproxy
+       stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
+       stats timeout 30s
+       user haproxy
+       group haproxy
+       daemon
+
+       # Default SSL material locations
+       ca-base /etc/ssl/certs
+       crt-base /etc/ssl/private
+
+       # Default ciphers to use on SSL-enabled listening sockets.
+       # For more information, see ciphers(1SSL). This list is from:
+       #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
+       # An alternative list with additional directives can be obtained from
+       #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
+       ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:
+       ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
+       ssl-default-bind-options no-sslv3
+
+defaults
+       log     global
+       mode    http
+       option  httplog
+       option  dontlognull
+        timeout connect 5000
+        timeout client  50000
+        timeout server  50000
+       errorfile 400 /etc/haproxy/errors/400.http
+       errorfile 403 /etc/haproxy/errors/403.http
+       errorfile 408 /etc/haproxy/errors/408.http
+       errorfile 500 /etc/haproxy/errors/500.http
+       errorfile 502 /etc/haproxy/errors/502.http
+       errorfile 503 /etc/haproxy/errors/503.http
+       errorfile 504 /etc/haproxy/errors/504.http
+
+</pre>
+                       <p>
+                               <em>Wartość opcji <code class="code-inline">
+                               ssl-default-bind-ciphers</code> złamano tylko i wyłączenie
+                               dla celów estetycznych strony.</em>
+                       </p>
+                       <p>
+                       Kolejny listing przestawia już gotową konfigurację HTTP
+                       </p>
+<pre class="code-block">
+       global
+       log /dev/log    local0
+       log /dev/log    local1 notice
+       chroot /var/lib/haproxy
+       stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
+       stats timeout 30s
+       user haproxy
+       group haproxy
+       daemon
+
+       # Default SSL material locations
+       ca-base /etc/ssl/certs
+       crt-base /etc/ssl/private
+
+       # Default ciphers to use on SSL-enabled listening sockets.
+       # For more information, see ciphers(1SSL). This list is from:
+       #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
+       # An alternative list with additional directives can be obtained from
+       #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
+       ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:
+       ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
+       ssl-default-bind-options no-sslv3
+
+defaults
+       log     global
+       mode    http
+       option  httplog
+       option  dontlognull
+       option  forwardfor
+       option  http-server-close
+        timeout connect 5000
+        timeout client  50000
+        timeout server  50000
+       errorfile 400 /etc/haproxy/errors/400.http
+       errorfile 403 /etc/haproxy/errors/403.http
+       errorfile 408 /etc/haproxy/errors/408.http
+       errorfile 500 /etc/haproxy/errors/500.http
+       errorfile 502 /etc/haproxy/errors/502.http
+       errorfile 503 /etc/haproxy/errors/503.http
+       errorfile 504 /etc/haproxy/errors/504.http
+
+frontend www_front
+       bind *:80
+       acl host_stronya hdr(host) -i example.edu.pl www.example.edu.pl
+       
+       use_backend stronaa if host_stronya
+
+
+backend stronaa
+       http-request set-header X-Client-IP %[src]
+       server stronaa 192.168.56.2:80 check
+
+</pre>
+                       <p>
+                               <em>Wartość opcji <code class="code-inline">
+                               ssl-default-bind-ciphers</code> złamano tylko i wyłączenie
+                               dla celów estetycznych strony.</em>
+                       </p>
+                       <p>
+                       Więc, co się zmieniło względem konfiguracji bazowej? W konfiguracji domyślnej 
+                       <code class="code-inline">defaults</code> 
+                       zmieniono dwie opcje:
+                               <ul>
+                                       <li><code class="code-inline">option forwardfor</code> - 
+                                       dzięki, której włączono wstawianie nagłówka 
+                                       <em>X-Forwarded-For</em> do żądań wysyłanych do
+                                       serwera. Dzięki temu nagłówku do logów serwera trafi
+                                       prawdziwy adres IP klienta a nie adres <em>HAP-a</em>,</li>
+                                       <li><code class="code-inline">option http-server-close</code> - 
+                                       włącza zamykanie połączeń przez serwer. Użycie tej
+                                       opcji ma na celu zmniejszyć zużycie zasobów
+                                       serwera.</li>
+                               </ul>
+                       Dodano sekcję <code class="code-inline">frontend</code>.
+                       Zawiera ona opcje uruchomieniowe proxy takie jak port, na 
+                       którym <em>HAP</em> ma nasłuchiwać oraz reguły, według których należy
+                       traktować spływające do usługi dane. Na przykład do jakiego
+                       serwera przekierować żądanie na konkretny adres. W 
+                       przypadku proxy dla HTTP, wystarczą tylko poniższe opcje:
+                               <ul>
+                                       <li>
+                                               <code class="code-inline">
+                                               acl host_stronya hdr(host) -i example.edu.pl www.example.edu.pl
+                                               </code> - <em>ACL-ele</em> są warunkami, które
+                                               określają kryteria przekazywania danych przez proxy.
+                                               Te warunki użwane są np. przez polecenia wskazujące
+                                               na konkretny serwer. Sama reguła <em>ACL</em>
+                                               składa się w tym przypadku z:
+                                                       <ul>
+                                                               <li>Słowa kluczowego: 
+                                                               <code class="code-inline">acl</code>,
+                                                               </li>
+                                                               <li>nazwy:
+                                                               <code class="code-inline">host_stronya</code>,
+                                                               </li>
+                                                               <li>kryterium:
+                                                               <code class="code-inline">hdr(host)</code> - 
+                                                               To kryterium może być niezrozumiałe. W konteście
+                                                               <em>ACL</em> polega ono na przyrównaniu zawartości
+                                                               nagłówka <em>host</em> żądania z wartościami na końcu
+                                                               reguły,
+                                                               </li>
+                                                               <li>flagi:
+                                                               <code class="code-inline">-i</code> -
+                                                               brak czułości na wielkość znaków,
+                                                               </li>
+                                                               <li>wartości do przyrównania:
+                                                               <code class="code-inline">example.edu.pl www.example.edu.pl</code>
+                                                               </li>
+                                                       </ul>
+                                       </li>
+                                       <li>
+                                               <code class="code-inline">
+                                                       use_backend stronaa if host_stronya
+                                               </code> - polecenie wskazujące na serwer, którego
+                                                       deklaracja znajduje się w sekcji <code class="code-inline">
+                                                       backend</code> o nazwie <code class="code-inline">
+                                                       stronaa</code> na podstawie <em>ACL-ki</em>
+                                                       <code class="code-inline">host_stronya</code>.
+                                       </li>
+                               </ul>
+                       Jeśli chodzi o HTTP, to tak naprawdę tyle. Ta konfiguracja
+                       powinna bez trudu działać. 
+                       </p>
+                       <p>
+                       Konfigurację <em>HAProxy</em> możemy przetestować przed 
+                       uruchomieniem za pomocą poniższego polecenia:
+                       </p>
+<pre class="code-block">
+$ sudo haproxy -f &lt;ścieżka_do_pliku_konfiguracyjnego&gt; -c
+</pre>
+                       <p>
+                       Użycie <em>HAProxy</em> dla HTTPS, wydaje się być jeszcze
+                       prostsze. Poniżej znajduje się listing konfiguracji dla HTTPS
+                       jednak w tym przypadku jest <em>TCP/443</em>.
+                       </p>
+<pre class="code-block">
+global
+       log /dev/log    local0
+       log /dev/log    local1 notice
+       chroot /var/lib/haproxy
+       stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
+       stats timeout 30s
+       user haproxy
+       group haproxy
+       daemon
+
+       # Default SSL material locations
+       ca-base /etc/ssl/certs
+       crt-base /etc/ssl/private
+
+       # Default ciphers to use on SSL-enabled listening sockets.
+       # For more information, see ciphers(1SSL). This list is from:
+       #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
+       # An alternative list with additional directives can be obtained from
+       #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
+       ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:
+       ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
+       ssl-default-bind-options no-sslv3
+
+defaults
+       log     global
+       mode    tcp
+       option  tcplog
+       option  dontlognull
+        timeout connect 5000
+        timeout client  50000
+        timeout server  50000
+       errorfile 400 /etc/haproxy/errors/400.http
+       errorfile 403 /etc/haproxy/errors/403.http
+       errorfile 408 /etc/haproxy/errors/408.http
+       errorfile 500 /etc/haproxy/errors/500.http
+       errorfile 502 /etc/haproxy/errors/502.http
+       errorfile 503 /etc/haproxy/errors/503.http
+       errorfile 504 /etc/haproxy/errors/504.http
+
+frontend port443
+       mode tcp
+       bind *:443
+       tcp-request inspect-delay 5s
+       tcp-request content accept if { req_ssl_hello_type 1 }
+       use_backend www if { req_ssl_sni -i www.example.edu.pl }
+       use_backend www if { req_ssl_sni -i example.edu.pl }
+       
+backend www 
+       mode tcp
+       server www 192.168.56.2:443
+
+</pre>
+                       <p>
+                               <em>Wartość opcji <code class="code-inline">
+                               ssl-default-bind-ciphers</code> złamano tylko i wyłączenie
+                               dla celów estetycznych strony.</em>
+                       </p>
+                       <p>
+                       Jeśli przyrównamy sobie konfiguracje dla HTTP oraz TCP (HTTPS),
+                       to pierwszą rzeczą, która będzie rzucać się nam w oczy będzie
+                       zmiana trybu w sekcji <code class="code-inline">defaults</code>
+                       </p>
+<pre class="code-block">
+defaults
+...
+       mode tcp
+       option tcplog
+...
+</pre>
+                       <p>
+                       Z tej sekcji usunięto również opcje 
+                       <code class="code-inline">forwardfor</code> oraz 
+                       <code class="code-inline">http-server-close</code>, ponieważ
+                       są to ustawienia trybu <code class="code-inline">http</code>
+                       </p>
+                       <p>
+                       W sekcji <code class="code-inline">frontend</code> nie ma
+                       już <em>ACL-elek</em> są warunki są używane bezpośrednio
+                       przez polecenie <code class="code-inline">use_backend</code>,
+                       więc po kolei:
+                               <ul>
+                                       <li><code class="code-inline">mode tcp</code> - 
+                                       ustawienie trybu TCP,</li>
+                                       <li><code class="code-inline">bind *:443</code> - 
+                                       ustawienie nasłuchiwania na porcie 443 na wszystkich
+                                       adresach w systemie,</li>
+                                       <li><code class="code-inline">tcp-request inpspect-delay 5s</code> - 
+                                       Maksymalny czas oczekiwania na dane podczas 
+                                       sprawdzania zawartości. Ustawiany w celu oczekiwania na przesłanie
+                                       przez klienta danych <em>SSL hello</em>,</li>
+                                       <li><code class="code-inline">tcp-request content accept if { req_ssl_hello_type 1 }</code> - 
+                                       Zaakceptowanie zawartości żądania o ile przesłana 
+                                       przez klienta wiadomość <em>SSL hello</em> jest typu
+                                        nr. 1.</li>
+                               </ul>
+                       Kolejnymi liniami tej sekcji są już polecenia <code class="code-inline">
+                       use_backend</code>, które przekazują żądania do konkretnego
+                       serwera na podstawie warunku. Tym warunkiem jest przypasowanie
+                       wartości <em>SSL SNI</em> do ciągu znaków (w tym przypadku
+                       <code class="code-inline">www.example.edu.pl</code>) bez 
+                       rozróżniania wielkości znaków (flaga <code class="code-inline">-i</code>).
+                       </p>
+<pre class="code-block">
+use_backend www if { req_ssl_sni -i www.example.edu.pl }
+</pre>
+                       <p>
+                       Po sekcji <code class="code-inline">frontend</code> występują
+                       już sekcje <code class="code-inline">backend</code>, wewnątrz
+                       sekcji znajduje się ustawienie trybu TCP oraz opcja 
+                       <code class="code-inline">server</code> wraz z adresem IP oraz
+                       portem serwera.
+                       </p>
+<pre class="code-block">
+backend www 
+       mode tcp
+       server www 192.168.56.2:443
+</pre>
+                       <p>
+                       To już jest wszystko co trzeba zrobić, aby skonfigurować
+                       <em>HAProxy</em> w podstawowy sposób. Te konfiguracje 
+                       przedstawiają <em>HAP-a</em> jako proxy, które może zastąpić
+                       <em>reverse-proxy</em> lokalnie instalowane na serwerach
+                       przy pomocy NGINX czy Apache2. Wystarczy tylko skonfigurować
+                       aplikacje tak, aby nasłuchiwały na wszystkich interfejsach
+                       systemu.
+                       </p>
+                       <p>
+                       ~xf0r3m
+                       </p>
+                       </div>
+                       <p class="footer">
+                               2021; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/laboratorium_sieci_VPN.html b/articles/terminallog/laboratorium_sieci_VPN.html
new file mode 100755 (executable)
index 0000000..91b69c3
--- /dev/null
@@ -0,0 +1,379 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       <style>
+                               .code-block {
+                                       text-align: left;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+                       </style>
+               </head>
+               <body>
+<pre>
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+</p>
+       <div class="main">
+               <h1 class="title">Laboratorium sieci VPN</h1>
+               <!--<p>15.05.2021
+                       <strong>Z racji tego iż https://vpn.wiki.morketsmerke.net nie jest już dostępna, artykuł wymaga uaktualnienia.</strong>
+               </p>-->
+               <p>
+       Laboratorium sieci prywatnych, powstało w celu sprawdzenia wartości merytorycznej, materiału Sieci VPN w kategorii terminallog.
+               </p>
+               <p>
+       Z tego co udało mi się zaobserwować to że mamy cztery główne metody realizacji, takich sieci czy też połączeń.
+               </p>
+               <ul>
+                       <li>program Stunnel,</li>
+                       <li>protokół SSH,</li>
+                       <li>program OpenVPN,</li>
+                       <li>protokół IPSec (w implementacji libreswan),</li>
+               </ul>
+               <p>
+       W zależności od naszych potrzeb możemy użyć, któregoś z powyższych narzędzi. Jeśli musimy zabezpieczyć połączenie punkt-punkt dla jednej usługi, to możemy kłaniać się ku dwóm pierwszym rozwiązaniom. Oczywiście wszystko ma swoje wady. Dla programu Stunnel, potrzebować będziemy certyfikatów, oczywiście wystawionych przez wiarygodne źródło certyfikacji, nic nie stoi na przeszkodzie, abyśmy sami stworzyli nasze własne CA.
+               </p>
+               <p><em>Stunnel wymagania:</em></p>
+               <ul>
+                       <li>certyfikaty x509,</li>
+                       <li>urząd certyfikacji CA,</li>
+                       <li>Najlepiej gdyby serwer nasłuchiwał na pętli zwrotnej,</li>
+               </ul>
+               <p>
+                       Wadą protokołu <em>SSH</em> jest to, że potrzebujemy serwera <em>SSH</em> gdzieś w Internecie.
+               </p>
+               <p>
+                       <em>SSH wymagania:</em>
+               </p>
+               <ul>
+                       <li>Serwer <em>SSH</em> gdzieś w internetach.</li>
+               </ul>
+               <p>
+                       Zaletami tych dwóch rozwiązań są kolejno:
+               </p>
+               <p>
+                       <em>Zalety Stunnel:</em>
+               </p>
+               <ul>
+                       <li>Samowystarczalne wymagania</li>
+               </ul>
+               <p>
+                       <em>Zalety SSH:</em>
+               </p>
+               <ul>
+                       <li>Realizuje połączenia, które z racji konfiguracji sieci nie mogłyby być
+    zrealizowane (robi magiczne sztuczki)</li>
+               </ul>
+               <p>
+       Co można rozumieć przez "samowystarczalne wymagania", otóż są to wymogi które możemy zrealizować samodzielnie, bez angażowania osób trzecich lub dodatkowych środków pieniężnych. Jeśli jesteśmy spłukani i możemy sobie pozwolić na konto shell, z możliwością tunelowania (większość darmowych zabrania tunelowania). Pozostaje na jedyne wyjście <em>Stunnel</em>.
+               </p>
+                       <h2>Stunnel</h2>
+               <p>
+       Naszą przygodę rozpoczynamy od czystej maszyny wirtualnej, najlepiej z jakiś bezpiecznym Linuksem. Ja wybrałem do tego celu, i nie tylko jak się przekonamy później, dystrybucje Alpine Linux. Instaluje się ją jakieś 5 min. Opis instalacji znajdziemy pod tym <a href="https://morketsmerke.net/instalacja-alpine-linux/" target="_blank">adresem</a>. Po zainstalowaniu już systemu, tworzymy nasze nowe CA (urząd certyfikacji).
+               </p>
+               <p>
+                       Edytujemy plik <em>/etc/ssl/openssl.cnf.</em> Odnajdujemy sekcję <em>[ CA_default ]</em> ustawiamy tylko opcje <em>dir</em>, tak aby wskazywała na <em>/etc/ssl</em>. Zapisujemy plik. Tworzymy pusty plik <em>index.txt</em>, inicjujemy plik <em>serial</em> za pomocą ciągu '00' (dwa zera), tworzymy katalogi <em>crl</em> i <em>newcerts</em> oraz tak jak plik <em>serial</em> inicjujemy plik <em>crlnumber</em> za pomocą dwóch zer.
+               </p>
+               <p>
+       Teraz generujemy klucz prywatny oraz certyfikat dla CA, dzięki niemu będziemy mogli, podpisywać certyfikaty. Polecenie odnośnie generowania klucza znajdują się pod tym <a href="https://vpn.wiki.morketsmerke.net/index.php/SSL">linkiem</a>. Pamiętając zarazem aby nazwy plików były takie jak w pliku konfiguracyjnym <em>openssl</em>. W <em>Common Name</em> wpisujemy FQDN hosta CA.
+               </p>
+               <p>
+       W na końcach poleceń na wiki znajduje się przy niektórych liczba 1024, jest długość klucza. Ponieważ, obecnie klucze poniżej 2048 bitów są uznawane za niebezpieczne, warto pominąć tę wartość. W pliku <em>/etc/ssl/openssl.cnf</em> wartość wskazująca na domyślną długość klucza ustawiona jest 2048 bity.
+               </p>
+               <p>
+       Korzystając z poleceń na wiki, generujemy certyfikat CA oraz klucz prywatny serwera, po wygenerowaniu klucza, przechodzimy do wygenerowania wniosku dla serwera. W polu <em>Common Name</em> wpisujemy FQDN serwera. Teraz dopiero ustawienia CA w pliku konfiguracyjnym <em>OpenSSL</em> zostaną zweryfikowane. Wszystkie błędy zwracane są dość zrozumiałe. Więc nie powinno być problemów z ich identyfikacją i naprawą. Po wygenerowaniu certyfikatu warto zdjąć hasło, z klucza prywatnego serwera, będzie to konieczne, gdy nasz tunel będzie zestawiany wraz ze startem systemu, ponieważ oczekiwanie na hasło klucza będzie wstrzymywać start systemu i może go unieruchomić, jeśli pracujemy gdzieś zdalnie. Jednak nie należy tego robić na CA, ale na hoście docelowym gdzie Stunnel będzie pracować.
+               </p>
+               <p>
+       Akurat to nie <em>Stunnel</em> zwrócił mi uwagę na ten problem, nie mniej jednak warto wyrobić w sobie pewne nawyki.
+               </p>
+               <p>
+       Teraz przechodzimy do dość trudnego zdania, generalnie na wiki jest napisane, aby stworzyć CA  na jakimś bezpiecznym komputerze, najlepiej nie podłączonym do sieci. Ja mam dwie wariacje na ten temat. Otóż możemy wykorzystać do tego celu <em>Raspberry Pi 0</em>, które hardwarowo jest offline, i komunikować się tylko z naszym komputerem za pomocą protokołu <em>RNDIS</em>, lub skorzystać z maszyny wirtualnej, tak jak w tym przypadku. Gdzie tworzymy maszynę z natywnym dostępem do internetu. Sprawdzamy czy mamy pakiet <em>OpenSSL</em>, jeśli nie to go instalujemy. Po zainstalowaniu lub upewnieniu się że pakiet jest obecny w systemie, wyłączamy maszynę. Ustawiamy interfejsy na nie podłączone, lub je usuwamy.
+                       Teraz do sedna, zanim włączymy maszynę ustawiamy jej katalog współdzielony na jeden z katalogów na naszym komputerze. Uruchamiamy maszynę, po jej uruchomieniu montujemy, katalog współdzielony, metoda na zamontowanie katalogu współdzielonego hipernadzorcy VirtualBox w Alpine Linux, znajduje się <a href="https://morketsmerke.net/virtualbox-shared-folder-na-alpine-linux/">tutaj</a>. Tam możemy przekopiować wygenerowane przez nas certyfikaty. Następnie przenieść je na inną maszynę.
+               </p>
+               <p>
+                       Obecnie w większości dystrybucji Linux, stunnel występuje pod nazwą stunnel4 (gdzie 4 oznacza wersję protokołu IP z jaką pracuje). Stunnel, możemy zainstalować z paczki systemowej, lub skompilować samodzielnie. Po zainstalowaniu programu w przypadku systemu Alpine Linux w katalogu <em>/var/run</em> pojawia się katalog <em>stunnel</em> oraz jeden dodatkowy użytkownik, jednak konfiguracje rozpoczynamy od przygotowania pliku certyfikatu. Tworzymy nowy plik w <em>/etc/stunnel</em> przekierowując zawartość pliku klucza prywatnego. Następnie do owego pliku dodajemy linję ze samą spacją, przekierowując wyjście polecenia <em>echo </em>oraz dopisując do wszystkiego zawartość pliku z certyfikatem z serwera. Dla danego pliku ustawiamy odpowiednie uprawnienia <em>600</em> oraz właściciela i grupę na <em>root</em>. Teraz tworzymy w katalogu <em>/var/run/stunnel</em>, katalog wraz z podkatalogiem mianowicie <em>var/log</em>, tam będą umieszczane nasze logi z połączenia.
+                        Wracamy do katalogu <em>/etc/stunnel</em> tworzymy plik konfiguracyjny wg. wzorca. Teraz możemy uruchomić nasz tunel, wzór pliku konfiguracyjnego oraz      uruchomienie tunelu znajdują się <a href="https://vpn.wiki.morketsmerke.net/index.php/Stunnel">tutaj</a>. Pamiętajmy dwie rzeczy, że bezpiecznie byłoby zmusić demona naszej zabezpieczanej usługi do nasłuchu tylko i wyłącznie na pętli zwrotnej o ile <em>stunnel</em> uruchamianym bezpośrednio na serwerze. Można go również uruchomić na routerze, opis znajduje się <a href="https://vpn.wiki.morketsmerke.net/index.php/Stunnel">tutaj</a>, oraz żeby zmienić porty i adresy na te które mamy tunelować, a nie kopiuj-wklej konfiguracje, a potem płacz że coś nie działa.
+               </p>
+                       <h2>SSH</h2>
+               <p>
+       Tunele <em>SSH</em> są o tyle proste, że ich konfiguracja sprowadza się do wydania jednego polecenia. Oczywiście musimy mieć gdzieś w sieci serwer z <em>SSH</em>. Za pomocą tych tuneli możemy rozwiązać trzy konkretne problemy:
+               </p>
+               <ul>
+       <li>
+               <p>
+            Problem 1. Zabezpieczenie transmisji protokołów które, szyfrowania nie oferują. Problem ten technicznie nazywamy tunelem lokalnym. Np. mamy na naszym serwerze <em>SSH</em> również serwer <em>SAMBA</em>, i chcielibyśmy z niej w bezpieczny sposób skorzystać. To w tym celu wydajemy poniższe polecenie:
+               </p>
+<pre class="code-block">
+$ ssh username@server.example.com -L 11445:127.0.0.1:445
+</pre>
+               <p>
+            Kolejno znaczenie:<br />
+            <ul>
+                 <li>
+                    <code class="code-inline">-L</code> - Oznacza że tunel będzie, tunelem lokalnym. Tunelem pomiędzy klientem (osobą inicjującą tunel), a serwer SSH.
+                </li>
+                <li>
+                    <code class="code-inline">11445:</code> - Oznacza port otwierany na pętli zwrotnej komputera klienta.
+                </li>
+                <li>
+                    <code class="code-inline">127.0.0.1</code> - Adres pętli zwrotnej.
+                </li>
+                <li>
+                    <code class="code-inline">445</code> - tunelowany port (port po stronie serwera z którym zestawiany jest tunel)
+                </li>
+            </ul>
+               </p>
+               <p>
+            Problem jest identyczny jaki rozwiązuje stunnel. Jednak z wykorzystaniem protokołu SSH. Po wywołaniu polecenia zostaniemy poproszeni o hasło lub nie, o ile importowaliśmy wcześniej klucz publiczny na nasz serwer. Normalnie zostaniemy zalogowani na serwerze Musimy pamiętać aby nie zamykać lub nie wylogowywać, tak jak długo jesteśmy zalogowani. Tyle trwa tunel. Aby teraz połączyć z sambą łączymy sie z 127.0.0.1:11445.
+               </p>
+       </li>
+       <li>
+               <p>
+            Problem 2. Chcemy połączyć się z jakąś usługą, jednak port został zablokowany przez administratora. Ten problem możemy rozwiązać za pomocą portów dynamicznych. Porty dynamiczne polegają na przekazywaniu połączeń za pomocą proxy <em>SOCKSv5</em> przez nasz serwer <em>SSH</em>. Aby uruchomić porty dynamiczne wydajemy następujące polecenie:
+               </p>
+<pre class="code-block">
+$ ssh username@server.example.com -D 8080
+</pre>
+               <p>
+            Gdzie:
+            <ul>
+                <li>
+                    <code class="code-inline">-D</code> - oznacza uruchomienie dynamicznych portów
+                </li>
+                <li>
+                    <code class="code-inline">8080</code> - oznacza port otwierany po stronie klienta dla proxy.
+                </li>
+            </ul>
+               </p>
+               <p>
+            Przy używaniu portów dynamicznych należy pamiętać o tym że adresem na jakim nasłuchuje proxy jest adres pętli zwrotnej. Najprostszą metodą użycia jest skonfigurowanie proxy <em>SOCKSv5</em> w przeglądarce Firefox, lub użycie któregoś z programów opisanego <a href="https://wiki.archlinux.org/index.php/Proxy_server#Using_a_SOCKS_proxy">tutaj</a>.
+               </p>
+       </li>
+       <li>
+               <p>
+            Problem 3. Musimy otworzyć port dla usługi, jednak nasza sięć jest skonfigurowana w taki sposób, że nie mamy dostępu aby taki port otworzyć. Problem ten jest często spotykany w sieciach osiedlowych, gdzie na interfejsie WAN naszego routera dostajemy adres sieci prywatnej oznacza to ni mniej ni więcej, że gdzieś znajduje się router nadrzędny, i to na nim należało by takiego przekierowania portów dokonać. Jednak jest prawie nie możliwe, abyśmy załatwili sobie coś takiego na telefon, często gdy naszym usługodawcą internetowym jest jakaś korporacja. Dlatego jednym z najciekawszych rozwiązań dostarczanych przez <em>SSH</em> jest zdalny tunel z przekazywaniem. Tutaj aby się nie pogubić użyjemy przykładu z Bobem i Alice.
+        </p>
+        <p>
+            <p>
+               Powiedzmy że Bob, chce udostępnić zdalny pulpit na swoim domowym komputerze Alice, jednak po telefonie i 10 minutowej rozmowie z Kobietą z wyraźnym wschodnim akcentem, nie dowiedział się niczego nowego. Zatem przy kolej na plan B, otóż Bob miał w zanadrzu jeszcze dostęp do maszyny, która pracowała sobie spokojnie na farmie serwerów, z którą łączył się za pomocą protokołu <em>SSH</em>. Więc Bob po uruchomieniu usługi zdalnego pulpitu wydaje następujące polecenie otwierając port zdalny.
+<pre class="code-block">
+$ ssh bob@server.bogobo.org -R 11111:127.0.0.1:3389
+</pre>
+            Gdzie:<br />
+                <ul>
+                    <li><code class="code-inline">-R</code> - uruchamia tunel zdalny</li>
+                    <li><code class="code-inline">11111</code> - port tunelu zdalnego - otwierany na serwerze</li>
+                    <li><code class="code-inline">127.0.0.1</code> - adres pętli zwrotnej zrówno serwera jak i klienta</li>
+                    <li><code class="code-inline">3389</code> - port lokalnej usługi komputera zestawiającego tunel</li>
+                </ul>
+            </p>
+            <p>
+               Teraz Bob instruuje Alice, aby wpisała poniższe polecenie w swoim terminalu, jednocześnie przekazując jej hasło do konta <em>SSH</em>. Polecenie Alice to (opis opcji znajduje się przy pierwszym problemie):
+            </p>
+<pre class="code-block">
+$ ssh bob@server.bogobo.org -L 13389:127.0.0.1:11111
+</pre>
+            <p>
+               Zatem tunel zdalny z przekazywaniem polega na otwarciu portu na serwerze, z którym zestawiany jest połączenie z lokalną usługą otwierającego tunel. Możemy stwierdzić że Bob za pomocą tunelu zahostował RDP swojego domowego komputera. Kiedy tunel jest otwarty, Alice otwiera tunel lokalny na port serwera <code class="code-inline">11111</code> ze swoim portem <code class="code-inline">13389</code> oczywiście na pętli zwrotnej. Dzięki czemu, może teraz połączyć się z komputerem Boba przez 127.0.0.1:13389 za pomocą aplikacji wbudowanej w systemie. Cała sztuczka polega na tym że jednym jawnym zdalnym połączeniem Alice i Boba jest połączenie z portem SSH serwera Boba.
+            </p>
+            <p>
+                                                       <strong>Ważna uwaga, należy wybierać numery portów powyżej 1024, w innym, przypadku będziemy potrzebować konta użytkownika root, inaczej tunel nie dojdzie do skutku. Najlepiej używać portów powyżej 10000.</strong>
+                                               </p>
+               </p>
+       </li>
+               </ul>
+                       <h2>OpenVPN</h2>
+    <p>
+       OpenVPN jest chyba najpopularniejszą metodą zdalnego dostępu, i o dziwo korzystając z przykładów z książki, opisanych po tym adresem: <a href="https://morketsmerke.net/site/articles/terminallog/sieci_VPN#openvpn">https://morketsmerke.net/site/articles/terminallog/sieci_VPN#openvpn</a>. Gdzie przetestowano zdalny dostęp do zasobów dla pracowników firmy oraz łączenie odziałów firmy to działa to bez zarzutu. Rzeczami, na które warto zwrócić uwagę jest to że musiałem co restart systemu tworzyć urządzenie TUN, (jedno polecenie, również znajduje się na wiki), może być to wina mojego systemu operacyjnego (Alpine Linux), na Lubuntu tego problemu nie było. I jeśli mamy ściągnąć hasło z klucza dla serwera, to zróbmy to już na docelowym hoście, ponieważ kiedy ja ściągałem hasło na CA, potem przeniosłem ten plik okazało się że jest on niezdatny do użycia. Więc to kolejna rzecz. Przy łączeniu oddziałów firmy, zmodyfikowałem scenariusz pod siebie, nie przepuszczałem całego ruchu, z oddziału przez siedzibę tylko za pomocą tras udostępniłem połączanie pomiędzy komputerami siedziby oraz oddziału. Trasy są bardzo proste.
+    </p>
+    <p>
+        Router w oddziale:
+<pre class="code-block">
+ip route add 192.168.20.0/24 via 10.3.0.2
+</pre>
+        Router w siedzibie:
+<pre class="code-block">
+ip route add 192.168.30.0/24 via 10.3.0.1
+</pre>
+        Gdzie klasy należą do poszczególnych podsieci X.Y.20.0/24 należy do klasy w siedzibie firmy, natomiast X.Y.30.0/24 należy
+        do klasy w oddziale. Adres <code class="code-inline">10.3.0.2</code> adres TUN w oddziale, a <code class="code-inline">10.3.0.1</code> to adres TUN w siedzibie.
+    </p>
+    <p>
+        Myślę że w ta wariacja, jest bardziej aktualna do dzisiejszych czasów, gdzie dysponuje się naprawdę szybkimi łączami
+        i nie potrzeba przepuszczać przez VPN, ruchu Pani Moniki, która lubi czytać pudelka do śniadania. Ponieważ opisy
+        konfiguracj
+                               i na wiki działają tu je pominę.
+    </p>
+               <p>
+                       <h2>IPSec</h2>
+               </p>
+               <p>
+                       Sporym nadużyciem było by napisanie że IPSec jest bardziej przezroczystym OpenVPN. OpenVPN to pakiet oprogramowania realizujący połaczenia punkt-punkt. IPSec to zbiór protokołów. Przez zawiłą historię twórców implementacji OpenSWAN, (pakiet który jest opisywany na wiki), opis na wiki jest nieaktualny. Powszechnie jeśli mówimy o IPSec w Linux mamy na myśli pakiet LibreSWAN, który na swojej stronie zawiera gotowe HOW-TO's połączeń host-host oraz podsieć-podsieć. Problem w tym że to nie działa. Znalazłem tutorial na howtoforge.com. Na którym działają obie metody uwierzytelnienia.
+               </p>
+               <p>
+       Konfiguracja LibreSWAN opiera się na dwóch plikach: <em>/etc/ipsec.conf</em> oraz <em>/etc/ipsec.secrets</em>. W pierwszym znich znajduje się właściwa konfiguracja natomiast w drugim znajduje się PSK. Typowe dla IPSec jest to że nie mamy klienta oraz serwera, oczywiście w ramach własnych oznaczeń, możemy nazwać którąś ze stron klientem a którąś serwerem. W IPSec mamy stronę lewą (<em>left</em>) oraz stronę prawą (<em>right</em>). Strona lewa jest tak jakby stroną naszą, czy też lokalną natomiast prawa - stroną obcą, odległa. Po obu stronach musi widnieć ta sama konfiguracja tunelu, jednak z odniesieniem stron, tj. dla strony lewej, to jest tak jak konfigurujemy, natomiast w konfiguracji strony prawej, to ona jest stroną lewą, a lewa prawą. To tak samo jak z ludźmi, kiedy stoją do siebie na przeciwko. Mamy do dyspozycji w IPSec dwa modele połączeń. Jest połączenie punkt-punkt, czy jak to woli host-host lub sieć-sieć.
+               </p>
+               <p>
+       Przed przystąpieniem do konfiguracji, nie twórzmy nowych plików, wykorzystajmy te które są dostarczone wraz pakietem LibreSWAN, tylko zakomentujmy ostatnia dyrektywę <em>include</em> (include /etc/ipsec.d/*.conf), w pliku <em>/etc/ipsec.conf</em> oraz jedyną dyrektywę <em>include</em> (include /etc/ipsec.d/*.secrets) w pliku <em>/etc/ipsec.secrets</em>. Konfiguracje przy użyciu uwierzytelnienia PSK wygląda następująco:
+               </p>
+               <p>
+       Strona lewa:<br />
+       Plik: ipsec.conf<br />
+               </p>
+<pre class="code-block">
+config setup
+protostack=netkey
+
+conn mytunnel
+
+       ike=aes256-sha256;modp4096
+       phase2alg=aes256-sha256;modp4096
+       left=172.16.2.144
+       leftsubnet=192.168.20.0/24
+       right=172.16.2.154
+       rightsubnet=172.16.2.154/32
+       authby=secret
+       type=tunnel
+  auto=start
+</pre>
+    <p>
+        Plik: ipsec.secrets
+               </p>
+<pre class="code-block">
+172.16.2.144 172.16.2.154: PSK "1234vpn_test1234"
+</pre>
+    <p>
+       Strona prawa:
+       Plik: ipsec.conf
+               </p>
+<pre class="code-block">
+config setup
+protostack=netkey
+
+conn mytunnel
+
+    ike=aes256-sha256;modp4096
+    phase2alg=aes256-sha256;modp4096
+    left=172.16.2.154
+    leftsubnet=172.16.2.154/32
+    right=172.16.2.144
+    rightsubnet=192.168.20.0/24
+    authby=secret
+    type=tunnel
+    auto=start
+
+</pre>
+    <p>
+    Plik: ipsec.secrets
+               </p>
+<pre class="code-block">
+172.16.2.154 172.16.2.144: PSK "1234vpn_test1234"
+</pre>
+               <p>
+       Powyższa konfiguracja przedstawia moją wariację na temat możliwych modeli połączeń. Na pierwszy rzut oka wygląda jak połączenie sieć-sieć, jednak w prawej podsieci znajduje się tylko jeden komputer. A więc można uznać że jest to połączenie sieć-host patrząc od lewej. Nie wiem czy ma sens, opis tych opcji, jeśli ktoś byłby zainteresowany, to use GOOGLE. Ważna rzecz, jeśli chodzi o IPSec. Jeśli korzystamy z pakietów LibreSWAN wbudowanych w system, to należy upewnić się czy mają identyczne wersje, w przeciwnym razie tunel inicjuje strona, która ma nowszą wersję oprogramowania. W przypadku tych samych wersji nie ma znaczenia, która inicjuje tunel. Aby uruchomić tunel, najpierw musimy uruchomić sługę IPSec poleceniem (na obu stronach):
+               </p>
+<pre class="code-block">
+# ipsec setup start
+</pre>
+               <p>
+       Po uruchomieniu usługi możemy dodać nasze połączenie (na obu stronach) poleceniem (podajemy nazwę połączenia, nazwa połączenia znajduje sie po słowie <em>conn</em>):
+               </p>
+<pre class="code-block">
+# ipsec auto --add mytunnel
+</pre>
+               <p>
+       Po dodaniu przez obie strony połączenia, jedna z nich (ta z wyższą wersją oprogramowania, jeśli po obu stronach są równe to bez znaczenia która) inicjuje tunel:
+               </p>
+<pre class="code-block">
+# ipsec auto --up mytunnel
+</pre>
+               <p>
+       Tunel zatrzymujemy poleceniem:
+               </p>
+<pre class="code-block">
+# ipsec auto --down mytunnel
+</pre>
+               <p>
+       Warto pamiętać o tym, że w pliku konfiguracyjnym mamy opcje <code class="code-inline">auto</code> ustawioną na <code class="code-inline">start</code> oznacza to że po dodaniu połączenia, będzie ono automatycznie zestawiane przy każdym starcie usługi ipsec. Poniżej przedstawię konfigurację z wykorzystaniem kluczy RSA do uwierzytelnienia. Poniższe kroki wykonujemy na obu komputerach. Te konfigurację zaczynamy od usunięcia obecnych plików <em>/etc/ipsec.secrets</em>. Następnie generujemy klucze właśnie do pliku poleceniem:
+               </p>
+<pre class="code-block">
+# ipsec newhostkey --output /etc/ipsec.secrets
+</pre>
+       Zawartość pliku powinna wyglądać mniej więcej tak:
+<pre class="code-block">
+: RSA   {
+        # RSA 3216 bits   a   Thu May 21 19:34:25 2020
+        # for signatures only, UNSAFE FOR ENCRYPTION
+        #ckaid=69f3a4f8d322f423033de7ef0acc3a600a351f43
+        #pubkey=0sAwEAAa235arqmgpHM21of9l7KagM4kOTZQ7VKjOwhPKdW/t+Lgo1Qp5RXcga9ENcIRUDMP3U2iqG8wOFeM0YmwsbMw58zcuTPodjjisuh4HZDf6LBvOfnG47P3mes1AJNdsDHJl96EFlrXpb3QHqK3caH9uX5qPsaiydc6ThjpYtOUyFqBkqBilg6XhO
+        Modulus: 0xadb7e5aaea9a0a47336d687fd97b29a80ce24393650ed52a33b084f29d5bfb7e2e0a35429e515dc81af4435c21150330fdd4da2a86f3038578cd189b0b1b330e7ccdcb933e87638e2b2e8781d90dfe8b06f39f9c6e3b3f799eb3500935d
+        PublicExponent: 0x010001
+        }
+# do not change the indenting of that "}"
+</pre>
+               <p>
+       Musimy pobrać do notatnika wartość <code class="code-inline">#pubkey</code>, z jednego i drugiego hosta. Następnie musimy je umieścić na pliku <em>/etc/ipsec.conf</em> jako wartości dla poszczególnych opcji. Więc <code class="code-inline">leftrsasigkey</code>, dla lewej strony oraz <code class="code-inline">rightrsasigkey</code> dla strony prawej na lewym hoście na prawym zaś odwrotnie. Konfiguracja wygląda zatem tak:
+               </p>
+               <p>
+        Strona lewa
+               </p>
+<pre class="code-block">
+config setup
+    protostack=netkey
+
+conn vpn_rsa
+
+    ike=aes256-sha256;modp4096
+    phase2alg=aes256-sha256;modp4096
+    left=172.16.2.156
+    right=127.16.2.157
+    authby=rsasig
+    leftrsasigkey=0sAwEAAa235arqmgpHM21of9l7KagM4kOTZQ7VKjOwhPKdW/t+Lgo1Qp5RXcga9ENcIRUDMP3U2iqG8wOFeM0YmwsbMw58zcuTPodjjisuh4HZDf6LBvOfnG47P3mes1AJNdsDHJl96EFlrXpb3QHqK3caH9uX5qPsaiydc6ThjpYtOUyFqBkqBi
+    rightrsasigkey=0sAwEAAfVs/GW0tllOWsFf9SrXh8w/Nt99a8+HaY7mw0BvtnYRZol+8DOwEpgwkeAMD0A2L02EpFGj8fv3DgVOvrFK3/bI67XeR7K3/m55jhloYT97RrinQGXFoqWxpAQP6TQFADHjjNypn/vHWgncuH8yfBKlsxNSUgmd1ii+ohGK15J8OS9s6
+    type=tunnel
+    auto=start
+</pre>
+                       <p>
+        Strona prawa
+                       </p>
+<pre class="code-block">
+config setup
+    protostack=netkey
+
+conn vpn_rsa
+
+    ike=aes256-sha256;modp4096
+    phase2alg=aes256-sha256;modp4096
+    left=172.16.2.157
+    right=127.16.2.156
+    authby=rsasig
+    leftrsasigkey=0sAwEAAfVs/GW0tllOWsFf9SrXh8w/Nt99a8+HaY7mw0BvtnYRZol+8DOwEpgwkeAMD0A2L02EpFGj8fv3DgVOvrFK3/bI67XeR7K3/m55jhloYT97RrinQGXFoqWxpAQP6TQFADHjjNypn/vHWgncuH8yfBKlsxNSUgmd1ii+ohGK15J8OS9s6
+    rightrsasigkey=0sAwEAAa235arqmgpHM21of9l7KagM4kOTZQ7VKjOwhPKdW/t+Lgo1Qp5RXcga9ENcIRUDMP3U2iqG8wOFeM0YmwsbMw58zcuTPodjjisuh4HZDf6LBvOfnG47P3mes1AJNdsDHJl96EFlrXpb3QHqK3caH9uX5qPsaiydc6ThjpYtOUyFqBkqBi
+    type=tunnel
+    auto=start
+</pre>
+               <p>
+    Tunel uruchamiamy wg. powyższych poleceń.
+               </p>
+                       <h2>Podsumowanie</h2>
+               <p>
+    Przedstawione zostały tu cztery sposoby, na zabezpieczenie transmisji danych, dzięki którym możemy bez obaw korzystać z usług, które takich mechanizmów nie oferują. Jeśli jeszcze nie zdecydowaliśmy czego powinniśmy użyć. Osobiście polecił bym SSH do zabezpieczania pojedynczych połączeń oraz OpenVPN dla całych sieci. Głównymi wadami, które rzutowały na ten wybór pośród pozostałych to dla Stunnela - dodatkowo potrzebne certyfikaty, a dla IPSec - potrzeba jawnych adresów IP, dokumentacja (żeby na stronie projektu przykłady konfiguracji nie działały, no to coś jest nie halo), gdyby nie te adresy, to dało by się to jakoś znieść, tunel IPSec jest przezroczysty i to jest mega. Nie trzeba ustawiać nawet routingu. Dla mnie prostota i szybkość konfiguracji to ważne rzeczy, nikt nie lubi się bawić całych dzień z daną rzeczą. Istotna jest multiplatformowość dla OpenVPN, który występuje np. na OpenBSD. Oczywiście jest to moje w pełni subiektywne zdanie.
+               </p>
+       </div>
+       <p class="footer">
+               2021; COPYLEFT; ALL RIGHTS REVERSED;
+       </p>
+               </body>
+       </html>
diff --git a/articles/terminallog/sieci_VPN.html b/articles/terminallog/sieci_VPN.html
new file mode 100644 (file)
index 0000000..55f230f
--- /dev/null
@@ -0,0 +1,3348 @@
+<!DOCTYPE html>
+  <html>
+    <head>
+      <meta charset="utf-8" />
+      <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+      <link rel="stylesheet" type="text/css" href="/style.css">
+      <style>
+        .code-block {
+          text-align: left;
+        }
+        ul { text-align: left; }
+        body {
+          width: 99%;
+          height: 100vh;
+        }
+        .main {
+          width: 100%;
+        }
+      </style>
+    </head>
+    <body>
+      <div class="main">
+      <div id="tableOfContent">
+             <h1>Sieci VPN</h1>
+        <ol>
+          <li><a href="#wstep">Wstęp</a></li>
+          <li><a href="#slabosc_protokolow">Słabość protokołów sieciowych i
+              związane z tym problemy</a></li>
+          <li><a href="#ssl">SSL jako standard bezpiecznego przesyłania danych
+              </a></li>
+          <li><a href="#tunel">Tunelowanie portów</a></li>
+          <li><a href="#openvpn">OpenVPN - praktyczne implementacja tuneli VPN
+              </a></li>
+          <li><a href="#ipsec">IPSec</a></li>
+          <li><a href="#ipsec_linux">IPSec w systemie Linux</a></li>
+        </ol>
+        <p class="footer">
+          2021; COPYLEFT; ALL RIGHTS REVERSED;
+        </p>
+        </div>
+        <div id="content">
+        <div id="contentHeader">
+<pre id="divisionBaner">
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+      <p id="contentHeaderLink" class="header_link">
+       &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+      </p>
+        </div>
+        <p>
+          <strong>VPN</strong> (ang. Virtual Private Network) - Wirtualna Sieć
+          Prywatna jest to usługa sieciowa, która pozwala na bezpieczne i
+          swobodne (chyba, że konfiguracja stanowi inaczej) połączenie 
+          odległych hostów.
+        </p>
+        <p>
+          <strong>
+          Ta strona jest oparta o książkę Marka Serfina pt. "Sieci VPN. Zdalna 
+          praca i bezpieczeństwo danych. Wydanie II rozszerzone.". Oznacza to 
+          tyle że mogą znaleźć się tu fragmenty, przykłady fragmenty kodu, a 
+          nawet całe rozdziały przepisane 1:1 z książki. Materiał na tej 
+          stronie został dostosowany tak, aby był jak najszybciej przyswajany 
+          oraz służył czytelnikowi za ściągę pod czas wdrażania/administracji 
+          technologią VPN.
+          </strong>
+        </p>
+        <h3 id="wstep">Wstęp</h3>
+        <p>
+          Żyjemy w czasach ogromnej informatyzacji przedsiębiorstw. Trudno
+          wyobrazić sobie obecnie działanie korporacji bez przynajmniej jednego
+          serwera plików czy bazy danych. Współczesne aplikacje pisane są 
+          prawie zawsze w architekturze klient-serwer, co umożliwia łatwy 
+          dostęp do zasobów wielu użytkownikom z różnych komputerów. Budowa 
+          protokołu IP sprawia, że serwer w sieci wewnętrznej może w łatwy 
+          sposób stać się osiągalny z innej sieci lub Internetu. Popularyzacja 
+          stałego, a często także szybkiego dostępu do globalnej sieci sprawia,
+          że miejsce, w którym się pracuje, przestaje mieć znaczenie. Liczy się
+          za to stały dostęp do zasobów firmy, a co za tym idzie — możliwość 
+          pracy w dowolnym miejscu o każdej porze.
+        </p>
+        <h3 id="slabosc_protokolow">Słabość protokołów sieciowych i związane z 
+          tym problemy</h3>
+        <p>
+          Leżący u podstaw działania Internetu protokół IP nie zapewnia sam w
+          sobie bezpiecznego przesyłu danych przez sieć. Podobnie rzecz ma się
+          z protokołami warstwy transportowej TCP/UDP — nie zaimplementowano w
+          nich żadnego algorytmu szyfrowania, uwierzytelniania i sprawdzania
+          integralności danych. Na domiar złego w powszechnym użyciu są
+          aplikacje zaprojektowane jeszcze na początku poprzedniej dekady —
+          takie, jak POP3 czy IMAP, które przesyłają dane (w tym hasła) jawnym
+          tekstem.
+        </p>
+        <p>
+          Mnogość aplikacji klienckich oraz skala Internetu sprawiają, że nie
+          można z dnia na dzień wycofać z użycia danego protokołu i zastąpić
+          go nowszym — łatwo wyobrazić sobie panujący w konsekwencji tego
+          posunięcia chaos.
+        </p>
+        <p>
+          W odpowiedzi na przedstawione problemy specjaliści IT opracowali
+          różne metody, a także standardy bezpiecznej transmisji danych w
+          niezabezpieczonej sieci. Najpopularniejsze z nich to: tunele SSL —
+          dla pojedynczych aplikacji, lub połączenia VPN — gdy potrzebujemy
+          przepuścić cały ruch szyfrowanym kanałem (niezależnie od protokołu
+          warstw wyższych).
+        </p>
+        <h3 id="ssl">SSL jako standard bezpiecznego przesyłania danych</h3>
+        <p>
+          <strong>SSL</strong> - Protokół bezpieczeństwa umożliwiający
+          zabezpieczenie transmisji innych protokołów zapewniający podstawowe
+          funkcje bezpieczeństwa tj.:
+        </p>
+        <ul>
+          <li>uwierzytelnienie stron - czyli potwierdzenie ich autentyczności
+              na podstawie certyfikatów,</li>
+          <li>poufność i integralność przesyłu - tzn. ochronę przed
+              podsłuchaniem i modyfikacją.</li>
+        </ul>
+        <h4>Historia i znacznie protokołu SSL</h4>
+        <p>
+          Protokół SSL został opracowany przez firmę Netscape Communications
+          Corporation w odpowiedzi na brak zabezpieczeń w popularnych wtedy
+          protokołach (tj. lata 90, ubiegłego wieku). Obecnie najpopularniejszą
+          wersją jest <strong>TLS 1.3</strong>, który jest rozwinięciem SSL. 
+          Mówiąc w obecnych czasach o SSL, to tak naprawdę mówimy o TLS.
+        </p>
+        <p>
+          W założeniach SSL powstał jako zabezpieczenie do protokołu HTTP dla
+          potrzeb usług e-commerce. Jednak dzięki jego uniwersalności można go
+          wykorzystać do zabezpieczenia większości usług TCP, a nawet do
+          tworzenia sieci VPN.
+        </p>
+        <h4>Przebieg nawiązania połączenia SSL</h4>
+        <p>
+          Zanim protokoły warstwy aplikacji będą mogły wymieniać dane w
+          bezpieczny sposób, musi nastąpić nawiązanie sesji SSL (ang.
+          <em>SSL handshake</em>). Na <strong>SSL handshake</strong> składa się
+          kilka faz negocjacji, które przedstawiono w poniżej:
+        </p>
+        <ol>
+          <li>
+           Klient łączy się z serwerem i wysyła pakiet początkowy 
+           <em>Hello</em>, a wraz z nim numer obsługiwanej wersji SSL, 
+           obsługiwane algorytmy szyfrujące, algorytmy kompresji, oraz losowy 
+           numer związany z rozpoczętą sesja (ID).</li>
+          <li>
+            Serwer w odpowiedzi wysyła klientowi numer obsługiwanej wersji SSL,
+            obsługiwane algorytmy szyfrujące, a także swój certyfikat (klucz
+            publiczny).</li>
+          <li>
+            Na tym etapie klient sprawdza certyfikat serwera - czy jest on 
+            ważny oraz czy wystawił go zaufany urząd (CA). Protokół SSL 
+            przewiduje także możliwość wysłania przez serwer żądania 
+            uwierzytelnienia klienta. Uwierzytelnienie to jest opcjonalnie i 
+            stosuje się je w określonych warunkach.</li>
+          <li>
+            W przypadku pozytywnego uwierzytelnienia serwera klient generuje
+            48-bajtową liczbę zwaną <em>pre-master secret</em> i szyfruje ją, 
+            używając przy tym klucza publicznego serwera (zawartego w 
+            certyfikacie serwera). Liczba <em>pre-master</em> składa się z 2 
+            bajtów identyfikujących klienta oraz 46 bajtów losowych.
+          </li>
+          <li>
+            Serwer po otrzymaniu liczby <em>pre-master</em> odszyfrowuje ją, 
+            używając do tego swojego klucza prywatnego, i porównuje 2 bajty 
+            identyfikujące klienta z danymi, które otrzymał w inicjacyjnym 
+            pakiecie Hello</li>
+          <li>
+            Jeśli jest wymagane uwierzytelnienie klienta, jest to robione w tej
+            chwili. Wówczas klient musi przesłać certyfikat.</li>
+          <li>
+            Na podstawie już wymienionych danych (m.in. <em>pre-master key</em>,
+            losowe dane wygenerowane w punkcie 1.) serwer i klient generuje 
+            tzw. <em>master-key</em> (znany tylko im).</li>
+          <li>
+            Zarówno klient, jak i serwer na podstawie <em>master-key</em> 
+            generują symetryczne klucze sesyjne (sześć, trzy w kierunku 
+            serwer-klient i trzy w drugą stronę), które umożliwiają im 
+            szyfrowanie i sprawdzenie integralności przesyłanych danych.</li>
+          <li>
+            Kończąc handshake, klient przesyła do serwera wiadomość 
+            zaszyfrowaną ustalonym kluczem sesyjnym. Wiadomość ta nazywana 
+            końcowym uzgodnieniem (ang. <em>finished handshake</em>), jest jako
+            pierwsza szyfrowana tajnym kluczem.</li>
+          <li>
+            Serwer odpowiada także wiadomością zaszyfrowaną za pomocą wspólnego
+            klucza. Od tej widomości, sesja SSL jest nawiązna.
+          </li>
+        </ol>
+        <h4>Znaczenie zaufanego certyfikatu</h4>
+        <p>
+          Zaufanym certyfikatem możemy określić każdy certyfikat, który został
+          wystawiony przez wiarygodne (zaufane) <strong>Centrum Certyfikacji 
+          (CA)</strong>. Każda aplikacja korzystająca z SSL, ma gdzieś w swoich
+          zasobach lokalnych bazę zaufanych wystawców, przez co nie zostajemy 
+          w ogóle poinformowani o nawiązywaniu połączenia czy sesji SSL.
+        </p>
+        <p>
+          Certyfikaty wystawione przez zaufane CA mają znaczenie głównie dla
+          publicznych serwerów, gdzie ludzie z różnych stron świata mają 
+          pewność, że serwera za który się łączą na pewno jest tym za który się
+          podaje (np. bank czy sklep internetowy).
+        </p>
+        <p>
+          Z tego względu, iż będziemy korzystać z sesji SSL do tworzenia sieci
+          VPN, nie ma przeciwwskazań aby twoja organizacja stała się CA 
+          (centrum certyfikacji) i aby można było samodzielnie generować 
+          certyfikaty i instalować je na hostach klienckich sieci. Przecież 
+          możemy zaufać przez nas wygenerowanym certyfikatom. W przeciwieństwie
+          do HTTPS, SSL w zastosowaniach VPN-owych ważne jest uwierzytelnienie 
+          klienta przez serwer, dzięku temu z naszą siecią będą mogły łączyć 
+          się tylko osoby posiadające odpowiednie certyfikaty.
+        </p>
+        <h4>Generowanie certyfikatów przy użyciu programu <em>OpenSSL</em></h4>
+        <p>
+          Zawarte w tej części informacje są niezwykle istotne, dla dalszych
+          konfiguracji, czy to <em>OpenVPN</em> czy też technologii 
+          <em>IPSec</em>. Dlatego wiele innych zagadnień będzie tu linkować.
+        </p>
+        <p>
+          Niezwykle istotne dla samego uruchomienia sieci VPN jest umiejętność
+          generowania kluczy i certyfikatów <em>X.509</em>. W systemach 
+          unixopodobnych narzędzie wykorzystywane do tego może się nieco 
+          różnić. W dystrybucjach systemu Linux raczej będziemy spotykać 
+          oryginalnym <em>OpenSSL</em>. Jeśli będziemy się decydować na 
+          skorzystanie z np. OpenBSD (co wg. mnie jest bardziej wskazane na 
+          bramę VPN niż np. Ubuntu. Dlatego że jest bardzo prosty system, ale 
+          oczywiście nie w swojej funkcjonalności raczej w architekturze czy 
+          też budowie, jest on również zorientowany na bezpieczeństwo jeśli 
+          ktoś jest fanem jądra GNU/Linux może Alpine Linux) to skorzystamy z 
+          pakietu <em>LibreSSL</em>, <em>OpenSSL</em> dla Alpine Linux.
+        </p>
+        <p>
+          Zanim jednak przejdziemy do generowania certyfikatów dla serwera i
+          klientów, musimy stworzyć własny urząd certyfikacji (CA). Dwie uwagi.  
+        </p>
+        <p>
+          Istotną rzeczą CA jest utworzenie go na jakimś bezpiecznym komputerze
+          najlepiej odłączonym od Internetu lub przynajmniej za dodatkowym
+          firewallem nie dopuszczającym żadnych innych połączeń poza jednym 
+          (tylko jednym) z swoich komputerów. Chodzi głównie aby nie był on 
+          widoczny w Internecie i ograniczyć komunikację z nim w sieci lokalnej.
+        </p>
+        <p>
+          Ważne jest aby robić kopie zapasowe, wystawionych certyfikatów oraz
+          całego katalogu <em>/etc/ssl</em>, tak aby w razie potrzeby można 
+          było unieważnić, któryś z certyfikatów.
+        </p>
+        <h5>Tworzenie własnego CA</h5>
+        <p>
+          W pierwszej kolejności odnajdujemy plik <em>openssl.cnf</em>.
+          Prawdopodobne lokalizacje tego pliku to:
+        </p>
+        <ul>
+          <li><em>/etc/ssl/openssl.cnf</em> - dla instalacji z pakietów 
+              dystrybucji,</li>
+          <li><em>/usr/local/etc/openssl.cnf</em> - w przypadkach ręcznej 
+              kompilacji,</li>
+          <li><em>C:\<em>OpenSSL</em>\bin</em> - dla systemów MS Windows.</li>
+        </ul>
+        <p>
+          W tym pliku musimy odnaleźć sekcje 
+          <code class="code-inline">[ CA_default ]</code>. Powinniśmy zmienić 
+          wpisy tak jak poniżej.
+        </p>
+<pre class="code-block">
+[ CA_default ]
+dir = /etc/ssl                        # katalog główny, w którym zapisywane są pliki.
+certs = /etc/ssl/certs                # katalog, w którym zapisywane są certyfikaty.
+crl_dir = $dir/crl                        # katalog z listą certyfikatów unieważnionych (CRL)
+private_key = $dir/private/cakey.pem  # klucz prywatny CA
+database = $dir/index.txt             # baza, w której przechowywane są informacje
+                                        o wystawionych certyfikatach wraz ze statusem
+certficate = $dir/cacrt.pem           # Certyfikat CA -  do podpisu wniosków
+serial = $dir/serial                  # plik pomocniczy z bieżącym numerem -
+                                        inkrementowany po każdym wystawieniu certyfikatu
+crl = $dir/crl.pem                    # bieżąca lista certyfikatów unieważnionych
+
+[ v3_ca ]
+# wykazujemy punkt dystrybucji listy CRL
+crlDistributionPoints=URI:http://example.com/crl.pem
+</pre>
+        <p>
+          <u>Jeśli będziemy edytować istniejący wpis, opcje których nie ma w
+          sekcji</u> <code class="code-inline">[ CA_default ]</code> 
+          <u>umieszczamy w komentarzu</u>.
+        </p>
+        <p>
+          Upewniamy się czy istnieje katalog podany w zmiennej
+          <code class="code-inline">dir</code> czyli <em>/etc/ssl</em>, oraz
+          wszystkie jego podkatalogi. Jeżeli nie, musimy je założyć. Dla 
+          katalogu <em>ssl/private</em> należy ustawić uprawnienia tak, aby 
+          tylko użytkownik <em>root</em> mógł do niego wejść.
+        </p>
+        <p>
+          Stwórzmy pliki <em>/etc/ssl/index.txt</em> oraz 
+          <em>/etc/ssl/serial</em>, używając podanych poniżej poleceń.
+        </p>
+<pre class="code-block">
+root@ca:~# touch /etc/ssl/index.txt   #(ma być pusty)
+root@ca:~# echo 00 &gt; /etc/ssl/serial  #(ma zawierać wpis 00)
+</pre>
+        <p>
+          Przystępujemy do generowania klucza prywatnego centrum certyfikacji 
+          CA. Jest to czynność jednorazowa, tzn. po wygenerowaniu klucza 
+          prywatnego CA, a następnie odpowiadającego mu certyfikatu będziemy 
+          ich używać do podpisywania innych certyfikatów. Należy pamiętać aby 
+          zarchiwizować pliki z katalogi <em>/etc/ssl</em> w bezpiecznym 
+          miejscu.
+        </p>
+        <p>
+          Będąc w katalogu <em>/etc/ssl</em>, wydajemy następujące polecenie:
+        </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl genrsa -des3 -out private/cakey.pem 1024
+Generating RSA private key, 1024 bit long modulus
+.....++++++
+...++++++
+e is 65537 (0x10001)
+Enter pass phrase for private/cakey.pem: &lt;podaj hasło klucza prywatnego CA&gt;
+</pre>
+        <p>
+          Po potwierdzeniu hasła do klucza prywatnego CA klucz zostanie 
+          zapisany w pliku <em>private/cakey.pem</em>. Nie możemy zapomnieć 
+          tego hasła, będzie nam nieraz potrzebne.
+        </p>
+        <p>
+          Kolejną czynnością jest wygenerowanie certyfikatu CA. W tym celu
+          wpisujemy następujące polecenie:
+        </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl req -new -x509 -days 365 -key private/cakey.pem -out cacert.pem
+</pre>
+        <p>
+          Zostaniemy poproszeni o podanie danych z kilku pól zawartych w 
+          certyfikacie.
+        </p>
+<pre class="code-block">
+Country Name (2 letter code) [AU]:PL
+State or Province Name (fuli name) [Some-State]:Wonderland
+Locality Name (eg. city) []: Liberty City
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:morketsmerke.net
+Organizational Unit Name (eg, section) []:
+Common Name (eg, YOUR name) []: ca.morketsmerke.net
+Email Address []:
+</pre>
+        <p>
+          Zwrócić należy uwagę na pole <code class="code-inline">
+          Common Name</code>, które powinno zawierać nazwę podmiotu - np. nazwę
+          użytkownika lub jednostki. W przypadku gdy generujemy certyfikat dla
+          CA, wpisujemy nazwę domeny firmowej lub podajemy nazwę organizacji.
+        </p>
+        <p>
+          Po podaniu hasła do klucza prywatnego certyfikat zostanie zapisany w
+          pliku <em>cacert.pem</em>. W powyższym przykładzie czas ważności
+          certyfikatu będzie wynosić 1 rok. Można go oczywiście przedłużyć.
+        </p>
+        <p>
+          Na tym kończymy tworzenie własnego urzędu CA. Mając pliki 
+          <em>cakey.pem</em> i <em>cacert.pem</em>, czyli klucz prywatny i 
+          certyfikat CA. Teraz można rozpocząć wystawianie certyfikatów innym 
+          podmiotom.
+        </p>
+        <h5>Tworzenie klucza prywatnego dla serwera</h5>
+        <p>
+          Aby stworzyć klucz prywatny należy na urzędzie CA w katalogu
+          <em>/etc/ssl</em> wydać polecenie:
+        </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl genrsa -des3 -out private/serverkey.pem 1024
+</pre>
+        <p>
+          Openssl zapyta o hasło - będzie to hasło klucza prywatnego serwera.
+          Klucz prywatny zapisany zostanie w pliku 
+          <em>private/serverkey.pem</em>
+        </p>
+        <h5>Generowanie wniosku o wystawienie certyfikatu</h5>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl req -new -key private/serverkey.pem  -out serverreq.pem
+</pre>
+        <p>
+          Potrzebne będzie hasło klucza prywatnego serwera, które podawaliśmy
+          punkt wyżej. Jeśli hasło będzie poprawne, zostaniesz zapytani o dane
+          do wniosku.
+        </p>
+<pre class="code-block">
+Country Name (2 letter code) [AU]:PL
+State or Province Name (fuli name) [Some-State]:Slask
+Locality Name (eg, city) []:G1iwice
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:Moja Firma Sp. z o.o.
+Organizational Unit Name (eg, section) []:
+Common Name (eg, YOUR name) []: server.firma.pl
+Email Address []:
+</pre>
+        <p>
+          Tutaj jako <code class="code-inline">Common Name</code> powinniśmy
+          podać pełną nazwę domenową pod, którą serwer działa w Internecie,
+          czyli FQDN. Wniosek zostanie zapisany w pliku
+          <em>/etc/ssl/serverreq.pem</em>.
+        </p>
+        <h5>Generowanie certyfikatu dla serwera</h5>
+        <p>
+          W celu wystawienia certyfikatu dla podmiotu (serwera) musismy 
+          podpisać jego wniosek. Aby to uczynić, należy wpisać poniższe 
+          polecenie.
+        </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl ca -notext -in serverreq.pem -out servercrt.pem
+</pre>
+        <p>
+          Zostaniemy zapytani o hasło do klucza prywatnego CA 
+          <em>cakey.pem</em>. Nie należy mylić go z hasłem klucza prywatnego
+           serwera.
+        </p>
+        <p>
+          Następnie <em>OpenSSL</em> pokaże szczegóły certyfikatu i zapyta, czy
+          chcemy go podpisać.
+        </p>
+<pre class="code-block">
+Signature ok
+Certificate Details:
+Serial Number: 5 (0x5)
+Validity
+Not Before: Sep 17 12:59:06 2007 GMT
+Not After : Sep 16 12:59:06 2008 GMT
+Subject:
+countryName = PL
+stateOrProvinceName = Slask
+organizationName = Moja Firma Sp. z o.o.
+organizationalUnitName =
+commonName = server.firma.pl
+X509v3 extensions:
+X509v3 Basic Constraints:
+CA:FALSE
+Netscape Comment:
+OpenSSL Generated Certificate
+X509v3 Subject Key Identifier:
+0E: CE: 3E: 06:C4:46:53:78: BO: 05: AB: 18:9B: BA: 90:79:9B: A l : A5 :C8
+X509v3 Authority Key Identifier:
+keyid:FC:B 8 :73:29:C 6 :E4:50:B 2 :3 E :C E :0A:78:8C:62:90:A 5 :62:3 C :87:IB
+DirName:/C-PL/ST=Slask/L-Gliwice/0=Moja Firma Sp. z o.o./
+CN=ca.fi rma.pl/emai 1 Address=admi n@firma.pl
+serial:97:1B:4E:CE:0B:5F:CE:E2
+Certificate is to be certified until Sep 16 12:59:06 2008 GMT (365 days)
+Sign the certificate? [y/n]: y
+1 out of 1 certificate requests certified, commit? [y/n]y
+Write out database with 1 new entries
+Data Base Updated
+</pre>
+        <p>
+          Odnośnie pracy z tak wygenerowanym certyfikatem jest jeszcze jeden
+          szczegół. Otóż każde uruchomienie aplikacji korzystającej z tego
+          certyfikatu będzie nas prosić hasło kluczy prywatnego, użytego do 
+          jego wygenerowania. Co nie jest zbyt pożądane w środowiskach 
+          serwerowych, jest natomiast rozwiązanie tego problemu. Otóż możemy 
+          przepisać klucz pomijając hasło.
+        </p>
+        <h5>Ściąganie hasła z klucza prywatnego serwera</h5>
+<pre class="code-block">
+# openssl rsa -in private/serverkey.pem -out private/serverkey.pem_bezhasla
+</pre>
+        <p>
+          Nie zaleca się ściągania haseł z certyfikatów klientów, ze względu na
+          możliwość kradzieży komputera, co umożliwi dostęp do VPN.
+        </p>
+        <h5>Unieważnianie certyfikatów</h5>
+        <p>
+          Powodów unieważnienia certyfikatów może być wiele. Jednak jeśli już
+          zachodzi taka potrzeba. Możemy użyć parametry 
+          <code class="code-inline">revoke</code> programu <em>OpenSSL</em>.
+        </p>
+<pre class="code-block">
+root@srv:/etc/ssl/# openssl ca -revoke jkowalskicert.pem
+</pre>
+        <p>
+          <em>OpenSSL</em> zapyta o hasło klucza CA i po podaniu prawidłowego 
+          unieważni certyfikat:
+        </p>
+<pre class="code-block">
+Using configuration from /usr/1ib/ssl/openssl.cnf
+Enter pass phrase for /etc/ssl/private/cakey.pem:
+DEBUG[load_index]: unique_subject = "yes"
+Revoking Certificate 04.
+Data Base Updated
+</pre>
+        <p>
+          Po unieważnieniu certyfikatu należy wygenerować jeszcze 
+          <strong>listę CRL</strong>, w której zapisane są unieważnione
+          certyfikaty.
+        </p>
+        <h5>Generowanie listy CRL (Listy unieważnionych certyfikatów)</h5>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl ca -gencrl -out crl.pem
+</pre>
+        <p>
+          Ważne, aby przenieść plik <em>crl.pem</em> do miejsca, które 
+          wskazaliśmy jako <code class="code-inline">crlDistributionPoint</code>
+          w pliku konfiguracyjnym <em>OpenSSL</em>.
+        </p>
+        <h5>Sprawdzanie ważności certyfikatu</h5>
+        <p>
+          Aby sprawdzić datę ważności certyfikatu oraz wyświetlić szczegółowe
+          informacje dla kogo został wystawiony możemy użyć polecenia:
+        </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl x509 -noout -text -i <plik certyfikatu>
+</pre>
+        <h5>Różne formaty certyfikatów</h5>
+        <p>
+          Niestety wśród certyfikatów nie ma jednego standardu i różni 
+          producenci preferują różne formaty. Niemniej za pomocą programu 
+          <em>OpenSSL</em> możemy je przekonwertować z jednego formatu na inny.
+          Klucze są najczęściej zapisywane w formie PEM lub DER (binarny). Dla 
+          certyfikatów używane są PEM, DER, PKCS12. Aplikacje bazujące na 
+          <em>OpenSSL</em>, czyli wszystkie unixowe, używają na ogół formatu 
+          PEM (Base64). Rozszerzenia dla formatu PEM to: <em>*.crt</em> 
+          <em>*.pem</em>, w systemach Windows <em>*.cer</em>
+      </p>
+      <p>
+        Aby przekonwertować certyfikat z jednej postaci na drugą, musimy
+        przekazać programowi <em>OpenSSL</em> odpowiednie parametry.
+      </p>
+      <table>
+        <tr>
+          <th>Format wejściowy</th>
+          <th>Format wyjściowy</th>
+          <th>Składnia <em>OpenSSL</em></th>
+        </tr>
+        <tr>
+          <td>PEM (cert)</td>
+          <td>DER (cert)</td>
+          <td>
+            <code class="code-inline">openssl x509 -in cert.pem -out cert.der 
+            -outform DER</code>
+          </td>
+        </tr>
+        <tr>
+          <td>DER (cert)</td>
+          <td>PEM (cert)</td>
+          <td>
+            <code class="code-inline">openssl x509 -in cert.der -inform DER 
+            -out cert.pem -outform PEM</code>
+          </td>
+        </tr>
+        <tr>
+          <td>PEM (key)</td>
+          <td>DER (key)</td>
+          <td>
+            <code class="code-inline">openssl rsa -in input.key -inform PEM 
+            -out output.key -outform DER</code>
+          </td>
+        </tr>
+        <tr>
+          <td>DER (key)</td>
+          <td>PEM (key)</td>
+          <td>
+            <code class="code-inline">openssl rsa -in input.key -inform DER 
+            -out output.key -outform PEM
+            </code>
+          </td>
+        </tr>
+        <tr>
+          <td>PEM (key,cert)</td>
+          <td>PKCS #12</td>
+          <td>
+            <code class="code-inline">openssl pkcs12 -export -out cert.p12 
+            -inkey userkey.pem -in usercert.pem</code>
+          </td>
+        </tr>
+        <tr>
+          <td>PKCS #12</td>
+          <td>PEM (cert)</td>
+          <td>
+            <code class="code-inline">openssl pkcs12 -clcerts -nokeys –in 
+            cert.p12 -out usercert.pem</code>
+          </td>
+        </tr>
+        <tr>
+          <td>PKCS #12</td>
+          <td>PEM (key)</td>
+          <td>
+            <code class="code-inline">openssl pkcs12 -nocerts -in cert.p12 –out 
+            userkey.pem</code>
+          </td>
+        </tr>
+      </table>
+      <p>
+        Aby wyświetlić informację o certyfikacie, np. informacje podane
+        podczas tworzenia wniosku, należy uruchomić program <em>OpenSSL</em> z
+        następującymi parametrami:
+      </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl x509 -in servercert.pem -subject –noout
+subject= /C=PL/ST=Slask/O=Helion/CN=server1
+</pre>
+      <p>
+        Jeśli dodamy parametr <code class="code-inline">-issuer</code>, 
+        <em>OpenSSL</em> zwróci także informację o wystawcy (CA):
+      </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl x509 -in servercert.pem -issuer -subject –noout
+subject= /C=PL/ST=Slask/O=Helion/CN=server1
+issuer= /C=PL/ST=Slask/L=Gliwice/O=Helion/CN=CA
+</pre>
+      <p>
+        Jeżeli certyfikat jest w formie binarnej (DER), do powyższej składni
+        należy dodać parametr <code class="code-inline">-inform DER</code>.
+      </p>
+      <h4>Kompilacja OpenSSL ze źródeł</h4>
+      <p>
+        Jeśli z jakichś powodów musimy skompilować <em>OpenSSL</em>, poniżej w 
+        punktach zamieszczono opis, jak to zrobić.
+      </p>
+      <ol>
+        <li>
+          Pobieramy ze strony http://www.openssl.org/source/ źródła
+          najnowszej wersji pakietu i zapisz w katalogu <em>/usr/src/</em>,
+        </li>
+        <li>
+          Porównujemy wartość MD5 pliku pobranego z sieci (polecenie 
+          <em>md5sum</em>) z wartością udostępnioną na stronie openssl.org,
+        </li>
+        <li>
+          Rozpakowujemy zawartość archiwum poleceniem
+<pre class="code-block">
+$ tar zxf openssl-nr_wersji.tar.gz
+</pre>
+        </li>
+        <li>
+          Przechodzimy do katalogu <em>openssl-nr_wersji.</em>
+        </li>
+        <li>
+          Przed przystąpieniem do kompilacji musimy ustalić, w którym katalogu 
+          program ma zostać zainstalowany oraz z jakimi dodatkowymi opcjami, 
+          podając je jako parametry skryptu 
+          <code class="code-inline">./config</code>. W poniższym przykładzie 
+          skompilujemy program z obsługą biblioteki <em>zlib</em>, a wynikowy 
+          program zostanie zainstalowany w katalogu <em>/usr/local/openssl</em>.
+          Wpisujemy polecenie:
+<pre class="code-block">
+# ./config --prefix=/usr/local zlib
+</pre>
+        </li>
+        <li>
+          Jeśli skrypt <code class="code-inline">./config</code> nie zgłosi
+          błędu, możemy przejść do właściwej kompilacji programu. W tym celu
+          wpisujemy polecenie
+<pre class="code-block">
+# make
+</pre>
+        </li>
+        <li>
+          Proces kompilacji może potrwać kilka minut, po jego zakończeniu 
+          możemy przejść do ostatniego kroku — instalacji skompilowanych
+          plików we właściwych katalogach. Aby zakończyć instalację, wpisujemy 
+          polecenie:
+<pre class="code-block">
+# make install
+</pre>
+        </li>
+      </ol>
+      <h4>Nakładki graficzne na SSL</h4>
+      <p>
+        Aby nie męczyć się ze skomplikowanymi poleceniami <em>OpenSSL</em>, 
+        można zainstalować sobie jedną z nakładek graficznych dostępnych także 
+        dla systemu Windows.
+      </p>
+      <ul>
+        <li>
+          <em>XCA</em> - Dzięki tej nakładce możemy utworzyć własny urząd
+          certyfikacji (Root CA), także generować klucze dla użytkowników i
+          wystawiać im certyfikaty. Dostępna jest dla większości systemów,
+          w tym BSD.
+        </li>
+        <li>
+          <em>My Certificate Wizard</em> - Drugą nakładka co prawda nie jest
+          przeznaczona dla administratorów. Tylko dla zwykłych użytkowników,
+          służy ona bowiem do generowania kluczy prywatnych oraz wniosków o
+          wydanie certyfikatu (pliki CSR). Program jest nieco stary. Jego
+          ostatnia stabilna wersja pochodzi z 2004, a strona twórcy ostatni
+          raz była aktualizowana w 2008 roku.
+        </li>
+      </ul>
+      <h3 id="tunel">Tunelowanie portów</h3>
+      <p>
+        <strong>Tunel</strong>, <strong>Tunele</strong> - właść.
+        <strong>Tunelowanie portów</strong>, technika pozwalając na przesłanie
+        jednego połączenia wewnątrz drugiego (tunelu). Najczęstszym 
+        zastosowanie tuneli jest szyfrowanie połączeń, które nie zostały 
+        przystosowane do korzystania z SSL czy TLS, kompresja danych czy 
+        obejście blokad portów.
+      </p>
+      <p>
+        Tunelowania używa się też jako prostszej alternatywy dla sieci VPN.
+        Jednak diametralna różnica między tunelami a siecią VPN jest taka, że
+        przez VPN operując na warstwie 3 (IP) wprowadzają własną adresacje
+        modyfikując tabele routingu tak, aby cały ruch niezależnie od aplikacji
+        czy protokołu przechodził przez szyfrowany kanał.
+      </p>
+      <p>
+        Duża zaletą tuneli jest to, że działają one warstwie użytkownika to
+        znaczy, że nie potrzeba uprawnień administratora aby zestawić tunel.
+      </p>
+      <p>
+        W praktyce tunele wyglądają tak, że użytkownik za pomocą specjalnej
+        aplikacji zestawia szyfrowane połączenie, stanowiąc tunel. W momencie
+        zestawienia tunelu otwierany jest nowy port na interfejsie pętli
+        zwrotnej (<em>127.0.0.1</em>) komputera klienta. Aplikacja na
+        komputerze użytkownika (np. program pocztowy) zamiast łaczyć się
+        bezpośrednio z IP serwera łączy się ze swoim adresem <em>127.0.0.1</em>,
+        wysyłając dane, które program obsługujący tunel pobiera, następnie
+        szyfruje i przesyła przez Internet na drugą stronę tunelu. Po drugiej
+        stronie połączenia program tunelujący odbiera dane odszyfrowuje i
+        przekazuje - po interfejsie pętli (<em>127.0.0.1</em>) - do właściwej
+        aplikacji (np. serwera POP3).
+      </p>
+      <p>
+        Oczywiście tunele, nie są alternatywą dla obsługi przez daemony SSL
+        czy TLS, główną różnicą jest tutaj ruch między aplikacją daemona, czy
+        klienta a programem tunelującym. Nie stanowi to jak zagrożenia, do
+        momentu zarażenia systemu złośliwym oprogramowaniem.
+      </p>
+      <p>
+        Wśród administratorów najpopularniejszymi programami do tworzenie
+        tuneli są <strong><em>Stunnel</em></strong> oraz <strong>SSH</strong>, oba
+        posiadają wersje na UNIX-y oraz na MS Windows.
+      </p>
+      <h4><em>Stunnel</em></h4>
+      <p>
+        <strong><em>Stunnel</em></strong> - rozprowadzany na licencji GNU/GPL program
+        do tworzenia szyfrowanych połączeń TCP. Program do uwierzytelnienia
+        wykorzystuje certyfikaty SSL/TLS <em>X.509</em>.
+      </p>
+      <p>
+      <strong>Dostępność programu w różnych systemach operacyjnych: </strong>
+      </p>
+      <ul>
+        <li><strong>Linux</strong> : REPOzytorium(Alpine, Arch, Cent OS, Debian,
+             Fedora, Mageia, OpenMandriva, OpenSUSE(leap), Ubuntu, Slackware)
+        </li>
+        <li><strong>*BSD</strong> : FreeBSD(REPO), NetBSD(REPO), 
+            OpenBSD(PORTS)</li>
+        <li><strong>macOS</strong> : brew install stunnel</li>
+        <li><strong>Windows</strong> : 
+            https://www.stunnel.org/downloads/stunnel-5.56-win64-installer.exe
+        </li>
+      </ul>
+      <p>
+        Oczywiście program można skompilować samodzielnie potrzebne biblioteki:
+        <em>libssl</em>, <em>libssl-dev</em>, <em>zlib</em>. Podczas
+        <code class="code-inline">./configure</code> podajemy
+        <code class="code-inline">--prefix=/usr/local/stunnel</code>, z 
+        docelowym miejscem instalacji. Jeśli <code class="code-inline">
+        ./configure</code> nie zgłosi błędu wykonujemy kolejno: 
+        <code class="code-inline">make</code> oraz 
+        <code class="code-inline">make install</code>.
+      </p>
+      <p>
+        Konfiguracja składa się z jednego pliku konfiguracyjnego oraz plików
+        certyfikatów. Do jego działania potrzebujemy CA (urządu certyfikacji)
+        oraz klucz i certyfikat dla serwera (najlepiej bez hasła).
+      </p>
+      <p>
+        Program <em>Stunnel</em> oczekuje klucza prywatnego oraz certyfikatu w jednym
+        pliku - podawanym w dyrektywie <code class="code-inline">cert</code>
+        pliku konfiguracyjnego. Musimy przygotować taki plik, uważając na jego
+        format. Na początku umieszczamy klucz serwera, następnie pustą linijkę
+        odstępu, a po niej certyfikat.
+      </p>
+<pre class="code-block">
+root@ca:/etc/ssl# cat private/serverkey_bezhasla.pem &gt; private/server.pem
+root@ca:/etc/ssl# echo " " &gt;&gt; private/server.pem
+root@ca:/etc/ssl# cat servercert.pem &gt;&gt; private/server.pem
+</pre>
+      <p>
+        Bardzo ważna jest pusta linijka przerwy pomiędzy kluczem a certyfikatem.
+      </p>
+      <p>
+        Tak przygotowane pliki <em>server.pem</em> wraz z certyfikatem wystawcy
+        CA (plik <em>cacert.pem</em>) musimy przegrać na właściwy serwer 
+        używając bezpiecznego połączenia, np. program SCP/SFTP lub fizycznego 
+        sprawdzonego nośnika np. pendrive'a. Pliki zapisujemy na serwerze w 
+        katalogu <em>/etc/stunnel</em>.
+      </p>
+      <p>
+        Należy pamiętać, aby na docelowej maszynie nadać odpowiednie 
+        uprawnienia do pliku <em>server.pem</em> tak, aby tylko <em>root</em> 
+        mógł go przeczytać. Do tego posłużą dwa poniższe polecenia:
+      </p>
+<pre class="code-block">
+root@srv:~# chown root:root /etc/stunnel/server.pem
+root@srv:~# chmod 600 /etc/stunnel/server.pem
+</pre>
+      <p>
+        Czy będą na potrzebne certyfikaty dla klientów? To zależy od aplikacji,
+        czy posiada ona wewnętrzne metody uwierzytelniania użytkowników. Jeśli
+        usługa jest ogólnodostępna tak jak np. IRC, warto rozważyć wdrożenie
+        certyfikatów dla klientów, o ile chcemy utajnić nasz serwer IRC.
+        Wystawianie dla tuneli certyfikatów klienta ma sens w jeszcze jednym
+        przypadku, mianowicie chodzi o ograniczenie dostępu do konkretnych 
+        rzeczy - tylko konkretne osoby mogą korzystać z konkretnych zasobów. 
+        Jeśli już decydujemy się na uwierzytelnianie użytkowników, to należy 
+        pamiętać aby w <em>Common Name</em> podać nazwę jednoznacznie 
+        identyfikująca np. login korporacyjny. Decyzje o uwierzytelnieniu 
+        użytkowników, należy podjąć samodzielnie, warto pod jedno za lub 
+        przeciw wziąć liczbę użytkowników.
+     </p>
+     <h5>stunnel.conf</h5>
+     <p>
+      Plik konfiguracyjny składa się z sekcji globalnej oraz przynajmniej 
+      jednej dotyczącej danego tunelu (instancji/usługi). Puste linie są
+      ignorowane, podobnie jak komentarze zaczynające się od średnika
+      (<strong>;</strong>) lub krzyżyka (<strong>#</strong>).
+    </p>
+    <p>
+      <strong>Wykaz najważniejszych opcji globalnych</strong>
+    </p>
+    <ul>
+      <li><code class="code-inline">chroot = katalog</code> (tylko Unix) -
+          określa katalog, w którym uwięziony zostanie proces programu po
+          inicjalizacji. Ścieżki podane w opcjach <code class="code-inline">
+          CApath</code>, <code class="code-inline">CRLpath</code>, 
+          <code class="code-inline">pid</code>,
+          <code class="code-inline">exec</code> muszą być określone względem
+          tego katalogu. Owo uwięzienie sprawia, że nawet w przypadku 
+          znalezienia poważnego błędu w aplikacji, umożliwiającego wywołanie 
+          powłoki systemu Unix, napastnik zostanie "uwięziony" wewnątrz 
+          katalogu <em>/var/run/stunnel</em>. Nie będzie mógł po za ten katalog
+          wyjść, a więc nie będzie miał dostępu do żadnych innych plików 
+          serwera. <code class="code-inline">chroot</code> jest typową metodą 
+          zabezpieczania programów w środowisku uniksowym,</li>
+      <li><code class="code-inline">compression = zlib | rle</code> -  wybór
+          algorytmu kompresji przesyłanych danych. Domyślna opcja to brak 
+          kompresji. Możemy skorzystać z prostego algorytmu <em>RLE</em> lub z 
+          bardziej wydajnej biblioteki <em>zlib</em>. W tym drugim przypadku 
+          biblioteka <em>OpenSSL</em> musi być skompilowana z obsługą kompresji
+          <code class="code-inline">zlib</code>,</li>
+      <li><code class="code-inline">debug = wartość</code> - określa poziom
+          szczegółowości logowania w skali od 1 do 7, odpowiadający poziomom
+          daemona <code class="code-inline">syslog</code>,</li>
+      <li><code>output = plik</code> - użycie tej opcji spowoduje logowanie
+          informacji do wskazanego pliku zamiast do daemona
+          <code class="code-inline">syslog</code>,</li>
+      <li><code class="code-inline">setuid = uid</code> (tylko Unix) - 
+          identyfikator użytkownika, na którego prawach będzie działał <em>Stunnel</em>.
+          Program po uruchomieni zrzuca uprawnienia administratora i działa 
+          jako wskazany tutaj użytkownik,</li>
+      <li><code class="code-inline">setgid = gid</code> (tylko Unix) - opcja
+          jak powyżej tylko dotycząca grupy.</li>
+    </ul>
+    <p>
+      <strong>Opcje dotyczące sekcji usług</strong>
+    </p>
+    <ul>
+      <li><code class="code-inline">accept = [adres:]port</code> - nasłuchuje
+          na podanym adresie i porcie. Jeśli nie zostanie jawnie podany adres
+          IP, <em>Stunnel</em> będzie nasłuchiwał na wszystkich adresach IP dostępnych
+          w systemie,</li>
+      <li><code class="code-inline">connect = [adres:]port</code> - połacz
+          się ze zdalnym serwerem na podany port. Domyślnie <em>localhost</em>,
+      </li>
+      <li><code class="code-inline">cert = server.pem</code> - plik z kluczem
+          prywatnym i certyfikatem,</li>
+      <li><code class="code-inline">ciphers = lista_algorytmów</code> - zawiera
+          listę dozwolonych algorytmów SSL. Przydatna jeśli druga strona nie
+          wspiera jakiegoś szyfru,</li>
+      <li><code class="code-inline">client = yes | no </code>  - ustala, czy
+          sekcja jest klientem czy serwerem. Domyślna wartość:
+          <code class="code-inline">no</code> - tryb serwerowy,</li>
+      <li><code class="code-inline">CRLfile = plik_CRL</code> - plik z listą
+          odwołanych certyfikatów (CRL). Używana, gdy załączona jest opcja
+          <code class="code-inline">verify</code>,</li>
+      <li><code class="code-inline">ident = nazwa_użytkownika</code> - 
+          weryfikuj nazwę zdalnego użytkownika korzystając z protokołu IDENT,
+      </li>
+      <li><code class="code-inline">verify = poziom</code> - domyślnie
+          <code class="code-inline">0</code> - nie weryfikuj certyfikatu 
+          (klienta). Dyrektywa ta może przyjmować następujące wartości:
+          <ul>
+            <li>poziom <code class="code-inline">1</code> -  weryfikuj, jeżeli
+                został przedstawiony,</li>
+            <li>poziom <code class="code-inline">2</code> - weryfikuj 
+                certyfikat przez lokalne CA,</li>
+            <li>poziom <code class="code-inline">3</code> - weryfikuj z 
+                lokalnie zainstalowanym certyfikatem drugiej strony.</li>
+          </ul>
+          Załączenie opcji <code class="code-inline">verify</code> po stronie
+          serwera jest koniecznie jeśli dostęp do tunelu mają mieć wyłącznie
+          uwierzytelnieni użytkownicy (z wystawionymi certyfikatami przez
+          nasze CA).</li>
+      <li><code class="code-inline">retry = yes | no (tylko Unix)</code> - 
+          połącz ponownie sekcję <code class="code-inline">connect+exec</code> 
+          po rozłączeniu.</li>
+    </ul>
+    <h5>Przykład 1</h5>
+    <p>
+      Przykład opisuje stworzenie tunelu TCP umożliwiającego bezpieczne
+      ściąganie poczty przez protokół POP3.
+    </p>
+    <p>
+      Jak wiadomo protokół POP3 w swej pierwotnej postaci przesyła wszystkie
+      dane, łącznie z hasłem, jawnym tekstem. Naszym celem będzie 
+      przepuszczenie sesji połączenia POP3 przez szyfrowany tunel SSL, tak aby 
+      nikt nie był w stanie odczytać ani treści poczty ani hasła.
+    </p>
+    <p>
+      Ze względu na to, że POP3 uwierzytelnia klientów, certyfikaty dla
+      użytkowników tunelu nie będą potrzebne.  Podstawowym celem tunelu jest
+      zapewnienie szyfrowania transmisji. Uwierzytelnienie serwera będzie
+      dobrym pomysłem, bo daje pewność, że łączą się z właściwym serwerem,
+      a nie z podstawionym przez intruza w wyniku zmiany routingu. Przykład
+      można wykonać wg. poniższych punktów.
+    </p>
+    <ol>
+      <li>Instalujemy najwygodniejszym dla nas sposobem <em>Stunnel</em> w naszym 
+          systemie,</li>
+      <li>Generujemy na komputerze przeznaczony do CA, klucz i certyfikat dla 
+          serwera, po czym łączymy ze sobą oba pliku w plik <em>server.pem</em>,
+          pamiętając o pustej linijce przerwy.</li>
+      <li>Przegrywamy na serwer docelowy przygotowany plik <em>server.pem</em>
+          oraz <em>cacert.pem</em> - certyfikat CA. Pamiętając o zmianie 
+          uprawnień dla pliku <em>server.pem</em>.</li>
+      <li>Tworzymy plik <em>/etc/stunnel/stunnel.conf</em> z zawartością
+          pokazaną w poniżej:
+<pre class="code-block">
+# stunnel.conf po stronie serwera
+# opcje globalne
+chroot = /var/run/stunnel ; ścieżka do chroota
+pid = /stunnel.pid
+setuid = stunnel   ; zrzuć uprawnienia do użytkownika stunnel
+setgid = stunnel   ; jw. dla grupy
+debug = 3
+output = /var/log/stunnel.log
+
+# sekcja związana z sekcją pop3
+[pop3s]            ; początek sekcji pop3
+accept  = 995      ; oczekuj połączeń na porcie 995
+connect = 110      ; przekazuj dane do portu 110 localhosta
+cert = /etc/stunnel/server.pem   ; plik PEM z kluczem prywatnym i certyfikatem
+CAfile = /etc/stunnel/cacert.pem ; certyfikat CA
+verify = 0         ; nie sprawdzamy certyfikatów użytkowników
+</pre>
+          Czytając ten plik konfiguracyjny wraz z komentarzami można zrozumieć
+          jak będzie działał program <em>Stunnel</em>.  Najważniejszą rzeczą jak trzeba
+          by tutaj zaznaczyć, jest że POP3 nasłuchuje na pętli zwrotnej
+          (<em>127.0.0.1</em>) na portcie 110. Jeśli instalując jakąś usługę
+          już wiemy że będziemy używać tunelu do realizowania połączenia między
+          jej daemonem a klientem, to w konfiguracji należy ustawić jako adres
+          nasłuchiwania <em>127.0.0.1</em>. Klienci łączą się na standardowym
+          porcie 995 (standardowy port pop3s) z tunelem, ten przekazuje dane
+          wewnątrz serwera na port 110 pętli zwrotnej do daemona POP3.</li>
+      <li>Uruchamiamy tunel na serwerze:
+<pre class="code-block">
+# stunnel /etc/stunnel/stunnel.conf
+</pre>
+      </li>
+      <li>Instalujemy na komputerze klienta <em>Stunnel</em>.</li>
+      <li>Przenosimy plik z certyfikatem CA - <em>cacert.pem</em> - na komputer
+           klienta.</li>
+      <li>Tworzy plik konfiguracyjny klienta pokazany poniżej:
+<pre class="code-block">
+debug = 3
+output = stunnel.txt ; loguj do pliku
+[pop3s] ; początek sekcji połączenia POP3S
+accept = 127.0.0.1:110 ; słuchaj na porcie 110 interfejsu pętli zwrotnej
+connect = 85.198.209.251:995 ; połącz się ze zdalnym serwerem na port 995
+client = yes ; jestem klientem
+CAfile = certs.pem ; certyfikat CA potrzebny do uwierzytelnienia serwera
+verify = 2 ; weryfikuj certyfikat serwera
+</pre>
+          Warto zaznaczyć że współczesne programy pocztowe obsługują SSL/TLS
+          same w sobie, dlatego punkty 6-8 są zbędne. Jednak aby program nie
+          zgłaszał błedu w połączeniu należy dodać certyfikat naszego CA do
+          zaufanych wystawców, a po stronie serwera natomiast należy wyłączyć
+          opcje weryfikacji klienta. (<code class="code-inline">verify = 0
+          </code>), ponieważ programy pocztowe nie przedstawiają swojego 
+          certyfikatu (a przynajmniej nie wszystkie da się do tego zmusić).
+      </li>
+    </ol>
+    <h5>Przykład 2</h5>
+    <p>
+      Przykład przedstawia stworzenie tunelu TCP umożliwiającego bezpieczny
+      dostęp do aplikacji bazodanowej wewnątrz sieci LAN.
+    </p>
+    <p>
+      Zadanie to możemy rozwiązać za pomocą programu <em>Stunnel</em>, przy czym w tym
+      przypadku program będzie działał na routerze, a nie bezpośrednio na
+      serwerze bazodanowym. Przyda nam się tutaj opcja uwierzytelniania
+      klientów, a także załączenie kompresji.
+    </p>
+    <p>
+      Zadanie wykonujemy wg. poniższych punktów.
+    </p>
+    <ol>
+      <li>Zainstalujemy program <em>Stunnel</em> na routerze.</li>
+      <li>Generujemy na osobnym komputerze (CA) klucz i certyfikaty dla serwera
+          i użytkowników. Pamiętajmy, aby nie ściągać haseł z kluczy dla
+          użytkowników.</li>
+      <li>Przenosimy przygotowany plik <em>server.pem</em> oraz certyfikat CA
+          (plik <em>cacert.pem</em>) na router. Ustawiamy uprawnienia tak aby 
+          tylko <em>root</em> był właścicielem i tylko on miał prawo odczytu.
+      </li>
+      <li>Ustalamy, na jakim porcie i jakim adresie działa baza danych.</li>
+      <li>Przygotowujemy plik konfiguracyjny po stronie routera</li>
+      <li>Odblokowujemy na firewallu możliwość łączenia się z portem,
+          na którym słucha program <em>Stunnel</em>.</li>
+      <li>Przenosimy klucz i certyfikat (w formie <em>client.pem</em>) oraz
+          certyfikat CA (<em>cacert.pem</em>) na komputer użytkownika. 
+          Pozostawiamy kopie certyfikatów użytkowników na komputerze CA.</li>
+      <li>Przygotowujemy plik konfiguracyjny klienta i testujemy połączenie.
+      </li>
+    </ol>
+    <p>
+      Jeśli jest to możliwe to dobrze by było, żeby <em>Stunnel</em> od strony Internetu
+      nasłuchiwał na jakimś wysokim porcie, z którym nie jest skojarzona żadna
+      usługa.
+    </p>
+    <p>
+      Poniżej przedstawiono plik konfiguracyjny routera:
+    </p>
+<pre class="code-block">
+# plik konfiguracyjny programu Stunnel po stronie routera
+# opcje globalne
+chroot = /var/run/stunnel ; ścieżka do chroota
+pid = /stunnel.pid
+setuid = stunnel   ; zrzuć uprawnienia do użytkownika stunnel
+setgid = stunnel   ; jw. dla grupy
+debug = 3
+output = /var/log/stunnel.log
+
+# sekcja związana z dostępem do serwera SQL
+[sqls]               ; początek sekcji SQL
+accept  = 11298      ; oczekuj połączeń na tym porcie
+connect = 192.168.20.6: 3050   ; przekazuj do portu 3050 hosta 192.168.20.6
+cert = /etc/stunnel/server.pem
+CAfile = /etc/stunnel/cacert.pem
+verify = 2
+</pre>
+    <p>
+      Jeśli na naszym routerze domyślną polityką jest <em>blokuj</em>, to w 
+      następnej kolejności należy odblokować port na którym słucha 
+      <em>Stunnel</em>.
+    </p>
+    <p>
+      Do uruchomienia tunelu pozostała jeszcze konfiguracja klienta. W tym
+      celu należy zainstalować program <em>Stunnel</em> oraz przegrać 
+      przygotowane wcześniej certyfikaty <em>client.pem</em> oraz 
+      <em>cacert.pem</em>. Konfiguracja klienta jest przestawiona poniżej.
+    </p>
+<pre class="code-block">
+debug = 3
+output = stunnel.txt ; loguj do pliku
+[sqls]
+accept = 127.0.0.1: 3050       ; słuchaj na porcie 110 interfejsu pętli zwrotnej
+connect = 85.198.209.251:11298 ; połącz się z serwerem na port 11298
+client = yes       ; jestem klientem
+CAfile = certs.pem ; plik z certyfikatem CA, ewentualnie certyfikatem serwera
+cert = client.pem  ; plik z kluczem i certyfikatem użytkownika
+verify = 2   ; weryfikuj certyfikat serwera przez CA
+</pre>
+    <p>
+      Ostatnią rzeczą jaką należy zrobić jest zmiana adresu IP serwera bazy
+      danych aplikacji, która ma korzystać z tej bazy na adres pętli zwrotnej.
+      Do testowania działania tunelu przydaje się Telnet - po połączeniu się
+      z portem lokalnego interfejsu, powinien odpowiedzieć serwer bazy danych.
+    </p>
+    <h4>SSH</h4>
+    <p>
+      <strong>SSH</strong> - protokół sieciowy umożliwiający bezpieczne
+      (szyfrowane) połączenie z powłoką/terminalem (interfejsem tekstowym
+      komputera).
+    </p>
+    <p>
+      Generalnie SSH, służy nie tylko do pracy za pomocą zdalnej powłoki na
+      odległych serwerach, za pomocą poleceń możemy wygenerować klucze RSA,
+      których później możemy użyć do logowania bez hasła, lub jednego
+      odrębnego hasła dla wszystkich innych serwerów czy bezpiecznego
+      transferu plików jak i również zestawić szyfrowany tunel. Jedyne czego
+      potrzebujemy to konta na serwerze oraz takich możliwości (są
+      ogólnodostępne serwery oferujące konta powłoki, jednak
+      opcje tunelowania są tam niedostępne - <em>przyp. red. 2021</em>).
+    </p>
+    <p>
+      W niniejszym punkcie zostanie przedstawionych kilka praktycznych
+      przykładów dla tunelowania SSH.
+    </p>
+    <h5>Przykład 1</h5>
+    <p>
+      Podstawowym przykładem będzie zestawienie tunelu SSH pomiędzy lokalnym
+      portem TCP/12345 a portem TCP/445 odległej maszyny. Przy użyciu unixowego
+      klienta <code class="code-inline">ssh</code> składnia polecenia będzie
+      następująca:
+    </p>
+<pre class="code-block">
+jkowalski@srv10:~$ ssh admin@123.10.12.11 -L 12345:127.0.0.1:445
+</pre>
+    <p>
+      Liczba podana po <code class="code-inline">-L</code> określa, który
+      lokalny port klienta ma zostać użyty dla potrzeb tunelu.
+      <code class="code-inline">127.0.0.1:445</code> mówi nam, że zdalna strona
+      - serwer SSH, ma połączyć się z adresem 
+      <code class="code-inline">127.0.0.1</code>
+      na port TCP/<code class="code-inline">445</code>. Czyli w tym przypadku 
+      koniec tunelu stanowić będzie lokalny interfejs zdalnego serwera i 
+      działająca tam SAMBA.
+    </p>
+    <p>
+      Po podaniu hasła użytkownika zdalnego, tunel zostanie utworzony. W
+      systemach unixowych uruchomienie usługi na porcie poniżej 1024 wymaga
+      uprawnień administratora (<em>root</em>) o czym warto pamiętać. Nie ma
+      to miejsca w systemach Windows.
+    </p>
+    <p>
+      Czasami może się zdarzyć, że chcemy zestawić tunel na określony czas,
+      a także żeby proces przeszedł w tło. Dla przykładu możemy zestawić
+      tunel trwający 10 minut.
+    </p>
+<pre class="code-block">
+$ ssh -f -n -L 12345:127.0.0.1:445 admin@123.10.12.11 sleep 600
+</pre>
+    <p>
+      Opcja <code class="code-inline">-f</code> powoduje przeniesienie na tło
+      wykonania polecenia <em>/bin/sleep</em>, z kolei opcja
+      <code class="code-inline">-n</code> jest często używana z opcją
+      <code class="code-inline">-f</code>, powoduje ona przekierowanie pliku
+      <em>/dev/null</em> na standardowego wejścia dla procesu uruchomionego
+      w tle. Opcja <code class="code-inline">-n</code> zostanie
+      zignorowana gdy <code class="code-inline">ssh</code> będzie prosił o 
+      hasło.
+    </p>
+    <h5>Utworzenie tunelu z portami 1:1</h5>
+    <p>
+      Przydatne wtedy, gdy aplikacja ma już zdefiniowane odgórnie porty.
+    </p>
+<pre class="code-block">
+xf0r3m@KAT2:~$ ssh xf0r3m@dl.morketsmerke.net -L 445:127.0.0.1:445
+</pre>
+    <h5>Przykład 2 - SSH jako Socks Proxy</h5>
+    <p>
+      Tunele SSH można wykorzystać do zestawiania końców tunelu z różnymi
+      hostami, do tej port hosta na końcu tunelu był stały. Twórcy SSH
+      zaimplementowali coś takiego jak tunele dynamiczne. Jeśli pakiet zostanie
+      przekazany na przykład przez jakieś ustawienie proxy na port, na którym 
+      jest uruchomiony tunel dynamiczny, serwer zdalny zestawi koniec tunelu
+      pomiędzy sobą a hostem docelowym na danym porcie zwartym w pakiecie.
+      Można użyć tej techniki do omijania blokad portów.
+    </p>
+<pre class="code-block">
+xf0r3m@KAT2:~$ ssh xf0r3m@dl.morketsmerke.net -D 8080
+</pre>
+    <h5>Przykład 3 - tunele z przekazywaniem zdalnym</h5>
+    <p>
+      SSH pozwala na jeszcze jeden rodzaj tuneli. Mianowicie tunel z
+      przekazywaniem zdalnym. Polega on na tym że nasz serwer, który z jakiś
+      powodów nie może być normalnie wypuszczony do Internetu, tworzy
+      specjalny rodzaj tunelu, który otwiera port na serwerze. Otwarcie tego
+      portu pozwoli na połączenie się potencjalnego klienta z problematycznym
+      serwerem, warunkiem jest zestawienie kolejnego tunelu, tym razem takie 
+      jak wcześniej (lokalnego), który przekieruje dane z aplikcji na port 
+      otwarty na serwerze, a ten z kolei na nasz serwer. Jeśli jesteśmy 
+      administratorem serwera SSH, możemy ustawić go tak aby zdalny port 
+      nasłuchiwał na wszystkich adresach na serwerze, co analogicznie 
+      uwidacznia go z poziomu internetu (nie koniecznie, może być jeszcze 
+      wymagany port forwarding na routerze/bramie), służy do tego opcja 
+      <code class="code-inline">GatewayPorts</code>, która domyślnie ustawiona
+      jest na <code class="code-inline">no</code> ze względów bezpieczeństwa,
+      niweluje nam potrzebę zestawiania lokalnego przekazywania (klasycznego 
+      tunelu SSH). Warunek jest prosty. Czy otwarty przez zdalne przekazywanie 
+      serwera ma być ogólnodostępny w internecie. Jeśli tak to (i oczywiście 
+      mamy do tego odpowiednie uprawnienia) możemy przestawić tę opcję na
+      <code class="code-inline">yes</code>. Jeśli nie to pozostaje nam
+      zestawić tylko tunel pomiędzy lokalnym portem a otwartym zdalnym portem.
+    </p>
+<pre class="code-block">
+#port zdalny
+xf0r3m@KAT2:~$ ssh xf0r3m@dl.morketsmerke.net -R 11111:127.0.0.1:3389
+</pre>
+<pre class="code-block">
+#port lokalny
+xf0r3m@KAT2:~$ ssh xf0r3m@dl.morketsmerke.net -L 13389:127.0.0.1:11111
+</pre>
+    <p>
+      Podobno jeśli używamy XP wersji Professional to nie powinniśmy
+      przekierowywać lokalnego tunelu na 3389, ponieważ może na nim działać
+      lokalny serwer usług terminalowych (sic!).
+    </p>
+    <p>
+      Po zestawieniu tych tuneli powinniśmy móc się połączyć, za pomocą
+      klienta RDP, na lokalnie przekierowanym porcie czyli TCP/13389.
+    </p>
+    <h4>Tunel UDP po SSH</h4>
+    <p>
+      W przykładach na powyższych stronach, tunelowane były inne połączenia
+      TCP. To tutaj zostanie przedstawiony pomysł na tunelowanie UDP przez 
+      połączenie SSH (TCP). Generalnie do tunelowanie UDP bardziej nadają się 
+      sieci VPN, jednak przestawiony sposób działa dobrze i może przydać do 
+      prostych zastosowań.
+    </p>
+    <p>
+      Załóżmy, że musimy połączyć się z usługa UDP na porcie 7777, jednak nasz
+      komputer jest podłączony do sieci, która blokuje połączenia UDP na tym
+      porcie.
+    </p>
+    <p>
+      W tym celu musimy zestawić połączenie TCP naszego komputera z serwerem
+      pośredniczącym SSH na interesujących nas portach. W tym celu na naszym
+      komputerze wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+xf0r3m@srv01:~$ ssh -L 7777:localhost:7777 xf0r3m@srv02.morketsmerke.net
+</pre>
+    <p>
+      Teraz na serwerze SSH musimy utworzyć "przekaźnik" danych, który dane
+      odczytane z TCP 7777 prześle do portu 7777 UDP do serwera. Wykorzystamy
+      do tego kolejkę FIFO oraz program Netcat. Na serwerze pośredniczącym
+      wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+root@srv02:~# mkfifo /tmp/fifo
+</pre>
+    <p>
+      Kolejnym krokiem będzie uruchomienie programu Netcat, który będzie
+      słuchał na porcie TCP 7777 serwera (pobierał dane z tunelu) a następnie
+      już bezpośrednio będzie przekazywał je do serwera:
+    </p>
+<pre class="code-block">
+xf0r3m@srv02:~$ nc -l -p 7777 < /tmp/fifo | nc -u 123.10.12.11 7777 > /tmp/fifo
+</pre>
+    <p>
+      W pierwszej części <code>nc</code> nasłuchuje na adresie pętli zwrotnej
+      na porcie 7777, pobierając dane z tunelu a następnie przekaże je do
+      potokiem to kolejnej instancji nc, która wyśle je do serwera,
+      natomiast odpowiedzi przekaże z powrotem do kolejki, a te trafią tunelem
+      do naszego komputera.
+    </p>
+    <p>
+      Teraz wracamy do naszego komputera i tam tworzymy nową kolejkę FIFO.:
+    </p>
+<pre class="code-block">
+xf0r3m@srv01:~# mkfifo /tmp/fifo
+</pre>
+    <p>
+      Następnie uruchamiamy program Netcat z odpowiedni parametrami:
+    </p>
+<pre class="code-block">
+xf0r3m@srv01:~#nc -l -u -p 7777 < /tmp/fifo | nc localhost 7777 > /tmp/fifo
+</pre>
+    <p>
+      NC uruchamia port 7777 UDP, to z nim będzie się łączyć nasza aplikacja,
+      dane wyjściowe przekazywane są do tunelu gdzie przekazywane są do serwera
+      odpowiedzi są przekazywane do kolejki, a następnie jako dane wejściowe
+      (pobrane z kolejki FIFO) do aplikacji.
+    </p>
+    <p>
+      Powinniśmy teraz móc się połączyć. Jeśli jest z czymś problem to warto
+      upewnić się czy do kolejki trafią dane, na wolnej konsoli możemy
+      wyświetlić jej zawartość poleceniem (na obu maszynach):
+    </p>
+<pre class="code-block">
+$ tail -f /tmp/fifo
+</pre>
+    <h3 id="openvpn">OpenVPN</h3>
+    <p>
+      <strong>OpenVPN</strong> - to działający w oparciu o protokół SSL/TLS
+      program do zestawiania wirtualnych sieci prywatnych.
+    <p>
+    <p>
+      Do najważniejszych cech można zaliczyć m.in.:
+    </p>
+    <ul>
+      <li>prosta instalacja i konfiguracja,</li>
+      <li>działa w warstwie użytkownika,</li>
+      <li>wykorzystuje dobrze znany i sprawdzony protokół SSL,</li>
+      <li>dostępny jest na licencji GPL w wersji 2,</li>
+      <li>działa z większością systemów operacyjnych nawet z Windows Mobile,</li>
+      <li>działa bezproblemowo w sieciach za NAT-em.</li>
+    </ul>
+    <h4>Instalacja</h4>
+    <p>
+      Instalacja programu <em>OpenVPN</em> różni się w zależności od 
+      zainstalowanego systemu operacyjnego. W systemach Linux możemy 
+      zainstalować program, używając właściwego dla swojej dystrybucji 
+      narzędzia do zarządzania pakietami, lub też pobrać źródła programu 
+      OpenVPN i skompilować je samodzielnie. W przypadku systemu FreeBSD zaleca
+      się użycie systemu portów. Dla systemów MS Windows (2000, XP, Vista) 
+      dostępny jest pakiet instalacyjny, który oprócz właściwego programu 
+      zainstaluje też sterownik wirtualnego interfejsu TAP.
+    </p>
+    <p>
+      Poniżej przedstawione zostanie instalacja w systemie GNU/Linux Debian
+      z wykorzystaniem <code class="code-inline">apt-get</code> a także
+      kompilacje ze źródeł.
+    </p>
+    <h5>Instalacja w systemie GNU/Linux Debian</h5>
+    <p>
+      Będąc zalogowanym jako root wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+root@srv01:~# apt-get install openvpn
+</pre>.
+    <p>
+      Program <code class="code-inline">apt-get</code> ściągnie z sieci paczkę
+      z programem <em>OpenVPN</em> i zainstaluje plik w odpowiednich katalogach.
+      Skrypt instalacyjny zapyta także, czy utworzyć plik urządzenia 
+      <em>/dev/net/tun</em>. Na te pytania należy odpowiedzieć twierdząco, 
+      urządzenie jest potrzebne do działania VPN. Skrypt instalacyjny Debiana 
+      zapyta także o to czy w przypadku aktualizacji programu <em>OpenVPN</em> 
+      powinien wyłączyć usługę przed aktualizacją, czy też robić to po 
+      aktualizacji. Odpowiedź na to pytanie jest istotna w przypadku gdy dostęp
+      do konsoli serwera mamy tylko przez nasz tunel VPN - wówczas należy 
+      odpowiedzieć <strong>NIE</strong> (nie zatrzymuj usługi przed 
+      aktualizacją). W przeciwnym razie stracilibyśmy łączność z serwerem.
+      W przypadku "paczek" Debianowych program zostanie 
+      zainstalowany w katalogu <em>/usr/sbin</em>, a pliki konfiguracyjny 
+      powinien znajdować się w <em>/etc/openvpn</em>.
+    </p>
+    <h5>Instalacja przez kompilację źródeł programu (Linux)</h5>
+    <p>
+      Opis instalacji ze źródeł jest uniwersalny dla większości systemów 
+      *niksowych. Przed kompilacją upewnij się, czy masz zainstalowane w
+      systemie tzw. narzędzia deweloperskie ( np. dla dystrybucji opartych na 
+      Debianie jest to pakiet pod nazwą <em>build-essentials</em>) tj.
+      kompilator języka C++ (pakiet g++) i program <em>make</em>. Jako że 
+      <em>OpenVPN</em> działa w oparciu o protokół SSL, potrzebna będzie także
+      zainstalowana biblioteka <em>openssl</em> wraz z nagłówkami (pakiety
+      <em>libssl</em>, <em>libssl-dev</em>). Dystrybucje, w których instalacja
+      oprogramowania na ogół polega na kompilacji źródeł, powinny mieć
+      wszystkie potrzebne biblioteki już zainstalowane.
+    </p>
+    <p>
+      Przed kompilacją programu <em>OpenVPN</em> upewnij się że masz 
+      zainstalowaną w systemie bibliotekę LZO (wraz z nagłówkami) - 
+      odpowiedzialną za kompresje danych. Wprawdzie można skompilować 
+      <em>OpenVPN</em> bez tej biblioteki, jednakże pozbawimy się możliwości 
+      używania kompresji w połączeniach VPN. Aby sprawdzić czy mamy 
+      zainstalowane pliki nagłówkowe biblioteki LZO wykonujemy poniższe 
+      polecenie.
+    </p>
+<pre class="code-block">
+srv:~# find /usr/ -type -f -name 'lzo1x.h'
+</pre>
+    <p>
+      Jeśli nie znaleziono pliku <em>lzo1x.h</em>, to musimy jeszcze 
+      skompilować i zainstalować bibliotekę LZO. W tym celu wykonujemy
+      poniższe czynności.
+    </p>
+    <ol>
+      <li>Pobieramy kod źródłowy biblioteki LZO ze strony
+          <a href="http://www.oberhumer.com/opensource/lzo/#download">
+          http://www.oberhumer.com/opensource/lzo/#download</a>. Musimy pobrać
+          pełną wersję, nie wybierajmy wersji Mini-LZO, która nie zawiera
+          potrzebnych plików nagłówkowych. Rozpakowujemy kod w jakiś katalog
+          tymczasowy np. <em>/usr/src/lzo-2.10</em>.
+      </li>
+      <li>Wpisujemy polecenie:
+<pre class="code-block">
+# ./configure &amp;&amp; make &amp;&amp; make install
+</pre>
+      </li>
+    </ol>
+    <p>
+      Jeśli mamy zainstalowane w systemie podstawowe narzędzia deweloperskie,
+      biblioteka powinna skompilować się bez problemów. W wyniku instalacji
+      (polecenia <code class="code-inline">make install</code>) powinny
+      powstać pliki nagłówkowe biblioteki LZO - w katalogu
+      <em>/usr/local/include/lzo</em>. Teraz możemy przejść do kompilacji
+      programu <em>OpenVPN</em>.
+    </p>
+    <ol>
+      <li>Pobieramy źródła stabilnej wersji programu <em>OpenVPN</em> ze strony
+         głównej projektu <a href="https://openvpn.net/community-downloads/">
+            https://openvpn.net/community-downloads/</a>.
+      </li>
+      <li>Rozpakowujemy plik w katalogu <em>/usr/src/</em>. W tym celu 
+          wpisujemy polecenie:
+<pre class="code-block">
+# unzip openvpn-&lt;numer_wersji&gt;.zip
+</pre></li>
+      <li>Przechodzimy do katalogu <em>openvpn-&lt;numer_wersji&gt;</em> i
+          wpisujemy polecenie:
+<pre class="code-block">
+# ./configure
+</code></li>
+      <li>Możemy zapoznać się z listą dostępnych opcji wpisując polecenie
+<pre class="code-block">
+# ./configure --help | more
+</pre>,
+          jednakże w większości przypadków domyślne opcje konfiguracyjne są
+          wystarczające.</li>
+      <li>Jeśli podczas działania skryptu 
+          <code class="code-inline">./configure</code> nie zostaną zgłoszone 
+          błędy, możemy uruchomić właściwą kompilacje programu w tym celu 
+          wpisujemy polecenie:
+<pre class="code-inline">
+# make
+</pre>
+          Kompilacja nie trwa długo, na szybkim komputerze po około minucie
+          program <code class="code-inline">make</code> zakończy działanie.</li>
+      <li>Ostatnim krokiem jest instalacja skompilowanych plików we właściwych
+          katalogach. W tym celu wpisujemy polecenie:
+<pre class="code-block">
+# make install
+</pre>
+          Program powinien zainstalować się w katalogu <em>/usr/local/bin</em>
+      </li>
+    </ol>
+    <p>
+      <em>OpenVPN</em> potrzebuje też do działania wirtualnego interfejsu 
+      sieciowego <em>TUN/TAP</em>, którego sterownik musi być wkompilowany w 
+      jądro systemu, bądź mieć postać modułów (Linux). Jeśli nie kompilowaliśmy
+      jądra swojego systemu samodzielnie, to najprawdopodobniej odpowiedni 
+      sterownik mamy już w systemie (popularne dystrybucje dodają go w postaci 
+      modułów). Aby się o tym przekonać wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+# modprobe tun
+</pre>
+     <p>
+      Jeśli program <code class="code-inline">modprobe</code> nie zgłosi błędu,
+      możemy wpisać komendę <code class="code-inline">dmesg</code>, aby 
+      sprawdzić, czy moduł jądra został załadowany do pamięci. Szukajmy napisu 
+      zawierającego "<em>TUN/TAP</em>". Gdy program 
+      <code class="code-inline">modprobe</code> zgłosi
+      następujący błąd: 
+      <code class="code-inline">Can't locate module tun</code>,
+      oznacza to, że albo sterownik interfejsu <em>TUN/TAP</em> został 
+      wkompilowany w jądro, albo też sterownika nie ma ani w jądrze, ani w 
+      postaci modułu. Aby sprawdzić to, wpisujemy polecenie: 
+      <code class="code-inline">dmesg | grep -i tun</code>. Powinniśmy
+      zobaczyć komunikat świadczący o obecności sterownika <em>TUN/TAP</em>, w 
+      przeciwnym razie jądro nie obsługuje tego sterownika i będzie trzeba je 
+      przekompilować.
+    </p>
+    <p>
+      <strong>
+        <em>(od Redaktora strony: Tutaj ze względu na to, że książka została
+            wydana 10 lat temu. Ta część zostanie zakończona. Rekompilacja 
+            jądra przedstawiona w tym miejscu w książce była kompatybilna z 
+            jądrem 2.6, w momencie pisania jest 5.5.10, wiele rzeczy z tym 
+            związane mogło zostać zmienione, natomiast nie umiejętna 
+            rekompilacja jądrą może unieruchomić system, ta część zostanie 
+            pominięta)
+        </em>
+      </strong>
+    </p>
+    <p>
+      Ostatnim etapem instalacji programu <em>OpenVPN</em> jest stworzenie 
+      pliku urządzenia interfejsu <em>TUN</em> oraz modyfikacja skryptów 
+      startowych. Wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+# mknod /dev/net/tun c 10 200
+</pre>
+    <p>
+      Jeśli instalowaliśmy <em>OpenVPN</em> z paczki, jest wielce prawdopodobne,
+      że plik już istnieje, więc wywołanie tego polecenia zwróci błąd o tym że, 
+      pliki istnieje. Nie należy się nim przejmować. W przypadku gdy sterownik 
+      <em>TUN</em> jest w postaci modułu, upewnijmy się czy jest on dopisany w 
+      pliku odpowiedzialnym za ładowanie modułów przy starcie systemu. Niestety
+      nie ma tutaj spójności pomiędzy systemami. Poniżej znajdują się ścieżki 
+      dla najpopularniejszych dystrybucji:
+    </p>
+    <ul>
+      <li><em>/etc/modules</em> - dystrybucja Debian i wszystkie bazujące na 
+          niej,</li>
+      <li><em>/etc/rc.modules</em> - dystrybucja Slackware,</li>
+      <li><em>/etc/modprobe.conf</em> - dystrybucja RedHat, Fedora, Aurox, 
+          o inne bazujące na RHEL.</li>
+    </ul>
+    <p>
+      Jako, że do działania sieci VPN na pewno będzie potrzebne przekazywanie
+      pakietów (ang. <em>forwarding</em>) dopisujemy do pliku 
+      <em>/etc/sysctl.conf</em> linijkę: 
+      <code class="code-inline">net.ivp4.ip_forward = 1</code>.
+    </p>
+    <p>
+      Ze względów bezpieczeństwa serwera na potrzeby działania programu 
+      <em>OpenVPN</em> powinieneś stworzyć osobne konto bez możliwości 
+      logowania się i bez możliwości uruchomienia powłoki. Program 
+      <em>OpenVPN</em> zaraz po uruchomieniu się zrzuci uprawnienia użytkownika
+      <em>root</em> na to specjalne konto.
+    </p>
+    <p>
+      Zakładamy konto <em>OpenVPN</em> oraz grupę o takiej samej nazwie. W tym 
+      celu wykonujemy poniższe polecenia.
+    </p>
+    <ol>
+      <li><code class="code-inline">groupadd openvpn</code></li>
+      <li><code class="code-inline">usermod -g openvpn -d /usr/local/etc/openvpn
+           -s /bin/false -f 1 openvpn</code></li>
+      <li><code class="code-inline">mkdir /user/local/etc/openvpn</code></li>
+      <li><code class="code-inline">chown openvpn:openvpn /usr/local/etc/openvpn
+          </code></li>
+    </ol>
+    <p>
+      W powyższym przykładzie konfiguracje programu <em>OpenVPN</em> będziemy 
+      przechowywali w katalogu <em>/usr/local/etc/openvpn</em>. Możemy ją 
+      zmienić oczywiście dostosowując je do własnych potrzeb.
+    </p>
+    <h4>Konfiguracja OpenVPN</h4>
+    <p>
+      Konfiguracja programu <em>OpenVPN</em> polega na stworzeniu jednego pliku
+      konfiguracyjnego oraz ewentualnym przygotowaniu klucz i certyfikatów SSL
+      dla serwera i klientów. Liczba opcji konfiguracyjnych sukcesywnie rosła,
+      osiągając już całkiem pokaźne rozmiary. Jednak w typowych konfiguracjach
+      używać będziemy używać tylko podstawowych opcji. Nim przejdziemy do
+      praktycznych przykładów, zostaną opisane najważniejsze właściwości
+      programu <em>OpenVPN</em>.
+    </p>
+    <p>
+      <em>OpenVPN</em> może działać w jednym z dwóch podstawowych typów:
+    </p>
+    <ul>
+      <li><strong>Tryb routera</strong> - używany w przypadku konfiguracji
+          typu brama + wielu klientów lub brama-brama. Dobrym przykładem jest
+          tutaj zdalny dostęp do zasobów firmy przez mobilnych pracowników.</li>
+      <li><strong>Tryb bridge'a</strong> - używany najczęściej w przypadku
+          łączenia dwóch lub większej liczby sieci. W tym przypadku między
+          sieciami przekazywany jest cały ruch łącznie z <em>broadcastami</em>. 
+          Przykładem wykorzystania tego trybu jest stworzenie tuneli VPN 
+          pomiędzy oddziałem firmy a centralą, tak aby działał między nimi 
+          protokół IPX.</li>
+    </ul>
+    <p>
+      Trybu bridge'a powinniśmy używać tylko w gdy jest naprawdę konieczne. We
+      wszystkich pozostałych lepszym rozwiązaniem jest tryb routera. Przede
+      wszystkim dla tego że nie przesyła pakietów <em>broadcast</em>. Po drugie
+      w przypadku routera każdy z klientów ma osobną podsieć IP, dzięki czemu 
+      możemy prosto i skutecznie definiować, który użytkownik do czego ma 
+      dostęp na firewallu (np. <em>iptables</em>).
+    </p>
+    <p>
+      Drugą istotną kwestią, którą musismy rozważyć, jest sposób 
+      uwierzytelniania klientów. Tutaj także mamy dwie możliwości:
+    </p>
+    <ul>
+      <li>Uwierzytelnianie przez współdzielony stały klucz znany obu stronom.
+          Rozwiązanie proste w konfiguracji, nie nadaje się dla wielu 
+          użytkowników. Znakomicie sprawdza się jednak w przypadku łączenia 
+          podsieci, np. oddziału firmy z centralą,</li>
+      <li>Uwierzytelnianie przez certyfikaty SSL X.509, znane z poprzedniego
+          rozdziału. To rozwiązanie znakomicie nadaje się do tworzenia zdalnego
+          dostępu dla pracowników. Dzięki własnościom protokołu SSL/PKI możemy
+          wystawiać użytkownikom certyfikat na określony czas, w razie potrzeby
+          unieważnić je, nadawać dostęp na podstawie właściciela certyfikatu 
+          itp.</li>
+    </ul>
+    <p>
+      Jeśli mamy wybrać metodę to uwierzytelnianie po przez certyfikaty X.509
+      należy zastosować wszędzie tam, gdzie mamy do czynienia z czynnikiem
+      ludzkim (odchodzący pracownicy, nieznani użytkownicy). Rozwiązanie z
+      kluczem współdzielonym wystarcza w przypadku łączenia ze sobą routerów.
+    </p>
+    <p>
+      UDP czy TCP - który protokół transportowy wybrać dla potrzeb tunelu?
+      <em>OpenVPN</em> może działać z wykorzystaniem zarówno protokół UDP, jak 
+      i TCP. Autorzy <em>OpenVPN</em> zalecają używanie protokołu UDP, co może 
+      na pierwszy rzut oka wydawać się dziwne, ponieważ UDP nie zapewnia 
+      mechanizmów kontroli przesyłu ani mechanizmów potwierdzeń. Powodem jest 
+      wydajność transmisji. Chodzi tutaj o znany problem, jak pojawia się w 
+      przypadku przesyłania transmisji TCP zawartej (tunelowanej, 
+      enkapsulowanej) w ramach innej sesji TCP - co miałoby miejsce w przypadku
+      uruchomienia tunelu po TCP. Mechanizm retransmisji sprawdza się bardzo 
+      dobrze na zawodnych łączach internetowych, natomiast gdy ten sam zgubiony
+      pakiet próbują retransmitować dwa protokoły TCP, prowadzi to do zapchania
+      łącza. Wyobraźmy sobie sytuacje, w której pierwsza warstwa transportowa 
+      (ta, po której działa tunel) zaczyna gubić pakiety. W czasie, w którym 
+      warstwa niższa czeka na retransmisje, warstwa wyższa TCP (ta, która 
+      "przenosi" właściwie dane użytkownika wewnątrz tunelu) nie dostaje 
+      potwierdzeń od hosta docelowego i sama zaczyna retransmitować brakujące 
+      segmenty - zatykając tym samym i tak przytkaną już warstwę niższą. To 
+      zjawisko nazywa się efektem meltdown lub TCP meltdown.
+    </p>
+    <p>
+      W praktyce dużo zależy od tego, jakie dane będą przesyłane przez tunel
+      VPN, oraz od jakości połączenia. W przypadku dobrego łącza i małego
+      obciążenia różnica może być pomijalna. Jeśli zamierzamy uruchomić bramę
+      dostępować dla pracowników mobilnych, musimy pod uwagę, że "nietypowe"
+      porty UDP mogą być blokowane w takich miejscach jak hotel czy publiczny 
+      hotspot itp. Ostatecznie nic nie stoi na przeszkodzie aby uruchomić dwa 
+      osobne tunele, jeden działający na TCP, drugi na UDP.
+    </p>
+    <h4>Praktyczny przykład - zdalny dostęp do zasobów dla pracowników firmy</h4>
+    <p>
+      Możemy rozważyć następujący przypadek. Dostępu do zasobów sieci LAN, tj.
+      dysków udostępnionych na serwerze Windows 2003, bazy danych <em>MySQL</em>
+      oraz aplikacji intranetowej, potrzebuje grupa handlowców. Brama 
+      internetowa w firmie działa na Linuksie, użytkownicy mają na laptopach 
+      system MS Windows XP. Klasa adresowa wewnątrz sieci firmowej to
+      <code class="code-inline">192.168.10.0/24</code>.
+    </p>
+    <p>
+      Jako, że mamy tu do czynienia z czynnikiem ludzkim na pewno zastosujemy
+      uwierzytelnianie użytkowników przez certyfikaty SSL. Zanim jeszcze
+      przejdziemy do konfiguracji programu <em>OpenVPN</em>, należy przygotować
+      klucze i certyfikaty SSL dla serwera (bramy) i użytkowników.
+    </p>
+    <h5>Generowanie certyfikatów SSL</h5>
+    <p>
+      Aby móc skonfigurować niezbędne będzie utworzenie urzędu certyfikacji
+      oraz certyfikatów zarówno dla serwera jak i dla poszczególnych 
+      użytkowników, zostało zobrazowane w sekcji poświęconej SSL:
+      <a href="#ssl">Generowanie certyfikatów SSL</a>
+    </p>
+    <h5>Konfiguracja po stronie serwera</h5>
+    <p>
+      Konfiguracje serwera rozpoczynamy od przegrania na nasz serwer 
+      <em>OpenVPN</em> do katalogu z konfiguracją, certyfikatu; klucza 
+      prywatnego serwera oraz certyfikatu wystawcy CA. Następnie po stronie 
+      serwera musimy wygenerować plik pomocniczy z parametrami algorytmu 
+      kryptograficznego Diffiego-Hellmana. Algorytm ten umożliwia uzgodnienie 
+      stronom wspólnego klucza do szyfrowania symetrycznego, który będzie znany
+      tylko im. Do tego celu potrzebne są wylosowane dwie liczby pierwsze 
+      zawarte w pliku DH. Obecnie za bezpieczne uznaje się aby klucz użyty w 
+      protokole DH był długości 1024 bitów. Do celu użyjemy biblioteki 
+      <em>OpenSSL</em>. Wpisujemy polecenie podane poniżej,
+    </p>
+<pre class="code-block">
+openssl dhparam -out dh1024.pem 1024
+</pre>
+    <p>
+      Operacja może potrwać nawet kilka minut - w zależności o szybkości
+      procesora. Podczas generowania klucza (1024-bitowej liczby pierwszej)
+      na ekranie zobaczymy kropki. Przygotowany plik dh1024.pem przegrywamy do
+      katalogu konfiguracyjnego programu <em>OpenVPN</em>. Teraz możemy przejść
+      do edycji po stronie serwera. Przykładowy plik został podany poniżej.
+    </p>
+<pre class="code-block">
+dev tun                        ; rodzaj interfejsu — dla routera zawsze TUN
+local 85.198.209.251           ; adres, na którym będzie działał VPN
+proto udp                      ; tunel będzie działał na porcie UDP
+port 17003                     ; używany port
+user openvpn                   ; zrzuć uprawnienia na wskazanego użytkownika
+group openvpn                  ; jw. dla grupy
+ca cacert.pem                  ; plik certyfikatu CA
+cert servercert.pem            ; certyfikat serwera
+key serverkey.pem_bezhasla     ; plik z kluczem prywatnym serwera
+dh dh1024.pem                  ; plik z parametrami protokołu Diffiego-Hellmana
+server 10.8.0.0 255.255.255.0  ; klasa adresowa, z której przydzielane będą adresy IP klientom
+ifconfig-pool-persist ipp.txt  ; zawiera informacje o przydzielonych adresach IP
+client-config-dir ccd          ; katalog z plikami specyficznych ustawień użytkowników
+keepalive 10 120               ;
+comp-lzo                       ; algorytm kompresji
+</pre>
+    <p>
+      Spośród tego pliku konfiguracyjnego szerszego omówienia wymagają dwie 
+      opcje. 
+      <code class="code-inline">ifconfig-pool-persist &lt;nazwa pliku&gt;</code>
+      w pliku wskazanym w tej dyrektywie <em>OpenVPN</em> zapisuje nazwy 
+      użytkowników oraz adresy IP, jakie zostały przydzielone klientom z puli 
+      adresów określonej dyrektywą <code class="code-inline">server</code>. 
+      Nazwa użytkownika to zawartość pola Common Name z certyfikatu klienta. 
+      Adres IP zapisane są w postaci podsieci o masce /30
+      (<em>255.255.255.252</em>). Dzięki plikowi 
+      <code class="code-inline">ifconfig-pool-persist</code> klient
+      może otrzymać to samo IP po ponownym podłączeniu. 
+      Z plikiem <em>ipp.txt</em> związana jest pewna nieścisłość która zostanie
+      wyjaśniona przy okazji opisu bardziej złożonej konfiguracji. Kolejną 
+      dyrektywą wartą omówienia jest 
+      <code class="code-inline">client-config-dir &lt;nazwa katalogu&gt;</code>,
+      opcja ta wskazuje katalog, w którym znajdują się konfiguracje
+      poszczególnych użytkowników. Twórcy <em>OpenVPN</em> przewidzieli 
+      możliwość dostosowywania konfiguracji do konkretnych użytkowników. W 
+      momencie zestawiania połączenia VPN program sprawdza, czy istnieje plik
+      konfiguracyjny użytkownika w katalogu <em>ccd</em> i jeśli tak, 
+      przetwarza zapisane w nim opcje. Pliki w katalogu <em>ccd</em> muszą mieć
+      nazwy zgodne z polem <code>Common Name</code> certyfikatu klienta. 
+      Między innymi dlatego pole <code>Common Name</code> certyfikatu SSL jest 
+      dla programu <em>OpenVPN</em> takie ważne. Najczęściej poprzez CCD 
+      przekazujemy użytkownikowi adres IP, adresy serwerów DNS, informacje o 
+      routingu.
+    </p>
+    <h5>Uruchomienie usługi serwera</h5>
+    <p>
+      Mając przygotowany plik konfiguracyjny, możemy uruchomić proces serwera.
+      W tym celu wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+/usr/sbin/openvpn --config /usr/local/etc/openvpn/server.conf
+</pre>
+    <p>
+      Dostosowując oczywiście ścieżki dostęp do według własnej konfiguracji.
+      Jeśli mamy skonfigurowaną zaporę sieciową na domyślne blokowanie musimy
+      odblokować ją na porcie jaki podaliśmy dla usługi <em>OpenVPN</em>.
+    </p>
+    <h5>Konfiguracja klienta</h5>
+    <p>
+      Aby przetestować nasze pierwsze połączenia VPN, musimy jeszcze
+      skonfigurować ustawienia po stronie użytkownika. Zakładając, że pliki z
+      kluczem prywatnym oraz certyfikatem użytkownika mamy już przygotowane.
+      Należy przegrać je na komputer użytkownika nazywając odpowiednio
+      <em>user.key</em> i <em>user.crt</em>. Przegrać musimy też certyfikat 
+      urzędu CA - plik <em>cacert.pem</em>, aby było wygodnie pisać plik
+      konfiguracyjny i darować sobie pisanie ścieżek do certyfikatów umieścimy
+      je w tym samym katalogu co plik konfiguracyjny. Poniżej znajduje się
+      przykładowy plik konfiguracyjny dla klienta.
+    </p>
+<pre class="code-block">
+dev tun                    ; interfejs typu TUN (router)
+client                     ; tryb klienta
+remote 85.198.209.251      ; adres zdalnego serwera
+proto udp                  ; użyty protokół transportowy
+port 17003                 ; port, z którym się połączy
+nobind                     ; nie otwieraj portu po stronie klienta
+ca cacert.pem              ; plik z certyfikatem CA
+cert user.crt              ; plik z certyfikatem użytkownika
+key user.key               ; plik z kluczem prywatnym użytkownika
+comp-lzo                   ; załączona kompresja
+verb 3                     ; poziom komunikatów
+</pre>
+    <p>
+      Podczas zestawiania połączenia program kliencki czy na Windows czy to na
+      Linux będzie wyświetlać komunikaty, z nich możemy wywnioskować czy
+      połączenie zostało zestawione czy też nie. Jeśli wydaje nam się, że tak
+      to dla pewności możemy spingować adres interfejsu <em>TUN</em> na 
+      serwerze. W razie problemów przydatnym staje się program <em>tcpdump</em>
+      lub <em>Wireshark</em>. Jednak, że adres przydzielony przez serwer w 
+      sieci VPN nie daje nam jeszcze możliwości komunikacji z hostami w sieci 
+      LAN w siedzibie firmy. Aby móc wykorzystać zasoby z siedziby firmy, 
+      należy ustawić trasę w systemie aby ruch skierowany na adresy w sieci 
+      firmowej przechodził przez interfejs <em>TUN</em> (wirtualny interfejs 
+      sieci VPN).
+    </p>
+    <p>
+      Ustawienia trasy czy też statycznych adresów serwerów DNS, możemy ustawić
+      tak, aby były one przekazywane przy połączeniu. Polecenie
+      <code class="code-inline">push</code> może zostać umieszczone w pliku
+      konfiguracyjnym wtedy mamy do czynienia z konfiguracją globalną, lub w
+      katalogu <em>ccd</em> w plikach konfiguracyjnych użytkowników. Składnia
+      polecenia <code class="code-inline">push</code> dla
+      <code class="code-inline">route</code>:
+    </p>
+<pre class="code-inline">
+push "route 192.168.10.20 255.255.255.255"
+</pre>
+    <p>
+      Zwróćmy uwagę na to, że nie ma adresu bramy. Otóż <em>OpenVPN</em> sam 
+      dobierze sobie adres bramy odpowiedni dla tunelu klienta.
+    </p>
+    <h4>Bardziej złożona konfiguracja z wieloma użytkownikami</h4>
+    <p>
+      Załóżmy, że do sieci firmowej zdalny dostęp przez VPN powinna mieć spora
+      liczba pracowników - np. trzydziestu. Jako że osoby te należą do różnych
+      działów, uprawnienia do zasobów wewnętrznych muszą różnić się.
+      Pomijając dalsze uwierzytelnienia w warstwie aplikacji (hasło do bazy
+      danych itd.), powinniśmy tak skonfigurować zdalny dostęp, aby
+      pracownik "widział" jedynie to, co powinien, a nie całą sieć wewnętrzną.
+      Nie wątpliwie najprościej ten cel zrealizować przez blokadę na
+      firewallu. Tutaj świetnie sprawdzi się <em>iptables</em>.
+    </p>
+    <p>
+      W pierwszej kolejności wygenerujemy klucze wraz certyfikatami dla wszystkich
+      użytkowników, następnie powinniśmy gdzieś sobie rozpisać kto do czego
+      powinien mieć dostęp. Należy pamiętać, aby użytkownik zdalny miał dostęp
+      <strong><u>TYLKO!</u></strong> do niezbędnych zasobów. Jeśli nie ma
+      konieczności to nie powinien on również mieć dostępu do Internetu przez
+      sieć VPN. Są w sumie trzy takie zasady, dzięki którym będziemy realizować
+      naszą konfiguracje. Otóż:
+    </p>
+    <ol>
+      <li>
+        Każdemu z użytkowników, <em>OpenVPN</em> powinien przydzielać zawsze to
+        samo IP, na podstawie którego będziemy przyznawać dostęp tylko do 
+        określonych zasobów w sieci LAN (serwerów, usług).</li>
+      <li>
+        Poprzez mechanizm CCD (<em>client-config dir</em>) będziemy przekazywać
+        użytkownikom ich konfiguracje (modyfikacja tabeli routingu, zmiana
+        serwerów DNS itp.).</li>
+      <li>
+        Informacje o adresach IP oraz dostępnie do serwerów wewnętrznych
+        będzie zapisywali w plikach konfiguracyjnych <em>OpenVPN</em> oraz w 
+        postaci reguł <em>iptables</em>.</li>
+    </ol>
+    <h5>Przypisywanie stałych adresów IP użytkownikom</h5>
+    <p>
+      Za przydzielanie użytkownikom stałych adresów IP odpowiada dyrektywa
+      <code class="code-inline">ifconfig-push</code>, którą umieścimy w plikach
+      ustawień użytkowników - w katalogu <em>ccd</em>. Składnia instrukcji
+      <code class"code-inline">ifconfig-push</code> jest następująca:
+    </p>
+<pre class="code-block">
+ifconfig-push &lt;adres_klienta&gt; &lt;adres_serwera&gt;
+</pre>
+    <p>
+      Na przykład:
+    </p>
+<pre class="code-block">
+ifconfig-push 10.8.0.10 10.8.0.9
+</pre>
+    <h5>Pliki ustawień użytkowników w katalogu ccd</h5>
+    <p>
+      Poprzez pliki konfiguracyjne w katalogu <em>ccd</em> możemy przekazać
+      różne parametry, poniżej znajduje się klika przykładów.
+    </p>
+    <ul>
+      <li><code class="code-inline">push "route &lt;adres&gt; &lt;maska&gt;"</code>
+          - dodaje wpis do tablicy routingu klienta.</li>
+      <li><code class="code-inline">
+          push "dhcp-option DNS &lt;adres_IP_serwera_DNS&gt;</code>
+          - ustawia nowy DNS w konfiguracji klienta.</li>
+      <li><code class="code-inline">
+          push "dhcp-option DOMAIN &lt;nazwa_domeny&gt;</code>
+          - ustawia sufiks domeny w konfiguracji DNS klienta.</li>
+      <li><code class="code-inline">push "redirect-gateway"</code> - ustawienie
+          tej opcji spowoduje przekierowanie całego ruchu klienta (domyślna 
+          trasa)</li>
+    </ul>
+    <p>
+      Skorzystanie z ostatniej opcji 
+      (<code class="code-inline">redirect-gateway</code>) będzie wymagało 
+      utworzenia regułek NAT-u, aby 
+      użytkownik mógł "wychodzić na świat" z adresu firmowego routera.
+    </p>
+    <p>
+      Korzystając z ww. opcji, utworzymy dla każdego z użytkowników odpowiedni
+      plik w katalogu <em>ccd</em>. Będziemy przekazywali adres IP oraz wpisy
+      dodające trasy w tabeli routingu.
+    </p>
+    <h5>Logowanie zdarzeń do pliku</h5>
+    <p>
+      Jeśli planujemy produkcyjnie wdrożyć program <em>OpenVPN</em> z większą 
+      liczbą użytkowników, warto mieć możliwość szybkiego i łatwego sprawdzenia
+      informacji takich jak: kto, kiedy i skąd połączył się z VPN. Informacje
+      tego typu warto archiwizować jako ewentualny "dowód w sprawie". Może też
+      wrzucić je do bazy SQL dla łatwiejszej obróbki i generowania statystyk.
+      Do tego celu możemy wykorzystać opcję serwera <em>OpenVPN</em>
+      <code class="code-inline">learn-address</code>. Opcja ta - jeśli jest
+      załączona - wywoła skrypt podany jako parametr podczas zdarzeń takich
+      jak podłączenie się klienta, zmiana adresu IP czy rozłączenie.
+      Składnia opcji jest następująca:
+    </p>
+<pre class="code-block">
+learn-address &lt;skrypt&gt;
+</pre>
+    <p>
+      OpenVPN przekaże do skryptu parametry takie, jak:
+    </p>
+    <ol>
+      <li>parametr: <code class="code-inline">akcja</code>
+          (<code class="code-inline">add,delete,update</code>) - w zależności 
+          od tego co miało miejsce,</li>
+      <li>parametr: adres IP klienta (przydzielony w ramach tunelu),</li>
+      <li>parametr: nazwa <code class="code-inline">Common Name</code> 
+          użytkownika.</li>
+    </ol>
+    <p>
+      Niestety żaden skrypt nie jest dołączony do <em>OpenVPN</em>. Musimy 
+      napisać go samodzielnie.
+    </p>
+    <h4>Unieważnianie certyfikatów</h4>
+    <p>
+      Przy większej liczbie użytkowników prędzej czy później zajdzie potrzeba
+      zablokowania dostępu do VPN któremuś z nich. Powody mogą być różne,
+      najczęstsze to odjeście z pracy lub kradzież laptopa.
+    </p>
+    <p>
+      Załóżmy, że chcemy unieważnić certyfikat użytkownika <em>jkowalski</em>.
+      W pierwszej kolejności musimy korzystając z programu <em>OpenSSL</em>, 
+      unieważnić certyfikat. Logujemy się na komputer CA, i przechodzimy do 
+      katalogu <em>/etc/ssl</em>, a następnie wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl ca -revoke jkowalskicert.pem
+</pre>
+    <p>
+      OpenSSL zapyta o hasło klucza CA i po podaniu prawidłowego unieważni
+      certyfikat. Po unieważnieniu certyfikatu dostaniemy informacje zwrotną,
+      że baza została zaktualizowana. Możemy teraz podejrzeć zawartość pliku
+      <em>index.txt</em> - przy użytkowniku <em>jkowalski</em> zobaczymy
+      znacznik <em>R</em> (ang. <em>revoked</em>).
+    </p>
+    <p>
+      Musimy jeszcze wygenerować listę CRL, w której zapisane są wszystkie
+      unieważnione certyfikaty.
+    </p>
+<pre class="code-block">
+root@ca:/etc/ssl# openssl ca -gencrl -out crl.pem
+</pre>
+    <p>
+      Teraz należy wygenerowany plik <em>crl.pem</em>, przegrać na serwer do
+      katalogu z konfiguracją <em>OpenVPN</em>. Następnie do pisać do pliku
+      konfiguracyjnego:
+    </p>
+<pre class="code-block">
+crl-verify crl.pem
+</pre>
+    <p>
+      Restartujemy usługę (zatrzymujemy i uruchamiamy ponownie) 
+      <em>OpenVPN</em>. Teraz możemy przetestować czy <em>jkowalski</em> 
+      rzeczywiście nie ma już dostępu do VPN, zestawiając połączenie jako on. 
+      Nie dostaniemy żadnego komunikatu, po stronie klienta. Połączenie po 
+      prostu się nie zestawia.
+    </p>
+    <h4>Łączenie oddziałów firmy</h4>
+    <p>
+      Rozważmy przypadek, w którym musimy połączyć siedzibę firmy z nowo
+      powstałym oddziałem w innym mieście.
+    </p>
+    <p>
+      Sposób pierwszy, podobny w działaniu do poprzedniego przypadku, tunel
+      VPN działający w trybie routera. W tym przypadku komputery w siedzibie A
+      i siedzibie B będą w innych klasach adresowych i do komunikacji między
+      sobą będą używały bram. Rozwiązanie dobre bo separuje podsieć
+      przepuszczając tylko wymagany ruch. Niestety nie zawsze się to sprawdza,
+      gdyż, jak wiemy routery nie przekazują pakietów wysyłanych na
+      adres rozgłoszeniowy sieci (ang. <em>broadcast</em>), a niektóre 
+      protokoły używają tego adresu do poprawnego działania.
+    </p>
+    <p>
+      W związku z powyższym omówimy też drugie rozwiązanie - oparte na mostach
+      sieciowych. W tym przypadku tunel VPN będzie przezroczysty dla warstwy
+      sieci, dzięki czemu komputery będą się widziały tak, jakby oddziały były
+      połączone siecią Ethernet. Wówczas komputery w oddziałach A i B będą w
+      tej samej klasie adresowej i do komunikacji nie będą używały bram.
+    </p>
+    <p>
+      Generalnie zalecam używanie trybu routera wszędzie tam gdzie to tylko
+      możliwe. Rozwiązanie "mostkowe" przepuszcza przez tunel cały ruch
+      warstwy sieci, w tym także zapytania ARP, co oczywiście wpływa na
+      obciążenie łącza VPN.
+    </p>
+    <h5>Przykład rozwiązania z routerem</h5>
+    <p>
+      Rozważmy przypadek. Siedzibę firmy A musimy połączyć tunelem z oddziałem 
+      B. Klasa używana w sieci wewnętrznej w siedzibie A to
+      <code class="code-inline">192.168.20.0/24</code>. Komputery w oddziale B
+      powinny mieć dostęp do trzech serwerów z sieci w siedzibie A:
+      <code class="code-inline">192.168.20.3, 192.168.20.4, 192.168.20.5</code>.
+      Dodatkowo komputery z oddziału B powinny mieć dostęp do Internetu przez
+      łącze z siedziby A. Routery po obu stronach działają na Linuksie.
+    </p>
+    <p>
+      Na interfejsach tunelu użyjemy klasy 
+      <code class="code-inline">10.3.0.0/30</code>. Dla potrzeb
+      sieci wewnętrznej w oddziale B wykorzystamy klasę
+      <code class="code-inline">192.168.30.0/24</code>.
+    </p>
+    <ol>
+      <li>Instalujmy program <em>OpenVPN</em> na obu routerach opisany w 
+          początkowych sekcjach tego artykułu.</li>
+      <li>Generujemy współdzielony klucz na serwerze. W tym celu wpisujemy 
+          polecenie:
+<pre class="code-block">
+openvpn --genkey --secret secret.key
+</pre>
+          W omawianym przypadku jako metodę uwierzytelnienia zastosujemy 
+          współdzielony klucz (ang. <em>pre-shared key</em> - PSK) - ponieważ
+          jest tylko jeden klient, nie ma potrzeby generowania certyfikatów.
+      </li>
+      <li>Przegrywamy plik <em>secret.key</em> na drugi router, używając
+          bezpiecznej transmisji danych - najlepiej połączenia SCP lub SFTP:
+<pre class="code-block">
+scp secret.key root@router.siedzibab.pl:/etc/openvpn
+</pre>
+      </li>
+      <li>Przygotowujemy plik konfiguracyjny dla serwera (brama w siedzibie A)
+<pre class="code-block">
+dev tun                         ; rodzaj interfejsu — dla routera zawsze TUN
+local 85.98.29.251              ; adres routera, na którym „słucha” OpenVPN
+proto udp                       ; tunel będzie działał na porcie UDP
+port 17003                      ; używany port
+ifconfig 10.3.0.1 10.3.0.2      ; adres serwera, adres klienta
+secret /etc/openvpn/secret.key  ; ścieżka do współdzielonego klucza (PSK)
+user openvpn                    ; zrzuć uprawnienia na wskazanego użytkownika
+group openvpn                   ; jw. dla grupy
+keepalive 10 120
+comp-lzo                        ; algorytm kompresji
+verb 3                          ; poziom szczegółowości logowania
+</pre>
+      </li>
+      <li>Przygotowujemy plik konfiguracyjny dla klienta (brama w siedzibie B)
+<pre class="code-block">
+dev tun                         ; rodzaj interfejsu — dla routera zawsze TUN
+remote 85.98.29.251             ; adres drugiej strony — routera w siedzibie A
+proto udp                       ; tunel będzie działał na porcie UDP
+port 17003                      ; używany port
+ifconfig 10.3.0.2 10.3.0.1      ; adres klienta, adres serwera
+secret /etc/openvpn/secret.key  ; ścieżka do współdzielonego klucza (PSK)
+user openvpn                    ; zrzuć uprawnienia na wskazanego użytkownika
+group openvpn                   ; jw. dla grupy
+keepalive 10 120
+comp-lzo                        ; algorytm kompresji
+verb 3                          ; poziom szczegółowości logowania
+</pre>
+          Zauważ brak słowa kluczowego <code class="code-inline">client</code> 
+          w pliku konfiguracyjnym klienta. Nie jest to błąd. Opcja
+          <code class="code-inline">client</code> jest synonimem opcji
+          <code class="code-inline">tls-client</code>, a w tym przypadku nie 
+          używamy uwierzytelnienia TLS.
+      </li>
+      <li>Upewniamy się, czy na obu routerach załączone jest przekazywania
+          pakietów.
+<pre class="code-block">
+cat /proc/sys/net/ipv4/ip_forward
+</pre>
+          Polecenie powinno na obu routerach zwrócić 1, jeśli zwraca 0. To
+          należy wykonać polecenie:
+<pre class="code-block">
+echo 1 &gt; /proc/sys/net/ipv4/ip_forward
+</pre>
+          oraz dopisać do linijkę skryptów startowych systemu 
+          (<em>sysctl.conf</em>)</li>
+      <li>Jeżeli domyślną polityką bezpieczeństwa na serwerze (bramie w
+          siedzibie A) jest <em>blokuj</em>, to musimy otworzyć port 17003. W 
+          tym celu wpisujemy polecenie:
+<pre class="code-block">
+iptables -I INPUT -i ethX -p udp -d IP_routera --dport 17003 -j ACCEPT
+</pre>
+          Gdzie <code class="code-inline">ethX</code> jest nazwą interfejsu
+          łączącego router z Internetem, <code class="code-inline">IP_routera</code>
+          adres IP, pod którym router jest dostępny w Internecie. Pamiętajmy 
+          aby zapisać nasze reguły firewalla.</li>
+      <li>Jeżeli komputery oddziale B mają mieć dostęp do Internetu przez tunel
+          VPN, to na routerze w siedzibie B musimy zmienić domyślną bramę.
+          Powinna wskazywać adres IP tunelu VPN routera w siedzibie A. Obecnej
+          bramy (przydzielonej przez ISP dla siedziby B użyjemy tylko do 
+          komunikacji z routerem w siedzibie A. Na routerze w siedzibie B 
+          wpisujemy polecenie:
+          <strong><u>Uwaga!</u></strong>Jeśli pracujemy zdalnie na routerze
+          ważna jest tutaj kolejność działania. Gdybyśmy zaczęli od usunięcia
+          domyślnej bramy na routerze w oddziale, skutkowało by to utratą
+          komunikacji z nim!
+<pre class="code-block">
+rtr-officeB:~# ip route add &lt;IP_rtr_w_office_A&gt;/32 via &lt;Brama_ISP_w_office_B&gt;
+</pre>
+          Jeśli w naszym systemie brakuje polecenia 
+          <code class="code-inline">ip</code>, to należy użyć starszego 
+          polecenia:
+<pre class="code-block">
+rtr-officeB:~# route add -host &lt;IP_rtr_w_office_A&gt; gw &lt;Brama_ISP_w_office_B&gt;
+</pre>
+          Następnie usuwamy istniejącą domyślną trasę:
+<pre class="code-block">
+rtr-officeB:~# ip route delete default
+lub
+rtr-officeB:~# route delete default
+</pre>
+      </li>
+      <li>Pora na zestawienie tunelu i sprawdzenie czy strony widzą się na
+          wzajem po adresach ustawionych w plikach konfiguracyjnych w
+          dyrektywie <code class="code-inline">ifconfig</code>:
+<pre class="code-block">
+# openvpn --config &lt;ścieżka do pliku konfiguracyjny&gt;
+</pre></li>
+      <li>Jeśli mamy wzajemną widoczność, musimy ustawić bramę domyślną na
+          routerze w biurze B:
+<pre class="code-block">
+rtr-officeB:~# ip route add default via &lt;ip_tun_w_office_A&gt;
+lub
+rtr-officeB:~# route add default gw &lt;ip_tun_w_office_A&gt;
+</pre>
+          Od tej chwili cały ruch z oddziału B będzie przechodził przez łącze
+          VPN.</li>
+      <li>Pozostało jeszcze skonfigurować reguły firewalla na routerze w
+          siedzibie A. Musimy określić na co zezwalamy komputerom z sieci
+          "oddziałowej" <code class="code-inline">192.168.30.0/24</code>. Jako,
+          że domyślną polityką może być <em>blokuj</em>, każdy dostep trzeba
+          jawnie zadeklarować. Zgodnie z założeniami komputery z siedziby B
+          powinny mieć dostęp do odpowiednich serwerów. Na routerze w siedzibie
+          A wpisujemy poniższe polecenia:
+<pre class="code-block">
+iptables -I FORWARD -i tun0 -p ip -s 192.168.30.0/24 -d 192.168.20.3 -j ACCEPT
+iptables -I FORWARD -i tun0 -p ip -s 192.168.30.0/24 -d 192.168.20.4 -j ACCEPT
+iptables -I FORWARD -i tun0 -p ip -s 192.168.30.0/24 -d 192.168.20.5 -j ACCEPT
+</pre>
+          Aby zapewnić komputerom z oddziału B połączenie z Internetem, musimy
+          jeszcze stworzyć jakąś regułę NAT. Przykładowa może wyglądać
+          następująco:
+<pre class="code-block">
+iptables -t nat -A POSTROUTING -o ethX -s 192.168.30.0/24 -j SNAT --to &lt;ADRES NAT&gt;
+</pre>
+          <code class="code-inline">ethX</code> oznacza interfejs, przez 
+          których łączymy się z Internetem. 
+          <code class="code-inline">ADRES NAT</code> jest to adres na jaki 
+          zachodzić ma translacja adresów, przeważnie adres interfejsu, przez 
+          który łączymy się z Internetem.
+      </li>
+    </ol>
+    <h5>Tunel VPN z mostkowaniem</h5>
+    <p>
+      W niniejszym przykładzie rozważymy przypadek połączenia oddziału firmy z
+      centralą "przezroczystym" tunelem VPN. Założenie jest takie aby przez
+      tunel przekazywane były pakiety rozgłoszeniowe. Klasa adresowa używana w
+      obu podsieciach to <code>192.168.20.0/24</code>. Most zbudujemy z dwóch
+      interfejsów: karty sieciowej eth1 łączącej router z siecią LAN oraz
+      wirtualnego interfejsu TAP. Oprócz programu <em>OpenVPN</em> będziemy 
+      potrzebowali wkompilowanego w jądro systemu (bądź w postaci modułu) 
+      sterownika mostów sieciowych oraz programu do administracji mostem.
+      Do zarządzania mostem służy pakiet <em>bridge-utils</em>, który na ogół
+      nie wchodzi w skład popularnych dystrybucji i będzie trzeba go
+      doinstalować. W przypadku dystrybucji opartych o GNU/Linux Debian:
+    </p>
+<pre class="code-block">
+# apt-get install bridge-utils
+</pre>
+    <ol>
+      <li><u>Przygotowanie środowiska</u>
+          <ol>
+            <li>Instalujemy program <em>OpenVPN</em> na obu routerach opisany
+                na początku sekcji sposób,</li>
+            <li>Generujemy współdzielony klucz na serwerze. W tym celu
+                wpisujemy polecenie:
+<pre class="code-block">
+# openvpn --genkey --secret secret.key
+</pre>
+                W omawianym przypadku jako metodę uwierzytelnienia zastosujemy
+                współdzielony klucz (ang. <em>pre-shared key</em> - PSK) -
+                ponieważ jest tylko jeden klient, nie ma potrzeby generowania
+                certyfikatów,</li>
+            <li>Przegrywamy plik <em>secret.key</em> na drugi router, używając
+                bezpiecznej transmisji danych - najlepiej połączeniem SCP/SFTP:
+<pre class="code-block">
+# scp secret.key root@router.siedzibab.pl:/etc/openvpn
+</pre>
+            </li>
+            <li>Przygotowujemy plik konfiguracyjny dla serwera (brama w
+                siedzibie A)
+<pre class="code-block">
+dev tap                                 ; rodzaj interfejsu — dla bridge zawsze TAP
+local 85.98.29.251                      ; adres routera, na którym „słucha” OpenVPN
+proto udp                               ; tunel będzie działał na porcie UDP
+port 17003                              ; używany port
+ifconfig 192,168.20.0 255.255.255.0     ; adres serwera, adres klienta
+secret /etc/openvpn/secret.key          ; ścieżka do współdzielonego klucza (PSK)
+user openvpn                            ; zrzuć uprawnienia na wskazanego użytkownika
+group openvpn                           ; jw. dla grupy
+keepalive 10 120
+comp-lzo                                ; algorytm kompresji
+verb 3                                  ; poziom szczegółowości logowania
+</pre>
+            </li>
+            <li>Przygotowujemy plik konfiguracyjny dla klienta (brama w 
+                siedzibie B)
+<pre class="code-block">
+dev tap                                  ; rodzaj interfejsu — dla bridge zawsze TAP
+remote 85.98.29.251                      ; adres drugiej strony — routera w siedzibie A
+proto udp                                ; tunel będzie działał na porcie UDP
+port 17003                               ; używany port
+ifconfig 192,168.20.0 255.255.255.0      ; adres klienta, adres serwera
+secret /etc/openvpn/secret.key           ; ścieżka do współdzielonego klucza (PSK)
+user openvpn                             ; zrzuć uprawnienia na wskazanego użytkownika
+group openvpn                            ; jw. dla grupy
+keepalive 10 120
+comp-lzo                                 ; algorytm kompresji
+verb 3                                   ; poziom szczegółowości logowania
+</pre>
+                Zwróćmy uwagę na brak słowa kluczowego 
+                <code class="code-inline">client</code> w pliku konfiguracyjnym
+                klienta. Nie jest to błąd. Opcja 
+                <code class="code-inline">client</code> jest synonimem opcji
+                <code class="code-inline">tls-client</code>, a w tym przypadku
+                nie używamy uwierzytelnienia TLS.</li>
+            <li>Jeżeli domyślną polityką bezpieczeństwa na serwerze (bramie w
+                siedzibie A) jest <em>blokuj</em>, to musimy otworzyć port 
+                UDP/17003. W tym celu wpisujemy polecenie:
+<pre class="code-block">
+# iptables -I INPUT -i ethX -p udp -d IP_routera --dport 17003 -j ACCEPT
+</pre>
+                Gdzie <code class="code-inline">ethX</code> jest nazwą 
+                interfejsu łączącego router z Internetem, 
+                <code class="code-inline">IP_routera</code> adres IP, pod 
+                którym router jest dostępny w Internecie. Pamiętajmy aby 
+                zapisać nasze reguły firewala.</li>
+            <li>Uruchamiamy program <em>OpenVPN</em> i sprawdzamy czy istnieje 
+                on liście procesów (w obu sidzibach).
+<pre class="code-block">
+# openvpn --config &lt;plik konfiguracyjny&gt;
+</pre>
+            </li>
+            <li> Tworzymy na obu routerach most używając programu 
+                 <code class="code-inline">brctl</code>. W tym celu wpisujemy
+                 podane poniżej polecenia zachowując kolejność na obu 
+                 komputerach.
+<pre class="code-block">
+# brctl addbr br0                         # tworzy interfejs dla bridge'a
+# brctl addif br0 eth1                    # dodaje do bridge'a interfejs eth1
+# brctl addif br0 tap0                    # dodaje do bridge'a interfejs tap0
+# ifconfig eth1 0.0.0.0 promisc up        # przestawia karty eth1 i tap0
+# ifconfig tap0 0.0.0.0 promisc up        # w tryb nasłuchiwania (promiscuous mode)
+</pre>
+                Szczególną uwagę warto zwrócić na komendę
+                <code class="code-inline">brcrl addif br0 eth1</code>, a
+                konkretnie na interfejs eth1 podany jako parametr. Powinien to
+                być interfejs łączący router z siecią lokalną, a nie Internetem.
+                Pomyłka w tym miejscu będzie skutkować utratą komunikacji z
+                serwerem (jeśli pracujemy zdalnie). Następną rzeczą, na którą 
+                warto zwrócić uwagę jest to, że na interfejsie
+                <code class="code-inline">eth1</code> nie przydzielamy adresu 
+                IP! Interfejsy mostu są przezroczyste dla warstwy sieciowej i 
+                nie posiadają adresów IP. Aby nasz router miał przydzielony 
+                adres z klasy lokalnej, musimy skonfigurować go na interfejsie
+                <code class="code-inline">br0</code>. Nadajmy więc routerom
+                adresy z puli lokalnej. Przypisujemy IP
+                <code class="code-inline">192.168.20.1</code> routerowi po
+                stronie siedziby A.
+<pre class="code-block">
+# ifconfig br0 192.168.20.1 up
+</pre>
+                Routerowi w oddziale B przypiszemy adres IP 192.168.20.200.
+<pre class="code-block">
+# ifconfig br0 192.168.20.200 up
+</pre>
+                Jeśli wszystko poszło pomyślnie to strony powinny się 
+                "pingować".
+            </li>
+          </ol>
+          Zauważmy że adres <code>192.168.20.1</code> przydzielony na interfejsie
+          <code class="code-inline">br0</code> routera w siedzibie A pełni też
+          funkcje bramy domyślnej dla komputerów w swoim LAN-ie (komputerów w
+          siedzibie A)! W związku z powyższym wszystkie reguły firewalla, które
+          dotyczyłyby interfejsu <code class="code-inline">eth1</code>, teraz
+          dotyczą interfejsu <code class="code-inline">br0</code>. Most nie
+          potrzebuje załączonego przekazywania pakietów, natomiast
+          w związku z faktem że serwer w siedzibie A, pełni funkcje mostu i
+          routera, przekazywanie musi być załączone. Upewnijmy się, czy plik
+          <em>/proc/sys/net/ipv4/ip_forward</em> ma zawartość 1.
+<pre class="code-block">
+# cat /proc/sys/net/ipv4/ip_forward
+</pre>
+          Jeśli nie to mu ją wpisujemy:
+<pre class="code-block">
+# echo 1 &gt; /proc/sys/net/ipv4/ip_forward
+</pre>
+      </li>
+      <li><u>Debugowanie</u>
+          <p>
+            Nie wykluczone, że za pierwszym razem wszystko nie zadziała od razu.
+            Zostanie tutaj przedstawione kilka kroków, które przydają się 
+            podczas debugowania.
+          </p>
+          <ol>
+            <li>Sprawdzamy czy tunel w ogóle się zestawił - przeglądamy logi
+                programu <em>OpenVPN</em>. Sprawdzamy, czy program widnieje na 
+                liście procesów - za pomocą polecenia
+<pre class="code-block">
+# ps aux | grep vpn
+</pre>
+            </li>
+            <li>Sprawdzamy, czy interfejs br0 powstał po obu stronach tunelu.
+                Wpisujemy polecenie:
+<pre class="code-block">
+# ifconfig | grep br0
+</pre>
+            </li>
+            <li>Używając polecenia 
+                <code class="code-inline">brctl show br0</code>,
+                sprawdzamy, czy oba interfejsy 
+                (<code class="code-inline">tap0</code>
+                i <code class="code-inline">eth1</code>) widnieją na liście
+                interfejsów członkowskich na moście br0. Jeśli któregoś z nich
+                brakuje - dodajemy go, za pomocą polecenia:
+<pre class="code-block">
+# brctl addif &lt;interfejs&gt;
+</pre>
+            </li>
+            <li>Upewniamy się czy wszystkie interfejsy tworzące most działają w
+             trybie <em>promiscuos</em> (nasłuchiwania). Wpisujemy polecenia:
+<pre class="code-block">
+# ifconfig eth1 promisc
+# ifconfig tap0 promisc
+</pre>
+            </li>
+            <li>Możemy użyć programu <em>tcpdump</em>, do przeglądania 
+                pakietów pojawiających się na obu stronach mostu.</li>
+            <li>Możemy podglądać na bierząco jak most uczy się adresów MAC.
+                Listę adresów sprawdzamy poleceniem:
+<pre class="code-block">
+brctl showmacs br0
+</pre>
+            </li>
+            <li>Jeśli w dalszym ciągu nic nie działa, czasem dobrym 
+                rozwiązaniem jest zresetowanie komputerów i rozpoczęcie 
+                wszystkiego od nowa</li>
+            <li>Jeśli pracujemy zdalnie na odległym serwerze, dobrym 
+            rozwiązaniem będzie napisanie skryptu, który będzie pingował 
+            wybrany serwer co 20 min. W przypadku braku odpowiedzi, skrypt 
+            powinien zresetować serwer.</li>
+          </ol>
+      </li>
+    </ol>
+    <h3 id="ipsec">IPSec</h3>
+    <p>
+      <strong>IPSec</strong> (ang. <em>IP Security</em> - bezpieczeństwo w IP) -
+      to zestaw protokołów kryptograficznych opracowanych przez grupę IETF w
+      odpowiedzi na zapotrzebowanie rynku IT na bezpieczną komunikację sieciową
+      przez Internet.
+    </p>
+    <p>
+      Podstawowym założeniem przy projektowaniu IPSec było zapewnienie
+      integralności i poufności przesyłanych danych niezależnie od używanych
+      protokołów warstw wyższy modelu OSI (TCP/UDP itd.). Zapewnienie
+      integralności przesyłanych danych, czyli możliwości wykrycia tego, czy
+      pakiet nie został zmodyfikowany, osiągnięto poprzez stosowanie skrótów
+      kryptograficznych zamiast zwykłych sum kontrolnych w protokole IP, (które
+      można przeliczyć po modyfikacji pakietu). Poufność z kolei, zapewnia
+      szyfrowanie danych kluczem symetrycznym (np. DES, 3DES, AES). Przy czym
+      IPSec nie narzuca wyboru algorytmu szyfrowania, dzięki czemu protokół
+      jest bardzo uniwersalny. W razie złamania w przyszłości, któregoś z
+      obecnie używanych algorytmów wystarczy jego zamiana bez potrzeby
+      przebudowy całego protokołu.
+    </p>
+    <p>
+      IPSec może być wykorzystywany w jednym z dwóch trybów. Pierwszy to tryb
+      transportowy, w którym nagłówek IPSec wstawiany jest pomiędzy oryginalny
+      nagłówek IP a nagłówek warstwy transportowej. Tryb transportowy używany
+      jest pomiędzy dwoma hostami komunikującymi się przez IPSec. Drugim
+      rodzajem połączeń IPSec jest tryb tunelowy, w którym cały pierwotny
+      pakiet IP enkapsulowany jest wewnątrz nagłówka IPSec. Tryb tunelowy na
+      ogół wykorzystywany jest do łączenia całych sieci korporacyjnych z
+      wykorzystaniem bram VPN. W tym przypadku komputery w sieciach 
+      wewnętrznych "nie wiedzą" w ogóle o fakcie, że pakiety po opuszczeniu 
+      routera opakowane są w nagłówki IPSec i w zaszyfrowanej formie wędrują 
+      przez Internet. Brama VPN po drugiej stronie wyodrębnia pierwotne pakiety
+      IP i przesyła do właściwego hosta wewnątrz sieci lokalnej. Warto zauważyć,
+      że w trybie tunelowania w razie ewentualnego podsłuchu transmisji osoba 
+      podsłuchująca nie jest wstanie dowiedzieć się nawet, pomiędzy jakimi 
+      hostami wymieniane są dane. Adresy źródłowy i docelowy nagłówka IPSec 
+      zawierają adresy bram VPN, a nie rzeczywistych hostów.
+    </p>
+    <p>
+      Dwa podstawowe protokoły wchodzące w skład IPSec to AH i ESP. Protokół
+      AH (ang. <em>Authentication Header</em>) zapewnia integralność danych,
+      ale nie zapewnia poufności. Nie jest możliwy spoofing czy inna 
+      modyfikacja pakietu ponieważ suma kontrolna została zabezpieczona 
+      kryptograficznie (funkcją skrótu - metoda HMAC) przy użyciu tajnego 
+      klucza znanego tylko nadawcy i odbiorcy.
+    </p>
+    <p>
+      Przed właściwą komunikacją zabezpieczoną protokołem AH (lub ESP) strony
+      nawiązują logiczne połączenie w warstwie sieci, tworząc tzw. skojarzenie
+      bezpieczeństwa SA (ang. <em>Security Association</em>). SA charakteryzują
+      następujące elementy:
+    </p>
+    <ul>
+      <li>idetyfikator używanego protokołu bezpieczeństwa (AH lub ESP),</li>
+      <li>źródłowy i docelowy adres IP połączenia,</li>
+      <li>32-bitowa liczba będąca identyfikacją połączenia, określana mianem
+          SPI (ang. <em>Security Parameter Index</em>).</li>
+    </ul>
+    <p>
+      Skojarzenie bezpieczeństwa SA jest jednokierunkowe, dlatego do
+      bezpiecznej komunikacji dwustronnej potrzebne są dwa niezależne kanały
+      SA, po jednym w każdnym kierunku. Zauważmy jednak, że w pewnych
+      okolicznościach wystarczy zabezpieczenie tylko jednej strony (np.
+      odpowiedzi serwera DNS), stąd koncepcja "jednokierunkowości" połączeń
+      jest uzasadniona.
+    </p>
+    <p>
+      Z protokołem AH związane jest także pojęcie SN - <em>serial number</em>,
+      którego celem jest zabezpieczenie transmisji przez atakiem polegającym
+      na wielokrotnym przesyłaniu tego samego pakietu do odbiorcy przez hosta,
+      który podsłuchał pakiet (ang. <em>reply attack</em>). Na początku
+      komunikacji strony ustawiają wartość SN na <em>0</em>, a następnie
+      inkrementują ją wraz z każdym wysłanym pakietem. Dzięki temu odbiorca
+      może wykryć, że odebrany właśnie pakiet to kopia już wcześniej
+      otrzymanego.
+    </p>
+    <p>
+      Protokół ESP (ang. <em>Encapsulated Security Payload</em>) pierwotnie
+      zapewniał wyłącznie szyfrowanie transmisji przy użyciu któregoś z
+      szyfrów blokowych (DES, 3DES, AES). Dlatego dla zapewnienia integralności
+      i poufności danych wykorzystywano oba protokoły - AH i ESP - jednocześnie.
+    </p>
+    <p>
+      Obecnie jednak ESP zapewnia także sprawdzenia integralności danych
+      (zasada działania bardzo podobna do AH - suma kontrolna zabezpieczona
+      kryptograficznie), dlatego protokół AH wychodzi z użycia. W przypadku
+      gdy szyfrowanie transmisji nie jest konieczne, w ESP istnieje możliwość
+      zastosowania algorytmu NULL zamiast któregoś z algorytmów
+      kryptograficznych. Istotną różnicą między protokołami ESP i AH jest fakt,
+      że w przypadku ESP ochrona integralności nie obejmuje nagłówka IP (tego
+      widzianego przez pośredniczące routery), dzięki czemu protokół IPSec/ESP
+      może przechodzić przez połączenia za NAT-em.
+    </p>
+    <p>
+      Za automatyczną negocjację parametrów połączenia tj. uwierzytelnianie,
+      ustalenie relacji SA oraz późniejsze uzgadniania kluczy kryptograficznych
+      odpowiada osobny protokół wymiany kluczy - IKE
+      (ang. <em>Internet Key Exchange</em>), także wchodzący w skład IPSec .
+      Przy czym samo uwierzytelnienie może być przeprowadzone różnymi metodami
+      - współdzielony klucz, podpisy RSA, certyfikaty X.509 lub Kerberos.
+    </p>
+    <p>
+      Protokół IKE działa w dwóch fazach. Pierwsza faza - ISAKMP (ang. 
+      <em>Internet Security Association and Key Management Protocol</em>), 
+      odpowiada za przeprowadzenie uwierzytelnienia, utworzenie kanału ISAKMP 
+      SA i zarządzanie nim. Druga faza - Oakley, odpowiada za uzgadnianie klucz
+      (wg. algorytmu DH) i związków SA w trakcie połączenia.
+    </p>
+    <p>
+      ISAKMP może zostać przeprowadzona w trybie głównym (ang. 
+      <em>main mode</em>)
+      lub w tzw. trybie agresywnym (ang. <em>aggresive mode</em>). W trybie
+      głównym wymieniane są 3 dwukierunkowe komunikaty (komunikat-odpowiedź -
+      razem 6). W trybie agresywnym natomiast przesyłane są jedynie 3 
+      komunikaty.
+      Tryb agresywny jest szybszy, natomiast ma pewną słabość, którą w pewnych
+      okolicznościach można wykorzystać do odgadnięcia klucz PSK. Otóż w trybie
+      agresywnym cześć informacji przesyłana jest przez ustanowieniem
+      bezpiecznego kanału. W przypadku uwierzytelnienia przez PSK i użycia 
+      trybu
+      agresywnego osoba podsłuchująca transmisję jest w stanie podejrzeć hash
+      współdzielonego klucza, a następnie próbować odnaleźć klucz metodą
+      słownikową/siłową. Znając PSK, atakujący może zestawić tunel VPN, 
+      podszywając się pod pracownika firmy, którego połączenie wcześniej 
+      podsłuchał. Oprócz rozkodowania PSK możliwy jest w tym przypadku atak 
+      typu man-in-the-middle.
+    </p>
+    <p>
+      Z powyższego wynika, że powinniśmy unikać trybu agresywnego w połączeniu
+      z uwierzytelnianiem PSK. Ogólnie nie powinniśmy używać uwierzytelnienia
+      przez PSK dla tuneli zdalnych pracowników, gdzie IP drugiej strony tunelu
+      nie jest znane (możliwość siłowego odgadnięcia hasła).
+    </p>
+    <p>
+      Faza druga (Oakley) przebiega zawsze w trybie <em>quick mode</em>. Jako
+      że jest to faza druga, nie przeprowadza ona własnych metod 
+      uwierzytelnienia i umożliwia szybkie (stąd nazwa) zestawienie relacji 
+      IPSec SA.
+    </p>
+    <p>
+      Z drugą fazą związane jest także opcjonalne pojęcie PFS (ang. <em>Perfect
+      Forward Secrecy</em>) - poufność doskonała. Przez pojęcie to rozumie się
+      sposób wymiany kluczy sesyjnych w trakcie połączenia IPSec. Załączenie
+      PFS, zapewnia że materiał klucza głównego może być używany do 
+      wygenerowania tylko jednego klucza sesji. Przed utworzeniem nowego klucza
+      sesji jest przeprowadzana wymiana kluczy (algorytm Diffiego-Hellmana) w 
+      celu wygenerowania nowego materiału klucza głównego. Dzięki zastosowaniu 
+      PFS uzyskanie przez atakującego pojedynczego klucza pozwala mu na 
+      odczytanie tylko wiadomości zaszyfrowanych tym kluczem. Niestety, 
+      załączenie PFS wiąże się ze spadkiem wydajności (i wzrostem obciążenia 
+      procesora). Dodatkowo nie wszystkie implementacje obsługują tę właściwość.
+    </p>
+    <p>
+      Każda ze stron przechowuje informacje o nawiązanych skojarzeniach SA w
+      tzw. bazie SAD (ang. <em>Security Association Database</em>).
+    </p>
+    <p>
+      Do terminologi związanej z IPSec musimy jeszcze dołożyć pojęcia SPD -
+      <em>Security Policy Database</em>. SPD to baza odpowiadająca przyjętej
+      polityce bezpieczeństwa. Baza SPD jest używana dla pakietów wychodzących.
+      System sprawdza przed wysłaniem, czy dla określonego hosta docelowego
+      (sieci docelowej) istnieje jakiś wpis określający, czy protokół IPSec ma
+      zostać użyty. Jeżeli tak, przeglądana jest baza SAD w poszukiwaniu
+      skojarzenia SA odpowiedzialnego za komunikacje w określonym hostem
+      docelowym.
+    </p>
+    <h4>IPSec a translacja adresów (maskarada)</h4>
+    <p>
+      <strong>NAT</strong> (ang. <em>Network Address Transtalation</em>) to 
+      translacja adresów popularnie zwana maskaradą. Najkrócej mówiąc polega 
+      ona ukrywaniu hosta wewnętrznego poprzez zamianę adresu źródłowego w 
+      nagłówku pakietu IP - na adres routera. W tym przypadku NAT (a w zasadzie
+      PAT - <em>Port Address Translation</em>) stara się zachować port 
+      źródłowy, który został wybrany przez hosta źródłowego; dopiero gdy ten 
+      port jest zajęty przez inne połączenie NAT, zostanie zamieniony na inny. 
+      Router pełniący rolę NAT-u przechowuje wszystkie bieżące połączenia w 
+      specjalnej tabeli NAT, dzięki czemu wie, do którego hosta przekierować 
+      ma odpowiedzi przychodzące na dany port. Mechanizm ten doskonale sprawdza
+      się w przypadku połączeń TCP/UDP, gdzie bezproblemowo możemy przekierować
+      połączenie przychodzące na port 1234 do portu 5673 komputera wewnątrz 
+      sieci (za maskaradą).
+    </p>
+    <p>
+      W przypadku połączeń IPSec sprawa nie wygląda tak prosto z dwóch powodów.
+      Po pierwsze w przypadku protokołu AH nie jest możliwa zmiana adresu
+      źródłowego w nagłówku pakietu IP, gdyż cały nagłówek zabezpieczony jest
+      przed zmianą - do nagłówka dodawany jest skrót kryptograficzny utworzony
+      z sumy kontrolnej pakietu oraz tajnego hasła. Jakakolwiek modyfikacja
+      nagłówka pakietu uznana będzie za naruszenie integralności danych (router,
+      nie znając hasła nie będzie w stanie wygenerować odpowiedniego skrótu).
+      Na to nic nie poradzimy. Dla protokołu AH nie jest możliwa translacja
+      adresów.
+    </p>
+    <p>
+      W przypadku protokołu ESP sprawa wygląda lepiej, gdyż, ochronie 
+      integralności nie podlega "zewnętrzny" nagłówek IP, tak więc możliwa jest
+      zamiana źródłowego adresu IP. Pojawia się jednak niestety problem z 
+      wieloma klientami znajdującymi się za tym samym routerem (maskaradą). 
+      Protokół ESP nie wykorzystuje portów, jak ma to miejsce w protokołach TCP
+      i UDP, dlatego nie można w prosty sposób odróżnić połączeń IPSec 
+      inicjowanych z różnych hostów wewnątrz sieci.
+    </p>
+    <p>
+      Rozwiązanie powyższego problemu jest tzw. <strong>NAT-Traversal</strong>.
+      Mechanizm ten polega na enkapsulacji protokołu ESP wewnątrz połączenia
+      UDP (najczęściej port 4500)
+    </p>
+    <p>
+      Jak widać działanie protokołu IPSec (zespołu protokołów) jest dość 
+      złożone. Przedstawiono tutaj najistotniejsze elementy, tak aby poza 
+      posiadaniem wiedzy praktycznej, warto posiadać wiedzę teoretyczną, która 
+      to pomoże zrozumieć nam gdzie zrobiliśmy błąd, jeśli coś nie zadziała lub
+      nagle przestanie. Na szczęście konfiguracja połączenia IPSec z 
+      automatyczną wymianą kluczy (IKE) nie jest wcale taka trudna, co zostanie
+      zobrazowane.
+    </p>
+    <h4>Najważniejsze pojęcia związane z IPSec</h4>
+    <ul>
+      <li><strong>Protokół ESP (ang. <em>Encapsulated Security Payload</em>)</strong>
+          - podstawowy składnik IPSec. Pierwotnie zapewniał wyłączenie poufność,
+            tj. szyfrowanie transmisji przy użyciu któregoś z szyfrów blokowych
+            (DES, 3DES, AES). Obecnie jednak ESP zapewnia także sprawdzenie
+            integralności danych. ESP w przeciwieństwie do AH nie zabezpiecza
+            nagłówka IP pierwotnego pakietu,</li>
+      <li><strong>Protokół AH (ang. Authentication Header)</strong> - jeden z
+          protokołów wchodzących w skład IPSec. Jego zadaniem jest zapewnienie
+          integralności przesyłanych danych (funkcja skrótu HMAC). Protokół AH
+          nie zapewnia poufności. Wychodzi on obecnie z użycia, ponieważ ESP
+          zapewnia tę samą funkcjonalność oraz szyfrowanie,</li>
+      <li><strong>Protokół ISAKMP (ang. <em>Internet Security Association and
+          Key Management Protocol</em>)</strong> - odpowiada za negocjacje
+          parametrów IPSec, przeprowadzenie uwierzytelnienia, tworzenia kanału
+          SA i zarządzanie nim. Do działania wykorzystuje port 500 UDP,</li>
+      <li><strong>Związek SA (ang. <em>Security Association</em>) </strong>-
+          inaczej relacja SA, jednokierunkowy, logiczny kanał komunikacyjny
+          zestawiany w komunikacji IPSec. Do dwustronnej komunikacji IPSec
+          potrzebne są dwa kanały SA. Skojarzenie SA identyfikowane jest przez
+          32-bitową liczbę zwaną SPI (ang. <em>Security Parametr Index</em>),</li>
+      <li><strong>SPI (ang. <em>Security Parametr Index</em>)</strong> -
+          32-bitowa liczba, będąca identyfikatorem skojarzenia SA w komunikacji
+          IPSec,</li>
+      <li><strong>Baza SAD</strong> - każda ze stron tunelu IPSec przechowuje
+          informacje o nawiązanych relacjach SA w tzw. bazie SAD,</li>
+      <li><strong>DH (<em>Diffie-Hellman</em>) </strong>- algorytm uzgadniania
+          klucza, w którym dwie strony na podstawie wymienionych liczb 
+          uzgadniają liczbę wynikową - klucz. Osoba podsłuchująca transmisje 
+          nie jest w stanie na podstawie tego co usłyszała, wyliczyć klucza,</li>
+      <li><strong>Grupa DH</strong> - informacja mówiąca o wielkości liczb
+          używanych w obliczeniach w algorytmie Diffiego-Hellmana. DH1:768bitów,
+          DH2:1024bity, DH5:1536 bitów. Grupa pierwsza obecnie uważna jest za
+          słabą,</li>
+      <li><strong>Hash</strong> - inaczej funkcja skrótu. Dla dowolnie długiego
+          ciągu wejściowego wyliczany jest skrót o stałej długości. Do
+          najczęściej używanych funkcji należą MD5 i SHA-1, SHA-2. Funkcje 
+          skrótu wykorzystywane są do tworzenia sygnatur (np. cyfrowe 
+          zabezpieczenie sumy kontrolnej pakietu lub pliku),</li>
+      <li><strong>HMAC (ang. <em>keyed-Hash Message Authentication Code</em>)
+          </strong> - zabezpieczona hasłem funkcja skrótu. Dzięki temu oprócz 
+          ochrony integralności zapewniona jest też autentyczność pochodzenia. 
+          Osoba zabezpieczająca dokument podaje hasło i na podstawie hasła oraz
+          dokumentu tworzony jest skrót. Osoba sprawdzająca znając hasło, jest
+          w stanie potwierdzić autentyczność,</li>
+      <li><strong>SHA (SHA-1, SHA-2)</strong> - funkcje skrótu służące to
+          tworzenia sygnatur,</li>
+      <li><strong>MD5</strong> - funkcja skrótu, w wyniku której powstaje
+          128-bitowy hash,</li>
+      <li><strong>DES (ang. <em>Data Encryption Standard</em>)</strong> -
+          algorytm szyfrowania symetrycznego. Ze względu na słabość klucza -
+          56 bitów - obecnie wyszedł z użycia. Jego następcy to 3DES oraz AES,</li>
+      <li><strong>AES (ang. <em>Adavanced Encryption Standard</em>) </strong>
+          - silny szyfr blokowy, możliwe długości klucza to 128, 192, 256 bitów.
+          Powstał w wyniku konkursu na następcę DES. Obecnie często
+          wykorzystywany w kryptografii. m.in w IPSec,</li>
+      <li><strong>RSA</strong> - jeden z algorytmów kryptografii asymetrycznej,
+          stosowany m.in. w podpisach cyfrowych,</li>
+      <li><strong>Transform-set</strong> - w terminologii Cisco zbiór 
+          parametrów związanych z połączeniem IPSec. Do parametrów metrów tych 
+          należą m.in.: rozdzaj protokołu IPSec (ESP, AH) używany protokół 
+          szyfrowania (3DES, AES), używana funkcja skrótu (SHA, MD5) itp,</li>
+      <li><strong>Crypto-map</strong> - w terminologii Cisco to ustawienie,
+          które wiąże niejako wszystkie parametry tunelu w całość. Zawiera 
+          nazwę <em>transform-seta</em> (parametry IPSec), adres IP zdalnego 
+          routera oraz numer listy dostępu, kontrolującej jaki ruch zostanie 
+          przesłany tunelem VPN.</li>
+    </ul>
+    <p>
+      W niniejszym artykule zostanie omówione przygotowanie systemu do 
+      działania z protokołem IPSec.
+    </p>
+    <h4 id="ipsec_linux">IPSec - przygotowanie środowiska w systemie Linux</h4>
+    <p>
+      Z punktu wiedzenia systemu operacyjnego połączenia IPSec można podzielić 
+      na dwie części:
+    </p>
+    <ol>
+      <li>Część odpowiedzialną za zarządzanie pakietami (protokół AH/ESP) - tj.
+          enkapsulację pakietów IP w pakiety IPSec, zabezpieczenie sum 
+          kontrolnych itd. Z racji tego, że operacje te muszą być wydajne, ich
+          obsługą zajmują się moduły jądra systemu.</li>
+      <li>Część odpowiedzialną za zestawienie połączenia i późniejszą wymianę 
+          kluczy (protokół IKE). Obsługę tych funkcji zajmuje się program 
+          (daemon) działający w warstwie użytkownika - w systemie Linux to 
+          demon Pluto (wchodzący w skład OpenSWAN).</li>
+    </ol>
+    <p>
+      Obecnie każde współczesne jądro Linuxa ma już wbudowane moduły dla 
+      protokołu IPSec. Nie potrzeby przeprowadzania żadnych modyfikacji. 
+    </p>
+    <h4>Instalacja programu OpenSWAN</h4>
+    <p>
+      <strong>OpenSWAN</strong> to implementacja protokołu IPSec w systemie 
+      Linux rozwijana 
+      przez grupę developerów, którzy wcześniej pracowali nad projektem 
+      <em>FreeSWAN</em>. W trakcie prac doszło do konfliktu i część deweloperów 
+      rozpoczęła pracę nad <em>OpenSWAN</em>.
+    </p>
+    <p>
+      Jeżeli używana przez nas dystrybucja wspiera automatyczną instalację 
+      pakietów, możesz zainstalować program <em>OpenSWAN</em> z gotowych paczek.
+      W przypadku Debian możesz zastosować pakiet używając programu 
+      <em>apt</em>.
+    </p>
+    <p>
+      Opcjonalnym składnikiem, który należałoby zainstalować jest serwer L2TP -
+      najlepiej <em>xl2tpd</em>. Dlaczego opcjonalnym? Gdyż nie wszystkie 
+      rozwiązania IPSec używają tunelowania L2TP. Niemniej implementacja IPSec 
+      firmy Microsoft wbudowana w każdy z systemów Windows wymaga do działania 
+      właśnie protokołu L2TP. Jeśli zamierzamy łączyć z bramą VPN, używając 
+      wbudowanych w Windows mechanizmów IPSec, musimy zainstalować demon L2TP.
+    </p>
+    <p>
+      Protokół L2TP umożliwia przesłanie ramek połączenia PPP przez przez 
+      protokół IP (Internet), które to połączenie normalnie realizowane jest 
+      tylko w bezpośrednim połączeniu punkt-punkt (modemy, linie szeregowe 
+      itd.). Samo połączenie PPP operuje w warstwie drugiej modelu OSI i służy 
+      do enkapsulacji protokołów warstwy wyższej (IP, IPX itd.), zapewniając 
+      jednocześnie uwierzytelnienie oraz kompresję. Połączenie protokołu L2TP 
+      z PPP umożliwia tunelowanie protokołu IP w ramach innego połączenia IP, 
+      dlatego często wykorzystywane jest w sieciach VPN. Wykorzystanie protokołu
+      PPP daje także dodatkowe możliwości, jak np. przydzielanie adresów IP
+      tunelowi, przekazywanie parametrów sieciowych, takich jak DNS, WINS itp.
+    </p>
+    <p>
+      Naturalnie aby tunelowanie połączenia PPP przez protokół L2TP mogło 
+      działać, potrzebny jest także demon PPP. Jako że nie jest już instalowany
+      domyślnie w popularnych dystrybucjach możemy go zainstalować z 
+      repozytorium dystrybucji, dla Debiana możemy skorzystać z polecenia 
+      <em>apt</em>
+    </p>
+    <h4>Praktyczny przykład - brama IPSec/VPN dla użytkowników mobilnych</h4>
+    <p>
+      W tej sekcji stworzymy bramę VPN dla użytkowników mobilnych łączących 
+      się zdalnie z siedzibą firmy. Użytkownicy używają na laptopach systemu 
+      Microsoft Windows i wbudowanego weń "klienta" IPSec. Analogicznie jak dla
+      przykładu z bramą OpenVPN, użytkownicy powinni mieć dostęp do kilku 
+      serwerów w sieci LAN. Adresy IP użytkowników mobilnych nie są znane i
+      mogą oni się łączyć z różnych miejsc, także zza maskarady (połączenia 
+      GPRS, hotspot itd.). Po stronie bramy VPN wykorzystamy system Linux oraz
+      oprogramowanie <em>OpenSWAN</em>.
+    </p>
+    <h5>Konfiguracja bramy IPSec (Linux)</h5>
+    <p>
+      Konfigurację zaczniemy od przygotowania demona L2TP. Tworzymy plik 
+      konfiguracyjny <code>/etc/l2tp/l2tpd.conf</code>. Zawartość pliku 
+      <em>l2tpd.conf</em> powinna wyglądać następująco:
+    </p>
+<pre class="code-block">
+[global]
+ listen-addr = 85.98.29.251                   ;adres internetowy bramy
+ port = 1701                                  ;port — zostawiamy domyślny
+[lns default]
+ip range = 192.168.10.198-192.168.10.250      ;pula IP dla klientów
+local ip = 85.98.29.251                       ;IP lokalny połączenia PPP
+require chap = yes                            ;wymagamy uwierzytelniania CHAP
+;refuse pap = yes
+require authentication = yes
+name = ipsec
+ppp debug = yes
+pppoptfile = /etc/ppp/options.l2tpd           ;pozostały
+length bit = yes
+</pre>
+    <p>
+      Zwrócić należy uwagę na wymóg uwierzytelniania dotyczy tutaj połączenia 
+      PPP a nie L2TP. Demon L2TP nie możliwości przeprowadzenia swojego
+      uwierzytelniania, ale nie jest to w tym przypadku potrzebne. 
+    </p>
+    <p>
+      Teraz tworzymy plik z opcjami programu <em>pppd</em> - 
+      <em>/etc/ppp/options.l2tpd</em>. Przykładową konfigurację
+      przedstawiono poniżej.
+    </p>
+<pre class="code-block">
+ipcp-accept-local             ; pppd zaakceptuje lokalny adres połączenia
+ipcp-accept-remote            ; jw. dla adresu drugiej strony
+require-mschap-v2             ; wymagamy uwierzytelniania MSCHAP wersji drugiej
+auth
+proxyarp
+idle 1800
+mtu 500
+mru 500
+# eof
+</pre>
+    <p>
+      Następnie konfigurujemy plik z danymi uwierzytelniającymi dla PPP - 
+      <em>/etc/ppp/chap-secrets</em>
+    </p>
+<pre class="code-block">
+# Secrets for authentication using CHAP
+# client        server  secret                  IP addresses
+user      *    "test"
+</pre>
+    <p>
+      gdzie <code class="code-inline">user</code> to nazwa użytkownika a 
+      <code class="code-inline">"test"</code> - hasło.
+    </p>
+    <p>
+      W sytuacji gdyby PPP było jedynym uwierzytelnieniem, moglibyśmy wpisać do
+      pliku <em>chap-secrets</em> wszystkich użytkowników. Nie ma to jednak 
+      sensu, gdyż podstawowym uwierzytelnieniem będą certyfikaty X.509. Niemniej
+      konfiguracje PPP można wykorzystać do przypisywania stałych adresów IP 
+      dla poszczególnych klientów, np.:
+    </p> 
+<pre class="code-block">
+jacek * "test12" 192.168.10.220
+michal * "test13" 192.168.10.221
+</pre>
+    <p>
+      Ostatni element przygotowania bramy IPSec to właściwa konfiguracja 
+      programu <em>OpenSWAN</em>, która sprowadza się w najprostszym przypadku 
+      do edycji dwóch plików - <em>ipsec.conf</em> oraz <em>ipsec.secrets</em>.
+      Poniżej został przedstawiony plik <em>ipsec.conf</em> W tym przypadku 
+      metodą uwierzytelnienia jest klucz współdzielony a klientami mogą być 
+      użytkownicy Windowsa znajdujący się za NAT-em.
+    </p>
+
+<pre class="code-block">
+version 2.0
+config setup
+        interfaces=%defaultroute
+        plutodebug=none
+        forwardcontrol=yes
+        nat_traversal=yes
+virtual_private=%v4:10.0.0.0/8,%v4:172.16.0.0/12,%v4:192.168.0.0/16,%v4:!192.168.10.0/24
+conn roadwarrior-l2tp
+        leftprotoport=17/1701
+        rightprotoport=17/1701
+        also=roadwarrior
+conn roadwarrior
+        auth=esp
+        authby=secret
+        compress=yes
+        keyexchange=ike
+        keyingtries=3
+        pfs=no
+        rekey=yes
+        left=%defaultroute
+        right=%any
+        rightsubnet=vhost:%no,%priv
+        auto=add
+#Disable Opportunistic Encryption
+include /etc/ipsec.d/examples/no_oe.conf
+</pre>
+    <p>
+      Twórcy programu <em>OpenSWAN</em> przyjęli konwencję, aby stron 
+      połączenia nie nazywać w klasyczny sposób: "serwer" i "klient" (lub też 
+      "źródło" i "cel"), tylko "strona lewa" (ang. <em>left</em>) i 
+      "strona prawa" (ang. <em>right</em>). Ma to swoje uzasadnieniem, ponieważ
+      tak naprawdę i tak zestawiane są dwa nie zależne skojarzenia SA - dla 
+      każdego z kierunków transmisji. Poza tym nie zawsze jest jasne, która 
+      strona jest bardziej serwerem, a która bardziej klientem (przykład 
+      łączenia oddziałów firm). Przez "left" rozumie się lokalną konfigurację, 
+      a przez "right" odległą stronę. Zauważyć warto, że w przypadku połączenia
+      typu użytkownik mobilny-brama IPSec, patrząc od strony bramy IPSec, 
+      strona "right" najczęściej nie jest znana (nie znamy adresu IP, z którego
+      będzie łączyć się użytkownik). W przypadku łączenia dwóch bram IPSec 
+      (łączenie oddziałów firmy) strony "left" i "right" są na ogół ściśle
+      określone. W anglojęzycznej terminologii pracowników mobilnych, który
+      łączą się z rożnych miejsc kraju i świata, przyjęło nazwywać się 
+      <em>roadwarrior</em>.
+    </p>
+    <p>
+      Poniżej znajduje się analiza najważniejszych wpisów z pliku 
+      konfiguracyjnego. Plik jest podzielony na kilka sekcji. Podstawowe opcje
+      - tzw. globalne - są zwarte w sekcji <code class="code-inline">
+      config setup</code>.
+    </p>
+    <ul>
+      <li><code class="code-inline">version 2.0</code> - informuje program 
+          <em>OpenSWAN</em>, że 
+          składnia pliku będzie zgodna z <em>OpenSWAN</em>, a nie z 
+          przestarzałym FreeSWAN.</li>
+      <li><code class="code-inline">interfaces=%defaultroute</code> - oznacza 
+          interfejs, na którym ma działać IPSec. Wartość domyślna to 
+          <code class="code-inline">%defaultroute</code>, co oznacza, że 
+          zostanie użyty adres IP bramy domyślnej komputera. Na ogół 
+          <code class="code-inline">%defaultroute</code> jest poprawną 
+          wartością.</li>
+      <li><code class="code-inline">plutodebug=none</code> - definiuje poziom 
+          szczegółowości logów demona <em>pluto</em>. Inne możliwe wartości to:
+          <em>all, raw, krypt, parsing, emitting, control</em>. Najbardziej 
+          optymalną jest opcja <em>control</em>, gdy logi nie będą nam już 
+          potrzebne, to przełączamy na <code class="code-inline">none</code>.</li>
+      <li><code class="code-inline">forwardcontrol=yes|no</code> - sprawdza, 
+          czy załączone jest przekazywanie pakietów IP (ang. <em>IP 
+          forwarding</em>). Jeżeli nie, to je załącza. Po zakończeniu działania
+          tunelu przywraca poprzednią wartość.</li>
+      <li><code class="code-inline">nat_traversal=yes|no</code> - domyślnie: 
+          <code class="code-inline">no</code>. Ważna opcja, jeżeli spodziewasz 
+          się połączeń zza NAT-a (maskarady). Złączenie jej sprawi, że 
+          <em>OpenSWAN</em> będzie oczekiwał także połączeń na porcie UDP 4500,
+          po którym przenoszone są pakiety IPSec.</li>
+      <li><code class="code-inline">virtual_private</code> - określa podsieci 
+          (z zakresu "prywatnych" klas IP), z których mogą łączyć się klienci. 
+          Na ogół podaje się tutaj wszystkie pule IP zdefiniowane do użytku 
+          prywatnego, z wyjątkiem puli używanej w sieci firmowej, do której 
+          użytkownicy chcą mieć dostęp przez VPN.</li>
+    </ul>
+    <p>
+      Sekcja <code class="code-inline">conn roadwarrior-l2tp</code> - 
+      odpowiedzialna za połączenia L2TP (port UDP/1701). Jest ona potrzebna, 
+      jeśli oczekujemy połączeń od klientów wbudowanych w systemy Windows. 
+      Ważne jest, aby sekcja L2TP umieszczona była w pliku przed właściwą 
+      sekcją odpowiedzialną za połączenia klientów. 
+      (<code class="code-inline">conn roadwarrior</code>).
+    </p>
+    <ul>
+      <li><code class="code-inline">conn roadwarrior</code> - właściwa sekcja 
+          połączeń dla pracowników zdalnych.</li>
+      <li><code class="code-inline">auth=esp</code> - określa protokół IPSec. 
+          Możliwe opcje to <em>ah</em> lub <code class="code-inline">esp</code>.
+          Zalecaną metodą jest ESP, ponieważ obsługuje uwierzytelnienie i 
+          szyfrowanie.</li>
+      <li><code class="code-inline">authby=secret</code> - określa sposób 
+          uwierzytelnienia stron. Wartość <code class="code-inline">secret</code>
+          oznacza współdzielony klucz (PSK). W przypadku uwierzytelnienia z 
+          wykorzystaniem certyfikatów opcja powinna mieć wartość 
+          <em>rsasig</em></li>
+      <li><code class="code-inline">compress=yes</code> - możliwa kompresja 
+          danych.</li>
+      <li><code class="code-inline">keyexchange=ike</code> - wartość 
+          <code class="code-inline">ike</code> oznacza, że do uzgodnienia 
+          kluczy zostanie użyty protokół IKE (Internet Key Exchange). Użycie 
+          IKE jest zalecane, także przez twórców <em>OpenSWAN</em>.</li>
+      <li><code class="code-inline">keyingtries=3</code> - określa, ile prób 
+          negocjacji SA może nastąpić (maksymalnie).</li>
+      <li><code class="code-inline">pfs=yes|no</code> - włącza 
+          (<code class="code-inline">yes</code>) lub 
+          wyłącza (<code class="code-inline">no</code>) PFS.</li>
+      <li><code class="code-inline">rekey=yes</code> - określa, czy połączenie 
+          po wygaśnięciu powinno być renegocjowane. Możliwe wartości to 
+          <code class="code-inline">yes</code> lub 
+          <em>no</em>. Domyślnie <code class="code-inline">yes</code>.</li>
+      <li><code class="code-inline">right=%any</code> - określa adres drugiej 
+          strony. Słowo kluczowe <code class="code-inline">%any</code> oznacza, 
+          że adres IP nie jest znany (przypadek mobilnych pracowników).</li>
+      <li><code class="code-inline">rightsubnet=vhost:%no,%priv</code> - opcja 
+          <code class="code-inline">rightsubnet</code> określa podsieć drugiej 
+          strony. W przypadku połączeń typu <code>roadwarriors</code> z 
+          możliwym NAT-em oraz "nie NAT-em" powinna mieć wartość 
+          <code class="code-inline">vhost:%no,%priv</code> Przez NAT oraz 
+          "nie NAT" należy rozumieć że użytkownicy mogą łączyć się zza NAT-u 
+          lub też mieć "zewnętrzny" adres IP i obie konfiguracje będą działać 
+          jednocześnie.</li>
+      <li><code class="code-inline">auto=add</code> - opcja przyjmuje wartości: 
+          <em>start, add, ignore</em>(domyślna!) oraz <em>manual</em>. 
+          Znaczenie poszczególnych opcji jest następujące: 
+          <ul>
+            <li><em>start</em> - załaduj konfigurację i inicjuj połączenie z 
+                druga stroną. Wartość najczęściej używana w przypadku połączeń 
+                dwóch routerów lub jeśli strona jest klientem (ma inicjować 
+                połączenie z drugą stroną).</li>
+            <li><em>add</em> - załaduj konfiguracje i odpowiadaj na 
+                przychodzące połączenia (czekaj na połączenia od drugiej 
+                strony). Wartość używana dla konfiguracji typu 
+                <em>roadwarriors</em> - nie znamy ani czasu, ani adresu IP, z 
+                jakiego połączy się mobilny pracownik. Jedyne, co możemy zrobić
+                odpowiedzieć na jego połączenia.</li>
+            <li><em>ignore</em> - ignoruje sekcję tego połączenia. Uwaga: jest 
+                to wartość domyślna, dlatego musisz przypisać jakąś wartość 
+                sekcjom, które mają działać.</li>
+            <li><em>manual</em> - opcja używana przy ręcznej konfiguracji 
+                wymiany kluczy (zamiast użycia IKE). Opcja niepolecana.</li>
+          </ul></li>
+    </ul>
+    <p>
+      W ostatniej linijce pliku konfiguracyjnego widzimy dołączony plik:
+    </p>
+<pre class="code-block">
+#Disable Opportunistic Encryption
+include /etc/ipsec.d/examples/no_oe.conf
+</pre>
+    <p>
+      Dołączenie powyższego pliku wyłącza tzw. szyfrowanie oportunistyczne, 
+      które w tym przypadku nie jest potrzebne (strony uwierzytelniają się w 
+      inny sposób), a pozostawienie go załączonego skutkowałoby serią 
+      komunikatów w logach systemowych, mówiących o nie możliwości sprawdzenia 
+      informacji w DNS-ie. Idea szyfrowania oportunistycznego polega na 
+      możliwości uwierzytelnienia dowolnych hostów w internecie bez 
+      wcześniejszej wymiany tajnego klucza, (lub kluczy publicznych), 
+      Uwierzytelnienia hosta odbywa się tutaj na podstawie informacji 
+      pobranych z bezpiecznych serwerów DNS (ang. <em>Secure DNS</em>).
+    </p>
+    <p>
+      Ogólna uwaga odnośnie składni pliku <em>ipsec.conf</em>. Należy pamiętać 
+      aby pomiędzy sekcjami połączeń była jedna linijka przerwy. Nazwa sekcji 
+      nie powinna się zaczynać od spacji czy tabulacji. Opcje w ramach sekcji 
+      mogą zaczynać się od tabulacji.
+    </p>
+    <p>
+      Pozostał nam jeszcze do konfiguracji plik <em>/etc/ipsec.secrets</em>. W 
+      przypadku współdzielonego klucza oraz połączeń z nie znanych adresów IP 
+      składnia pliku jest następująca:
+    </p>
+<pre class="code-block">
+&lt;adres_ip_odpowiednik_%defaultroute&gt; %any: PSK "&lt;klucz_współdzielony&gt;"
+</pre>
+    <p>
+      Po zapisaniu pliku, należy zmienić uprawnienia, tak aby możliwość odczytu
+      pliku miał tylko użytkownik <em>root</em> (<code class="code-inline">
+      chmod 600</code>).
+    </p>
+    <h5>Uruchomienie tunelu</h5>
+    <p>
+      Aby uruchomić tunel (proces nasłuchiwania), wpisujemy poniższe polecenie:
+    </p>
+<pre class="code-block">
+# ipsec setup start
+</pre>
+    <h4>Konfiguracja klienta Windows</h4>
+    <p>
+       W tej sekcji zajmiemy się konfiguracją połączenia IPSec w systemach 
+       Windows, tak aby ich użytkownicy mogli się połączyć z naszą bramą 
+       Linuksową. Metodą uwierzytelnienia będzie klucz współdzielony oraz 
+       dodatkowe uwierzytelnianie w połączeniu PPP (MS-CHAP v2). Do połączenia 
+       będziemy używać wbudowanego w Windows klienta IPSec. W nowszych 
+       systemach Windows konfiguracja sprowadza się dodania nowego połączenia 
+       przy użyciu kreatora. Aby dodać nowe połączenie, wykonujemy poniższe 
+       czynności:
+    </p>
+    <ol>
+      <li>Wchodzimy do <em>Panelu sterowania</em> i wybieramy 
+          <em>Połączenia sieciowe</em>,</li>
+      <li>Uruchom <em>Kreatora nowego połączenia</em>. Kreator zapyta o rodzaj 
+          połączenia - wybieramy opcje "Połącz z siecią w miejscu pracy". 
+          Następnie klikamy przycisk <em>Dalej</em>,</li>
+      <li>W następnym kroku wybieramy opcje <em>Połączenie wirtualnej sieci 
+          prywatnej</em>, następnie klikamy przycisk <em>Dalej</em>,</li>
+      <li>Wpisujemy nazwę połączenia np. <code>ipsec1</code>,</li>
+      <li>Podajemy adres IP lub nazwę DNS bramy VPN</li>
+      <li>Kończymy pracę kreatora, klikając przycisk <em>Zakończ</em>.
+          Przed uruchomieniem naszego połączenia trzeba zmodyfikować dwie opcje. 
+          Wchodzimy we właściwości nowego połączenia - klikamy prawym 
+          przyciskiem myszy ikonę nowego połączenia i wybieramy z menu opcje 
+          <em>Właściwości</em>. Postępujemy wg. poniższych punktów,</li>
+      <li>Przechodzimy do zakładki <em>Zabezpieczenia</em> i wybieramy opcje 
+          <em>Ustawienia protokołu IPSec</em>,</li>
+      <li>Zaznaczamy opcje <em>Użyj klucza wstępnego do uwierzytelniania</em> 
+          oraz wpisujemy w polu <em>Klucz:</em> hasło podane w pliku 
+          <em>/etc/ipsec.secrets</em> na Linuksie. Zatwierdzamy przyciskiem 
+          <em>OK</em>,</li>
+      <li>Następnie przechodzimy do zakładki <em>Sieć</em> i zmieniamy wartość 
+          pola <em>Typ wirtualnej sieci prywatnej (VPN)</em> z 
+          <em>Automatyczny</em> na <em>Sieć VPN a protokołem L2TP IPSec</em>,</li>
+      <li>Zapisujemy zmiany.</li>
+    </ol>
+    <p>
+      W tej chwili możemy połączyć się z bramą IPSec. Klikamy dwukrotnie myszką
+      na ikonę połączenia VPN. W oknie dialogowym podajemy nazwę użytkownika i 
+      hasło, a następnie klikamy przycisk <em>Połącz</em>. Nazwa użytkownika i 
+      hasło to oczywiście dane uwierzytelniające połączenie PPP 
+      (patrz plik <em>/etc/ppp/chap-secrets</em> na Linuksie).
+    </p>
+    <h4>Debugowanie połączenia</h4>
+    <p>
+      Jeśli wykonaliśmy wszystkie kroki z poprzednich punktów połączenie 
+      powinno zadziałać od razu. W praktyce pewnie pojawią się jakieś 
+      komplikacje. W tej sekcji zostanie podanych kilka porad dotyczących tego,
+      jak znaleźć błąd.
+    </p>
+    <p>
+      W przypadku połączeń Windows-Linux (<em>OpenSWAN</em>) opartych na PSK 
+      błąd wystąpi prawdopodobnie gdzieś po stronie Linuksa. Konfiguracja 
+      Windowsa jest bowiem tak prosta, że trudno byłoby w niej coś zrobić źle.
+    </p>
+    <p>
+      Zaczynamy od przekierowania wszystkich logów systemowych do jednego pliku,
+      aby łatwiej było podglądać na bieżąco, co się dzieje. Dlaczego wszystkie 
+      do jednego pliku? Otóż dlatego że IPSec nie składa się z jednego demona, 
+      jest ich wiele, wiec wygodniej jest przeglądać jeden plik niż wiele. Aby 
+      przekierować wszystkie logi wpisujemy do pliku <em>/etc/syslog.conf</em> 
+      poniższą linijkę:
+<pre class="code-block">
+*.*    /var/log/all
+</pre>
+    <p>
+      Następnie przeładowujemy konfiguracje demona Syslog. Wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+killall -HUP syslogd
+</pre>
+    <p>
+      W środowisku produkcyjnym plik na serwerze może szybko przyrastać. Należy
+      pamiętać, aby po zakończonych testach usunąć wpis z konfiguracji Sysloga.
+      Łączymy sie z serwerem z innej konsoli, lub jeśli pracujemy lokalnie,
+      przełączamy się na drugą konsolę). Wpisujemy polecenie:
+    </p>
+<pre class="code-block">
+tail -f /var/log/all
+</pre>
+    <p> 
+      Na tej konsoli będziesz miał stały podgląd logów systemowych. Jeśli na 
+      serwerze działają inne usługi, które możemy wyłączyć (np. poczta, czy 
+      dhcp), zróbmy to - im mniej logów, tym łatwiej je przeglądać. Przełączamy
+      się na pierwszą konsolę i sprawdzamy następujące rzeczy:
+    </p>
+    <ol>
+      <li>Czy działa demon L2TP - wpisujemy polecenie: 
+<pre class="code-block">
+# ps -aux | grep "l2tp"
+</pre>
+          Powinniśmy zobaczyć proces. Jeśli nie działa - uruchamiamy go 
+          wpisując polecenie: 
+<pre class="code-block">
+# xl2tpd
+</pre> 
+          Sprawdzamy ponownie, czy widnieje na liście procesów. Jeżeli nie - 
+          sprawdzamy co mówią logi na drugiej konsoli.</li>
+      <li>Sprawdzamy poleceniem <code class="code-inline">netstat</code>, czy 
+          serwer nasłuchuje na portach 4500 (NAT Traversal), 500 (Pluto - IKE) 
+          oraz 1701 (L2TP). W tym celu wpisujemy polecenie: 
+<pre class="code-block">
+netstat -anp | grep udp
+</pre>
+          Powinniśmy zobaczyć nasłuchujące procesy powiązane z danymi portami.</li>
+      <li>Upewniamy się, czy firewall nie blokuje potrzebnych portów UDP oraz 
+          protokołu ESP. Najlepiej na czas testów w ogóle wyłączyć firewall, 
+          tzn. ustawiamy domyślną politykę zapory na <em>ACCEPT</em>.</li>
+      <li>Sprawdzamy, czy w systemie na pewno jest zainstalowany program 
+          <code class="code-inline">pppd</code> - wpisujemy polecenie: 
+<pre class="code-block">
+which pppd
+</pre>
+      </li>
+      <li>Upewnijmy się, że w pliku <em>ipsec.conf</em> widnieje wpis 
+          <code class="code-inline">pfs=no</code>, który oznacza, że PFS nie 
+          jest konieczne (możliwe gdy druga strona to obsługuje). Implementacja
+          Microsoftu nie obsługuje PFS, dlatego nie możemy go wymuszać.</li>
+    </ol>
+    <p>
+      Po stronie Windowsa debugowanie jest utrudnione z racji braku "sysloga". 
+      Można jedna zainstalować program <em>Wireshark</em> - bardzo dobry 
+      sniffer sieciowy - i analizować nim fazy połączenia. W przypadku Windows,
+      należy upewnić się że żaden program typu firewall nie blokuje połączenia 
+      zwłaszcza takie kombajny jak różne pakiety "Internet Security".
+    </p>
+    <h4>Konfiguracja z uwierzytelnianiem przez certyfikat</h4>
+    <p>
+      W tej sekcji utworzymy bramę IPSec dla mobilnych użytkowników, z tą tylko
+      różnicą, że do uwierzytelnienia użyjemy certyfikatów X.509, a nie klucza 
+      współdzielonego. Konfiguracja taka jest zdecydowanie bardziej zalecana 
+      przy zdalnym dostępie pracowników, gdyż umożliwia w razie potrzeby 
+      unieważnienie certyfikatu użytkownikowi.
+    </p>
+    <p>
+      Zakładamy tutaj że mamy już wygenerowane klucze i certyfikaty dla serwera
+      i użytkownika (na razie jeden użytkownik wystarczy).
+    </p>
+    <p>
+      Konfiguracja po stronie Linuksa (bramy VPN) znacząco się nie różni -  
+      więcej pracy będzie w systemie Windows.
+    </p>
+    <h5>Konfiguracja OpenSWAN z wykorzystaniem certyfikatów.</h5>
+    <p>
+      Po stronie Linuksa - w stosunku do konfiguracji z użyciem PSK - zmianie 
+      ulegają tylko pliki <em>ipsec.conf</em> oraz <em>ipsec.secrets</em>, 
+      pozostałe konfiguracje pozostają identyczne (demon L2TP, konfiguracja 
+      <em>pppd</em>).
+    </p>
+    <p>
+      Konfiguracje wykonujemy wg. następujących punktów:
+    </p>
+    <ol>
+      <li>Zapisujemy klucz prywatny serwera jako: 
+          <em>/etc/ipsec.d/private/serverkey.pem</em></li>
+      <li>Zapisujemy certyfikat serwera jako 
+          <em>/etc/ipsec.d/certs/servercrt.pem</em></li>
+      <li>Zapisujemy certyfikat CA jako 
+          <em>/etc/ipsec.d/cacerts/cacert.pem</em></li>
+      <li>Plik z listą unieważnionych certyfikatów (poźniejszy etap) powinien 
+          znajdować się w katalogu <em>/etc/ipsec.d/crls/</em>.</li>
+      <li>Dokonujemy zmian w pliku /etc/ipsec.secrets, tak aby miał 
+          następującą składnię:
+<pre class="code-block">
+: RSA serverkey.pem "&lt;hasło_klucza_prywatnego&gt;"
+</pre>
+          gdzie:
+          <ul>
+            <li><code class="code-inline">serverkey.pem</code> - to nazwa pliku 
+                z kluczem prywatnym, którego program <em>OpenSWAN</em> oczekuje
+                w katalogu <em>/etc/ipsec.d/private/</em>,</li>
+            <li><code class="code-inline">hasło_klucz_prywatnego</code> - to 
+                hasło do klucza prywatnego serwera. W przypadku gdy klucz nie 
+                jest zabezpieczony hasłem, można je pominąć. Wstawienie 
+                wartości <em>%prompt</em> spowoduje, że program <em>OpenSWAN</em>
+                przy starcie będzie pytał o hasło do klucza.</li>
+          </ul></li>
+      <li>Tworzymy plik konfiguracyjny <em>/etc/ipsec.conf</em>
+<pre class="code-block">
+version 2.0
+config setup
+        interfaces=%defaultroute
+        plutodebug=none
+        forwardcontrol=yes
+        nat_traversal=yes
+        virtual_private=%v4:10.0.0.0/8,%v4:172.16.0.0/12,%v4:192.168.0.0/16,%v4:!192.168.10.0/24
+conn roadwarrior-l2tp
+        leftprotoport=17/1701
+        rightprotoport=17/1701        
+        also=roadwarrior
+conn roadwarrior
+        auth=esp
+        authby=rsasig
+        compress=yes
+        keyexchange=ike
+        keyingtries=3
+        pfs=no
+        left=%defaultroute
+        leftcert=/etc/ipsec.d/certs/servercrt.pem
+        right=%any
+        rightrsasigkey=%cert
+        rightsubnet=vhost:%no,%priv
+        rightca=%same
+        auto=add
+#Disable Opportunistic Encryption
+include /etc/ipsec.d/examples/no_oe.conf
+</pre>
+          Opcja <code class="code-inline">rightrsasigkey=%cert</code> 
+          oznacza, że druga strona uwierzytelni się, przedstawiając swój 
+          certyfikat. Opcja <code class="code-inline">rightca=%same</code> 
+          oznacza, że certyfikat drugiej strony (klienta) musi być wystawiony 
+          przez to samo CA co certyfikat serwera, czyli przez CA, którego 
+          certyfikat znajduje się na serwerze w pliku:
+           <em>/etc/ipsec.d/cacert/cacert.pem</em>.</li>
+      <li>Uruchamiamy usługę IPSec, wpisując polecenie:
+<pre class="code-inline">
+ipsec setup start
+</pre></li>
+    </ol>
+    <h4>Import certyfikatów w systemie Windows</h4>
+    <p>
+      Zakładając, że wygenerowaliśmy już użytkownikom klucz oraz wystawiliśmy 
+      certyfikaty podpisane przez nasze CA. Powinniśmy mieć już pliki 
+      <em>user.key</em> i <em>user.crt</em>. Będziemy musieli przekonwertować 
+      nasze klucze i certyfikaty na format PKCS#12 używany w systemach Windows.
+      Konwersje zostały przedstawione podkoniec sekcji poświęconej 
+      <a href="#ssl">SSL</a>.
+    </p>
+    <p>
+      Przy imporcie certyfikatów należy powstrzymać się od instalowania 
+      certyfikatów w systemie Windows przez kliknięcie na plik. Ta metoda nie 
+      działa prawidłowo. Zamiast tego będziemy używać przystawki MMC.
+    </p>
+    <p>
+      Utworzymy przystawkę MMC, dzięki której będziemy mogli importować nasze 
+      klucze i certyfikaty. Naciskamy kombinację klawiszy (Win + r), w okienku 
+      uruchom pisujemy polecenie: <code>mmc</code> - uruchomi się konsola MMC.
+    </p>
+    <p>
+      Z menu <em>Plik</em> konsoli MMC wybieramy opcję 
+      <em>Dodaj/Usuń przystawkę...</em>. Pojawi się okno 
+      <em>Dodaj/Usuń przystawkę</em> - klikamy przycisk <em>Dodaj</em>.
+    </p>
+    <p>
+      Na liście dostępnych przystawek zaznaczamy <em>Certyfikaty</em>, a 
+      następnie klikamy <em>Dodaj</em> - uruchomi się kreator konfiguracji 
+      przystawki. Wybieramy <em>Konto komputera</em>, następnie 
+      klikamy <em>Dalej</em>. W następnym kroku wybieramy opcję 
+      <em>Komputer lokalny</em> oraz klikamy przycisk <em>Zakończ</em>.
+    </p>
+    <p>
+      Z menu <em>Plik</em> wybieramy opcję <em>Zapisz</em>, aby zapisać gotową 
+      przystawkę na dysku. Możemy ją nazwać dowolnie - np. 
+      <em>ipsec.mmc</em>.
+    </p>
+    <p>
+      Mając gotową przystawkę, możemy zaimportować certyfikat. W tym celu 
+      rozwiń przystawkę <em>Certyfikaty</em>, a następnie kliknij prawym 
+      przyciskiem myszy folder <em>Osobisty</em>. Z menu wybieramy 
+      <em>Wszystkie zadania</em> a następnie <em>Importuj...</em> - uruchomi 
+      się kreator importu certyfikatów.
+    </p>
+    <p>
+      W kreatorze dodawania certyfikatów wskazujemy przygotowany wcześniej plik
+      certyfikatu użytkownika. Kreator zapyta o hasło klucza prywatnego - 
+      podajemy je. Klikamy przycisk <em>Dalej</em>, następnie wybieramy opcje 
+      <em>Automatycznie wybierz magazyn certyfikatów na podstawie typu 
+      certyfikatu</em> (<strong>WAŻNE!</strong>) oraz ponownie klikamy 
+      <em>Dalej</em>.
+    </p>
+    <p>
+      Musimy jeszcze zainstalować certyfikat swojego CA w katalogu zaufanych 
+      urzędów certyfikacji. W tym celu klikamy prawym przyciskiem myszy katalog
+      <em>Zaufane główne urzędy certyfikacji</em>, a następnie z menu wybieramy
+      opcję <em>Wszystkie zadania/Importuj</em>.
+    </p>
+    <p>
+      Po wybraniu opcji <em>Importuj</em> uruchomi się kolejny kreator importu 
+      certyfikatów. Musimy wskazać plik z certyfikatem CA (<em>ca.crt</em>). 
+      Kreator importu certyfikatów oczekuje pliku z rozszerzeniem 
+      <em>*.crt</em>, a nie <em>*.pem</em>, dlatego przed importem musimy się 
+      upewnić czy plik ma takie rozszerzenie.
+    </p>
+    <p>
+      Klikamy przycisk <em>Dalej</em>, a następnie wybierz opcję <em>Umieść 
+      wszystkie certyfikaty w następującym magazynie - Zaufane główne urzędy 
+      certyfikacji</em>. Wychodzimy z konsoli zapisując zmiany.
+    </p>
+    <h5>Konfiguracja połączenia</h5>
+    <p>
+      Konfiguracja połączenia przeprowadzamy dokładnie w taki sam sposób, jak w
+      przykładzie z kluczem współdzielonym. Jedyna różnica polega na tym, aby w
+      zakładce <em>Zabezpieczenia</em> nie zaznaczymy opcji <em>Ustawienia 
+      protokołu IPSec/Użyj klucza wstępnego do uwierzytelniania</em>. 
+      Zapisujemy zmiany i próbujemy się połączyć.
+    </p>
+    <p>
+      Jeśli pojawi się błąd odnośnie certyfikatu, to należy upewnić się że 
+      poprawnie zaimportowaliśmy certyfikat CA w magazynie 
+      <em>Zaufane główne urzędy certyfikacji</em>. Najlepiej zrobić to jeszcze 
+      raz. 
+    </p>
+    <p>
+      Jeśli połączenie się zestawiło, spróbujmy spingować drugą stronę wtedy 
+      będzie mieli pewność.
+    </p>
+    <h4>Łączenie oddziałów firmy tunelem IPSec</h4>
+    <p>
+      W tej sekcji stworzymy tunel łączący siedzibę firmy A z oddziałem B. W 
+      obu lokalizacjach routery działają pod kontrolą Linuksa z instalowanym 
+      programem <em>OpenSWAN</em>. Celem tunelu jest zapewnienie bezpiecznej 
+      komunikacji w oddziałach.
+    </p>
+    <p>
+      Do uwierzytelnienia obu stron użyjemy tym razem kluczy RSA (klucz
+      prywatny i publiczny). Jeżeli routery mają stałe IP, możesz użyć nawet 
+      klucza współdzielonego (hasła), ale pamiętajmy, aby zablokować na 
+      firewallu możliwość łączenia się z protokołem IPSec ze wszystkich hostów 
+      wyjątkiem adresu IP "drugiej strony" (w przeciwnym razie ktoś będzie mógł
+      próbować odgadnąć hasło, np. przez atak typu <em>brute force</em>).
+    </p>
+    <p>
+      Ponieważ implementacja IPSec w Linuksie nie wymaga użycia protokołu PPP 
+      oraz L2TP, konfiguracja tutaj jest znacznie prostsza niż w przypadku 
+      połączenia z użytkownikami mobilnymi.
+    </p>
+    <p>
+      Tworzymy plik konfiguracyjny podany na listingu poniżej będzie to 
+      plik siedziby firmy A.
+    <p>
+<pre class="code-block">
+version 2.0
+config setup
+        interfaces=%defaultroute        
+        forwardcontrol=yes        
+        rp_filter=0        
+        nat_traversal=noconn
+linux-to-linux
+        auth=esp        
+        authby=rsasig        
+        pfs=yes        
+        left=91.192.0.186        
+        leftsubnet=192.168.20.0/24
+        leftrsasigkey=0sAQPuvae6KEw/yHijDjqHomCyLo8oO3H8wl3UExuTArCXtzc1DO5X2E8QFIu0grLofzIzgoCy8AkoFthFPJIyDF3zKVH9ppMS8XQQL2naWp+YOm2cROstRlAfyvC/jF7GvWlRIjxzHzCLCIJXihZmFZGN1ku/DExLx5TjzqG/bXQ9DQ==
+        right=91.192.0.185        
+        rightsubnet=192.168.30.0/24
+        rightrsasigkey=0sAQODH/CRwexspJ6mu/bThfQzs84IpaHBYNs5MeDpxbiLdacZjM22PqOvbVIqeQlYg4zHMAnB2EyUIgYHskJqyRmtmg6S5ELxnNHqvTE92KI5Bdicn458CowdqR2Jtc4tvD7OWHv/RFzmt6W1kIHPiILAOkR2mSvATgI/QhZtNN4oaw==        
+        auto=start
+include /etc/ipsec.d/examples/no_oe.conf
+</pre>
+    <p>
+    Znaczenie ważniejszych opcji jest następujące:
+    </p>
+    <ul>
+      <li><code class="code-inline">authby=rsasig</code> - uwierzytelnianie 
+          przez klucze RSA,</li>
+      <li><code class="code-inline">left=91.192.0.186</code> - adres IP routera
+          w siedzibie firmy A ("lewa strona" - lokalna routera),</li>
+      <li><code class="code-inline">leftsubnet=192.168.20.0/24</code> - sieć 
+          LAN za routerem w siedzibie firmy A,</li>
+      <li><code class="code-inline">leftrsasigkey=0sAQPuvae6KE...</code> - 
+          klucz publiczny "lewej strony" (routera w siedzibie A),
+      <li><code class="code-inline">right=91.192.0.185</code> - adres IP bramy 
+          odległej lokalizacji (oddziału B),</li>
+      <li><code class="code-inline">rightsubnet=192.168.30.0/24</code> - sieć 
+          LAN za routerem w oddziale B,</li>
+      <li><code class="code-inline">rightrsasigkey=0sAQODH/CRw...</code> - 
+          klucz publiczny prawej strony.</li>
+    </ul>
+    <p>
+      Warto zauważyć że PFS zostało włączone, nie trzeba tego robić jawnie, 
+      jest to opcja domyślna dla połączeń linux-linux. Ponieważ jest ona 
+      obsługiwana nie należy jej wyłączać.
+    </p>
+    <p>
+      Ze względu na to iż powyższy listing jest gotowcem pobranym z plików 
+      załączonych do pakietu <em>OpenSWAN</em>, aby użyć go w swoim przypadku 
+      należy zmienić wyżej wymienione opcje, prócz 
+      <code class="code-inline">authby</code>. Aby zmienić klucze musimy je 
+      wygenerować poleceniem pakietu <em>OpenSWAN</em>. Poniżej znajduje się 
+      lista czynności do wykonania, aby uruchomić tunel IPSec łączący oddziały 
+      firmy.
+    </p>
+    <ol>
+      <li>Na obu routerach wydajemy poniższe polecenie:
+<pre class="code-block">
+# ipsec rsasigkey 1024 &gt; /root/key.rsa
+</pre>
+      </li>
+      <li>Na obu routerach kopiujemy ciąg znaków zaczynający się 
+          od <code class="code-inline">#pubkey=...</code> i umieszczamy go w 
+          pliku <em>ipsec.conf</em> przy parametrze <code class="code-inline">
+          leftrsasigkey=</code>, po czym usuwamy skopiowany ciąg znaków z pliku 
+          klucza.</li>
+      <li>Kopiujemy ciąg umieszczony w <code class="code-inline">
+          leftrsasigkey</code> do pliku konfiguracyjnego w oddziale B, 
+          umieszczając go przy parametrze 
+          <code class="code-inline">rightrsasigkey=</code></li>
+      <li>Klucz przy parametrze <code>leftrsasigkey=</code> umieszczamy w pliku
+          konfiguracyjnym routera w siedzibie firmy A przy parametrze 
+          <code class="code-inline">rightrsasigkey=</code></li>
+      <li>Otwieramy do edycji plik <em>/etc/ipsec.secrets</em> i umieszczamy w
+           nim następujący wpis:
+<pre class="code-block">
+91.192.0.186 91.192.0.185: RSA {
+
+//część klucz prywatnego pobrana z pliku /root/key.rsa
+//począwszy od linii: Modulus do końca pliku
+
+}
+</pre>
+           gdzie 91.192.0.186 to w powyższym przykładzie adres IP 
+           "lewej strony" (IP lokalnego routera), a 91.192.0.185 to IP 
+           odległego routera. Na drugim routerze wpis wygląda odwrotnie. W 
+           sekcji pomiędzy nawiasami klamrowymi 
+           (<code class="code-inline">{...}</code>) powinien znaleźć się klucz 
+           prywatny RSA.</li>
+      <li>Uruchamiamy tunel po obu stronach, wpisując poniższe polecenie:
+<pre class="code-block">
+# ipsec setup start
+</pre>
+      </li>
+      <li>Sprawdzamy czy połączenie IPsec zostało zestawione. Wpisujemy 
+          polecenie: 
+<pre class="code-block">
+# ip xfrm state
+</pre>
+      </li>
+</ol>
+</div>
+</div>
+</body>
+</html>
diff --git a/articles/terminallog/ściąga_z_PYTHONga.html b/articles/terminallog/ściąga_z_PYTHONga.html
new file mode 100755 (executable)
index 0000000..11b80a2
--- /dev/null
@@ -0,0 +1,5464 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       <style>
+                               .code-block {
+                                       text-align: left;
+                               }
+                               ul {
+                                       text-align: left;
+                               }
+                               .toc {
+                                       list-style-type: none;
+                               }
+                               body {
+                                       width: 99%;
+                                       height: 100vh;
+                               }
+                               .main {
+                                       width: 100%;
+                               }
+                       </style>
+               </head>
+               <body>
+       
+       <div class="main">
+       <div id="tableOfContent">
+               <h1>Ściąga z PYTHONga</h1>
+    <ol class="toc mainToc">
+      <li><a href="#1.part1">Część 1: Zapoznanie się z językiem Python</a>
+        <ul class="toc">
+          <li><a href="#1.1.introduction">1.1. Wstęp.</a></li>
+          <li><a href="#1.2.helloworld">1.2. Witaj w świecie Pythona.</a>
+            <ul class="toc">
+              <li><a href="#1.2.1.strings">1.2.1. Ciągi tekstowe w Pythonie</a></li>
+              <li><a href="#1.2.2.moreaboutvariables">1.2.2. Więcej o zmiennych</a></li>
+              <li><a href="#1.2.3.comments">1.2.3.Komentarze</a></li>
+              <li><a href="#1.2.4.afewrules">1.2.4. Kilkanaście zasad.</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.3.lists">1.3. Listy</a>
+            <ul class="toc">
+              <li><a href="#1.3.1.appendingelementstolist">1.3.1. Dodawanie elementów do listy</a></li>
+              <li><a href="#1.3.2.removingelementsfromlists">1.3.2. Usuwanie elementów z listy</a></li>
+              <li><a href="#1.3.3.sortinglists">1.3.3. Sortowanie list</a></li>
+              <li><a href="#1.3.4.reversingthelist">1.3.4. Odwracanie listy.</a></li>
+              <li><a href="#1.3.5.lengthoflist">1.3.5. Długość listy</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.4.forloop">1.4. Pętla for</a></li>
+          <li><a href="#1.5.rangefunction">1.5. Funkcja range</a></li>
+          <li><a href="#1.6.simplestatsfunctions">1.6. Proste funkcje statystyczne</a></li>
+          <li><a href="#1.7.listcomprehension">1.7. Lista składana</a></li>
+          <li><a href="#1.8.pieceoflist">1.8. Wycinek listy.</a>
+            <ul class="toc">
+              <li><a href="#1.8.1.stepinpieceoflist">1.8.1. Krok w wycinku listy</a></li>
+              <li><a href="#1.8.2.iterationviapieceoflist">1.8.2. Iteracja przez wycinek listy</a></li>
+              <li><a href="#1.8.3.copyoflist">1.8.3. Kopia listy</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.9.tuplets">1.9. Krotki</a></li>
+          <li><a href="#1.10.conditionalexpressions">1.10. Wyrażenia warunkowe</a></li>
+          <li><a href="#1.11.ifinstruction">1.11. Konstrukcja if</a></li>
+          <li><a href="#1.12.dictionaries">1.12. Słowniki</a>
+            <ul class="toc">
+              <li><a href="#1.12.1.addingnewvalues">1.12.1. Dodawanie nowych wartości do słownika</a></li>
+              <li><a href="#1.12.2.interationthroughthedictionary">1.12.2. Iteracja przez słownik</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.13.collections">1.13. Zbiory</a></li>
+          <li><a href="#1.14.nestingindatatypes">1.14. Zagnieżdznie złożonych typów danych</a></li>
+          <li><a href="#1.15.gettingdatafromuser">1.15. Pobieranie danych od użytkownika.</a></li>
+          <li><a href="#1.16.modulooperator">1.16. Operator modulo (reszty z dzielenia).</a></li>
+          <li><a href="#1.17.whileloop">1.17. Pętla while.</a></li>
+          <li><a href="#1.18.function">1.18. Funkcje</a>
+            <ul class="toc">
+              <li><a href="#1.18.1.functiondefinition">1.18.1. Definiowanie funkcji</a></li>
+              <li><a href="#1.18.2.passingcomplexdatatypestofunc">1.18.2. Przekazywanie do funkcji złożonych typów dancyh</a></li>
+              <li><a href="#1.18.3.undefinedamountofargs">1.18.3. Przekazywanie nieokreślonej liczy argumentów</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.19.modules">1.19. Moduły</a></li>
+          <li><a href="#1.20.objectorientedprograming">1.20. Programowanie zorientowane obiektowo</a>
+            <ul class="toc">
+              <li><a href="#1.20.1.object">1.20.1. Objekt</a></li>
+              <li><a href="#1.20.2.methods">1.20.2. Metody</a></li>
+              <li><a href="#1.20.3.workingonattributs">1.20.3. Praca z atrybutami obiektów.</a></li>
+              <li><a href="#1.20.4.inheritance">1.20.4. Dziedziczenie</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.21.standardlibrary">1.21. Biblioteka standardowa</a></li>
+          <li><a href="#1.22.filehandling">1.22. Obsługa plików</a>
+            <ul class="toc">
+              <li><a href="#1.22.1.openfunction">1.22.1. Funkcja open</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.23.try-except">1.23. Obsługa błędów</a></li>
+          <li><a href="#1.24.usingJSONformatwithpython">1.24. Wykorzystanie formatu JSON w Pythonie</a></li>
+          <li><a href="#1.25.unittests">1.25. Testy jednostkowe</a>
+            <ul class="toc">
+              <li><a href="#1.25.1.unittestsoffunction">1.25.1. Testy jednostkowe funkcji</a></li>
+              <li><a href="#1.25.2.unittestsofmethods">1.25.2. Testy jednostkowe metod</a></li>
+            </ul>
+          </li>
+          <li><a href="#1.26.sourcecodestyle">1.26. Koncepcje stylu kodu źródłowego</a></li>
+        </ul>
+      </li>
+      <li><a href="#2.part2">Część 2: Aplikacje internetowe</a>
+        <ul class="toc">
+          <li><a href="#2.1.virtualenv">Środowisko wirtualne</a></li>
+          <li><a href="#2.2.djangobasics">Podstawy pracy z frameworkiem Django</a>
+            <ul class="toc">
+              <li><a href="#2.2.1.installationofdjango">2.2.1. Instalacja django</a></li>
+              <li><a href="#2.2.2.creatingnewproject">2.2.2. Stworzenie nowego projektu w Django</a></li>
+              <li><a href="#2.2.3.cratetindbforproject">2.2.3. Tworzenie bazy danych dla projektu</a></li>
+              <li><a href="#2.2.4.startaprojectserver">2.2.4. Uruchomienie serwera projektu</a></li>
+              <li><a href="#2.2.5.creatinganapplication">2.2.5. Tworzenie aplikacji Django</a></li>
+              <li><a href="#2.2.6.models">2.2.6. Modele</a></li>
+              <li><a href="#2.2.7.instalationappinproject">2.2.7. Instalacja aplikacji w projekcie</a></li>
+              <li><a href="#2.2.8.approvingmodels">2.2.8. Zatwierdzanie modeli w bazie danych.</a></li>
+              <li><a href="#2.2.9.managingmodelsviaadminsite">2.2.9. Zarządzanie modelami za pomocą wirtyny administracyjnej Django</a></li>
+              <li><a href="#2.2.10.djangoshell">2.2.10. Powłoka Django</a></li>
+            </ul>
+          </li>
+          <li><a href="#2.3.creatingappspages">2.3. Tworzenie aplikacji</a>
+            <ul class="toc">
+              <li><a href="#2.3.1.sitemappings">2.3.1. Mapowanie stron aplikacji</a></li>
+              <li><a href="#2.3.2.creatingaview">2.3.2. Tworzenie widoku</a></li>
+              <li><a href="#2.3.3.creatingatemplate">2.3.3. Tworzenie szablonu</a></li>
+              <li><a href="#2.3.4.mappingapps">2.3.4. Mapowanie aplikacji</a></li>
+              <li><a href="#2.3.5.anexampleexpanding">2.3.5. Rozszerzanie przykładu</a></li>
+            </ul>
+          </li>
+          <li><a href="#2.4.theuserapplication">2.4. Aplikacja users</a>
+            <ul class="toc">
+              <li><a href="#2.4.1.userslogin">2.4.1. Logowanie użytkowników</a></li>
+              <li><a href="#2.4.2.theuserregistration">2.4.2. Rejestracja użytkowników</a></li>
+            </ul>
+          </li>
+          <li><a href="#2.5.expandingpizzasapplication">2.5. Rozbudowa aplikacji 'pizzas'.</a></li>
+          <li><a href="#2.6.securinganapplication">2.6. Zabezpieczenie aplikacji</a></li>
+          <li><a href="#2.7.usingbootstrap4fordjango">2.7. Nadawanie stylu aplikacji - Bootstrap 4</a></li>
+          <li><a href="#2.8.herokuplatform">2.8. Platforma Heroku</a></li>
+        </ul>
+      </li>
+    </ol>
+    <p class="footer">
+                 ~xf0r3m<br />
+                 2021; COPYLEFT; ALL RIGHTS REVERSED;
+         </p>
+       </div>
+       <div id="content">
+  <div id="contentHeader">
+<pre id="divisionBaner">
+ _                      _             _ _
+| |_ ___ _ __ _ __ ___ (_)_ __   __ _| | | ___   __ _
+| __/ _ \ '__| '_ ` _ \| | '_ \ / _` | | |/ _ \ / _` |
+| ||  __/ |  | | | | | | | | | | (_| | | | (_) | (_| |
+ \__\___|_|  |_| |_| |_|_|_| |_|\__,_|_|_|\___/ \__, |
+                                               |___/
+</pre>
+<p id="contentHeaderLink" class="header_link">
+          &#9760;&nbsp;<a href="https://morketsmerke.github.io">morketsmerke</a>&nbsp;&#9760;
+    </p>
+    </div>
+    <h1 id="1.part1">Część 1: Zapoznanie się z językiem Python</h1>
+               <h2 id="1.1.introduction">1.1. Wstęp.</h2>
+               <p>
+                       Informacje zawarte tutaj odnoszą się do wersji Pythona powyżej 3.6. 
+      Python powinien być zainstalowany domyślnie we wiodących dystrybucjach 
+      systemu Linux. Jeśli nie ma w ogóle Pythona w wersji &gt;= 3. To warto 
+      sprawdzić czy istnieją pakiety w repozytorium dystrybucji z wersją 
+      powyżej 3.6. Jeśli tak to instalujemy te pakiety. Jeśli nie, to wtedy 
+      należałoby pobrać kod źródłowy najnowszego Pythona i go skompilować. 
+      Zazwyczaj nie kompiluje, ale w przypadku kiedy użyłem dystrybucji 
+      <em>BunsenLabs Helium</em>, to pre-instalowanego Pythona miałem w wersji 
+      3.5. Za mało na najnowszy <em>Crash Course</em>. Kompilacje wykonujemy w 
+      następujących krokach:
+               </p>
+               <ol>
+                       <li>Instalujemy odpowiednie dla naszej dystrybucji <em>build-essential</em> 
+          oraz dwa pakiety, których nieobecność została zauważona przy 
+          wykonywaniu polecenia <code class="code-inline">make altinstall</code>
+          i zwrócona jako błąd, mianowicie chodzi o <em>zlib1g</em> oraz 
+          <em>zlib1g-dev</em>.</li>
+                       <li>Pobieramy najnowszą wersję kodu z 
+          <a href="https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tar.xz">https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tar.xz</a>.</li>
+                       <li>Rozpakowujemy: 
+          <code class="code-inline">tar -xvf Python-3.8.3.tar.xz</code></li>
+                       <li>Przechodzimy do katalogu: 
+          <code class="code-inline">cd Python-3.8.3.tar.xz</code></li>
+                       <li>Ja w swoim systemie zachowałem obecną wersję Pythona, wskazując 
+          skryptowi konfiguracyjnemu opcje <code class="code-inline">prefix</code> 
+          wskazującą na katalog utworzony w moim katalogu domowym: 
+          <code class="code-inline">./configure --prefix="/home/xf0r3m/bin/python3.8"</code>.
+          Użycie opcji <code class="code-inline">prefix</code>, przekazuje 
+          skryptowi, aby przygotował środowisko do kompilacji względem podanej 
+          ścieżki. Jeśli nie zostanie zwrócony żaden błąd podczas pracy skryptu,
+          zostanie nam wygenerowany tzw. plik <em>makefile</em>.</li>
+                       <li>Wydajemy polecenie kompilacji kodu: <code class="code-inline">make</code>. 
+          Po poprawnie zakończonej kompilacji, to znaczy po wyświetlonych przez
+          polecenie <code class="code-inline">make</code> następnych 
+          kompilacjach, zostanie nam zwrócony <em>prompt</em>, możemy przejść 
+          do ostatniej części kompilacji czyli instalacji pakietu w systemie.
+          Ze względu na to iż zostawiłem pre-instalowaną wersję 3.5, wydaje 
+          polecenie '<code class="code-inline">make altinstall</code> po 
+          wykonaniu tego polecenia nasz Python 3.8 znajduje się w podkatalogu 
+          <em>bin</em> na ścieżce, którą podaliśmy w opcji 
+          <code class="code-inline">prefix</code>. </li>
+                       <li>Ostatni punkt jest dla wygodnych. W pliku <em>.bashrc</em> możemy
+          sobie zdefiniować alias <em>python</em> dla naszego nowo 
+          zainstalowanego Pythona.  Po uruchomieniu polecenia 
+          <code class="code-inline">python</code> powiśmy zobaczyć 
+          <em>prompt</em> powłoki wraz z informacjami odnośnie wersji.</li>
+               </ol>
+<pre class="code-block">
+Python 3.8.2 (default, Apr 27 2020, 15:53:34)
+[GCC 9.3.0] on linux
+Type "help", "copyright", "credits" or "license" for more information.
+&gt;&gt;&gt;
+</pre>
+               <p>
+                       Poniżej znajdują się zagadnienia z książki które warto mieć przy sobie 
+      przy pierwszych projektach tworzonych w tym języku. Kolejność jest 
+      identyczna z kolejnością występowania w książce.
+               </p>
+    <h2 id="1.2.helloworld">1.2. Witaj w świecie Pythona.</h2>
+               <p>
+                       <strong>print()</strong> - instrukcja wyświetlająca wszystko co umieścimy
+      pomiędzy nawiasami.
+               </p>
+               <p>
+                       Konwencja nadawania wartości zmiennym w Pythonie wygląda w ten sposób:
+    </p>
+<pre class="code-block">
+greetinsg_message = "Hello, World!"
+</pre>
+    <p>
+      Warto pamiętać o spacjach pomiędzy operatorem. Podobnie zresztą wygląda 
+      konwencja stosowania jakichkolwiek operatorów.
+               </p>
+    <h3 id="1.2.1.strings">1.2.1. Ciągi tekstowe w Pythonie</h3>
+               <p>
+                       <strong>Ciągi tekstowe <em>f</em> </strong>- formatowane ciągi tekstowe. 
+      Litera f pochodzi od słowa <em>format</em>, ich głównym zadaniem jest 
+      zamiana nawiasu klamrowego wraz z nazwą zmiennej na jej wartość w ciągu.
+      Taki ciąg tworzy się w następujący sposób:
+               </p>
+<pre class="code-block">
+imie = 'xf0r3m'
+print(f"Witaj {imie}! Czy chcesz zanurzyć się w świat Pythona?")
+</pre>
+               <p>
+                       Czy w innej zmiennej czy poleceniu <code class="code-inline">print()</code> 
+      zapisanie litery <code class="code-inline">f</code> przed znakami 
+      cudzysłowu lub apostrofu, spowoduje że dany ciąg będzie <em>ciągiem f</em>. 
+    </p>
+    <p>
+      <strong>Uwaga!</strong> <em>Ciągi f</em> są dostępne dopiero od wersji 3.6.
+               </p>
+               <p>
+                       <strong>Formatowanie ciągu przed wersją Pythona 3.6.</strong> 
+      Takie formatowanie polega na użyciu wbudowanej metody 
+      <strong>format()</strong>. Przykład poniżej.
+               </p>
+<pre class="code-block">
+imie = 'xf0r3m'
+print("Witaj {}! Czy chcesz zanurzyć się w świat Pythona?".format(imie))
+</pre>
+               <p>
+                       Dodatkowa zmienna do wyświetlenia, to dodatkowa para nawiasów i kolejna 
+      zmienna jako argument metody format.
+               </p>
+               <p>
+                       Do obróbki ciągów tekstowych, a konkretnie ich <strong>normalizacji</strong> 
+      mogą służyć nam poniższe metody:
+               </p>
+               <ul>
+                       <li><strong>title()</strong> - Zwraca ciąg tekstowy jak tytuł, czyli 
+          każdy wyraz w ciągu zaczyna się z wielkiej litery.</li>
+                       <li><strong>lower()</strong> - Zwraca ciąg tekstowy po całości zapisany 
+          małymi literami.</li>
+                       <li><strong>upper()</strong> - Zwraca ciąg tekstowy zapisany po całości 
+          z wielkich liter</li>
+               </ul>
+               <p>
+                       Warto zaznaczyć że te metody nie zmieniają wartości ciągu, o ile nie 
+      przypiszemy nie ich wartości zwrotnych.
+               </p>
+               <p>
+                       <strong>Białe znaki w ciągach tekstowych. </strong>Białe znaki w naszych 
+      ciągach uzyskuje się w bardzo prosty sposób, po prostu po przez 
+      umieszczenie w ciągu:
+               </p>
+               <ul>
+                       <li><strong>\t </strong> - tabulator</li>
+                       <li><strong>\n</strong> - znak nowej linii</li>
+               </ul>
+<pre class="code-block">
+imie = 'xf0r3m'
+print(f"Witaj \t{imie}!\nCzy chcesz zanurzyć się w świat Pythona?")
+</pre>
+               <p>
+                       <strong>Usuwanie białych znaków</strong>. Może zdarzyć się taka sytuacja,
+      że weźmie się skądś dane, i nagle gdzieś nasz algorytm nie działa, bo 
+      ma nieprawidłowe dane. Gdzieś na początku albo na końcu ciągu znajdują 
+      się nadmiarowe białe znaki np. skopiowaliśmy jakiś ciąg ze spacją na 
+      końcu. To zresztą zdarza się dość często. W tym przypadku korzystamy z 
+      metody <code class="code-inline">strip()</code> jeśli nie potrafimy jasno
+      określić czy z lewej lub prawej strony ciągu znajdują się nadmiarowe 
+      białe znaki. Dla znaków po lewej stronie możemy użyć <strong>lstrip()</strong>
+      a dla znaków po prawej <strong>rstrip()</strong>. Warto mieć na uwadze, 
+      że te metody <strong>nie dokonują w zmiennej żadnych zmian, aby zapisać 
+      zmiany musimy nadać zmiennej wartość zwracaną przez tą metodę</strong>.
+               </p>
+<pre class="code-block">
+dirty_strings='  python  '
+washed_strings=dirty_strings.strip()
+</pre>
+    <h3 id="1.2.2.moreaboutvariables">1.2.2. Więcej o zmiennych</h3>
+               <p>
+                       Wielkie liczby możemy zapisywać za pomocą grup rozdzielonych przy
+      pomocy znaku podkreślenia (<strong>_</strong>), na przykład:
+               </p>
+<pre class="code-block">
+one_bilion = 1_000_000_000
+</pre>
+               <p>
+                       Z poziomu Pythona nie ma znaczenia, czy jest 1000000000 czy 
+      <em>1_000_000_000</em>. Podobnie jest z mniejszymi liczbami, takimi jak 
+      1000 (<em>1_000</em>). <strong>Uwaga!</strong> Ta funkcjonalność dostępna
+      jest od Pythona <strong>3.6</strong> w górę.
+               </p>
+               <p>
+                       <strong>Wiele przypisań</strong> wartość możemy skrócić sobie do 
+      praktycznego, aczkolwiek nie zawsze czytelnego zapisu. Na przykład:
+               </p>
+<pre class="code-block">
+x, y, z = 0, 0, 0
+a, b, c = 3, 4, 5
+</pre>
+               <p>
+                       W Pythonie nie ma stałych, jednak wśród programistów nie tylko Pythona 
+      przyjęło się, że każdą zmienną, której nazwa (identyfikator) będzie 
+      zapisany wielkimi literami traktuje się jako <strong>stałą</strong>.
+               </p>
+<pre class="code-block">
+UNIX_EPOCH = "01-01-1970"
+</pre>
+    <h3 id="1.2.3.comments">1.2.3.Komentarze</h3>
+    <p>
+                       <strong>Komentarze</strong> w Pythonie zaczynają się od krzyżyka
+      (<strong>#</strong>). Wszystko co zostanie umieszczone po tym znaku 
+      zostanie zignorowane w przez interpreter Pythona.
+               </p>
+<pre class="code-block">
+NIGGA_AM = 300
+#BANG!
+</pre>
+    <h3 id="1.2.4.afewrules">1.2.4. Kilkanaście zasad.</h3>
+               <p>
+                       <strong>Zen Pythona </strong>- to kilka zasad stworzonych przez 
+      społeczność Pythona. Cenne uwagi, które warto wziąć sobie do serca 
+      programując nie tylko w Pythonie. Warto sobie zrobić z tego swoisty 
+      kodeks programisty - 18 zasad.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; import this
+The Zen of Python, by Tim Peters
+
+Beautiful is better than ugly.
+Explicit is better than implicit.
+Simple is better than complex.
+Complex is better than complicated.
+Flat is better than nested.
+Sparse is better than dense.
+Readability counts.
+Special cases aren't special enough to break the rules.
+Although practicality beats purity.
+Errors should never pass silently.
+Unless explicitly silenced.
+In the face of ambiguity, refuse the temptation to guess.
+There should be one-- and preferably only one --obvious way to do it.
+Although that way may not be obvious at first unless you're Dutch.
+Now is better than never.
+Although never is often better than *right* now.
+If the implementation is hard to explain, it's a bad idea.
+If the implementation is easy to explain, it may be a good idea.
+Namespaces are one honking great idea -- let's do more of those!
+</pre>
+               <h2 id="1.3.lists">1.3. Listy</h2>
+               <p>
+                       <strong>Listy </strong> - bardzo podobne do tablic. Do poszczególnych 
+      elementów uzyskujemy dostęp poprzez podanie indeksu w nawiasie 
+      kwadratowym:
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+print(cars[2])
+</pre>
+               <p>
+                       Dostęp do końcowych elementów listy następuje poprzez podanie 
+      <strong>ujemnego indeksu</strong>, począwszy od -1  wskazujący 
+      ostatni element listy, kolejno -2 to przedostatni itd.
+               </p>
+               <p>
+      Nadając zmiennej parę nawiasów kwadaratowych możemy utworzyć  
+                       <strong>pustą listę</strong>, do której wrazie potrzemy będziemy mogli
+      dodać elementy.
+               </p>
+<pre class="code-block">
+cars=[]
+</pre>
+    <h3 id="1.3.1.appendingelementstolist">1.3.1. Dodawanie elementów do listy</h3>
+               <p>
+                       Dodawanie elementów na końcu listy możemy zrealizować za pomocą 
+      wbudowanej metody <code class="code-inline">append()</code>. Jak argument
+      metoda przyjmuje wartość dodawanego elementu.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+cars.append('toyota')
+</pre>
+               <p>
+                       Za pomocą metody <code class="code-inline">insert()</code>, możemy
+      wstawić element w dowolny indeks listy. Metoda jako argumenty przyjmuje 
+      indeks dla nowego elementu oraz jego wartość.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+cars.insert(2, 'daewoo')
+</pre>
+    <h3 id="1.3.2.removingelementsfromlists">1.3.2. Usuwanie elementów z listy</h3>
+               <p>
+                       Usuwanie elementów z listy możemy przeprowadzić na <strong>trzy</strong> 
+      sposoby. Po prostu usuwając element poprzez podanie nazwy listy oraz 
+      indeksu (tak jak byśmy uzyskiwali dostęp do wartości) instrukcji 
+      <code class="code-inline">del</code>.
+               </p>
+<pre class="code-block">
+del cars[1]
+</pre>
+               <p>
+                       Kolejnym sposobem może być zabranie danej wartości z listy za pomocą 
+      metody <code class="code-inline">pop()</code>. Jako argument metoda 
+      przyjmuje indeks, tak więc możemy pobrać dowolny element, jeśli nie
+      podamy żadnych argumentów metoda pobierze ostatni element.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+fura = cars.pop()
+</pre>
+               <p>
+                       Ostatnim, chyba najciekawszym sposobem jest metoda 
+      <code class="code-inline">remove()</code>, która wyszukuje element na 
+      podstawie wartości. Poszukiwaną wartość podajemy jak argument metody.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+swag_gablota = 'bmw'
+cars.remove(swag_gablota)
+</pre>
+               <p>
+                       <strong>Uwaga!</strong> Metoda <code class="code-inline">remove()</code> 
+      usuwa tylko pierwsze wystąpienie danej wartości na liście, więc jeśli 
+      jest więcej niż jedna taka wartość to tylko pierwsza odnaleziona zostanie
+      usunięta.
+               </p>
+    <h3 id="1.3.3.sortinglists">1.3.3. Sortowanie list</h3>
+               <p>
+                       Elementy na liście mogą być innej kolejności niż moglibyśmy sobie tego 
+      życzyć, w Pythonie istnieje kilka sposób na uporządkowanie listy 
+      (sortowanie).
+    </p>
+    <p> 
+      Pierwszą z nich jest użycie metody 
+      <code class="code-inline">sort()</code>, metoda ta wyróżnia się tym, że 
+      wprowadza zmiany samej liście, czyli jej użycie w kodzie zmieni kolejność
+      wartości na liście. Domyślnie metoda <em>sort()</em> sortuje rosnąco, 
+      jednak możemy mieć na to wpływ, podając jej argument 
+      <code class="code-inline">reverse=True</code>, teraz metoda posortuje 
+      listę malejąco.
+    </p>
+    <p>
+      Kolejnym sposobem na sortowanie jest sposób tymczasowy, na przykład gdy 
+      kolejność danych ma znaczenie i nie możemy jej od tak sobie zmieniać, ale
+      jednak wypadałoby aby użytkownikowi wypisać posortowane dane.
+                       Za sortowanie tymczasowe odpowiada funkcja 
+      <code class="code-inline">sorted()</code>. Funkcja od metody tym 
+      kontekście różni się tym że musimy podać jako argument listę, a następnie
+      zrobić coś z danymi zwróconymi albo przechować je w zmiennej albo wypisać
+      za pomocą polecenia <code class="code-inline">print()</code>. Oczywiście 
+      funkcja <em>sorted()</em> również przyjmuje argument <em>reverse=True</em>.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+cars.sort()
+print(cars)
+cars.sort(reverse=True)
+print(cars)
+
+cars = ['audi', 'bmw', 'renault', 'honda']
+print(sorted(cars))
+print(sorted(cars, reverse=True))
+</pre>
+               <p>
+                       W Pythonie sortowanie jest nieco bardziej skomplikowane, ponieważ ciągi 
+      tekstowe sortowane są za pomocą wartości tablicy <em>ASCII</em>. Mniejszą
+      wartość (liczbę całkowitą przyporządkowaną do znaku w tablicy) mają 
+      wielkie litery, dlatego jeśli elementy listy mają wartość nie jednakowe 
+      (wszystkie z wielkiej/wszystkie z małej) to możemy spodziewać się, że 
+      wartość zapisane wielką literą będą miały pierwszeństwo na posortowanej 
+      liście.
+               </p>
+    <h3 id="1.3.4.reversingthelist">1.3.4. Odwracanie listy.</h3>
+               <p>
+                       Inną metodą na organizację listy jest jej odwrócenie. To znaczy, że 
+      ostatni element będzie pierwszym, przedostatni drugim itd, 
+      do odwracania listy służy metoda <code class="code-inline">reverse()</code>.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+cars.reverse()
+</pre>
+               <p>
+                       Warto wspomnieć, że <em>reverse()</em> trwale zmienia kolejność listy.
+               </p>
+    <h3 id="1.3.5.lengthoflist">1.3.5. Długość listy</h3>
+               <p>
+                       Wielkość listy możemy określić przy pomocy funkcji 
+      <code class="code-inline">len()</code>, funkcja jako argument przyjmuje 
+      naszą listę.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+len(cars)
+</pre>
+               <h2 id="1.4.forloop">1.4. Pętla for</h2>
+               <p>
+                       Pętla <em>for</em> w Pythonie jest podobna konstrukcyjnie do pętli 
+      <em>for</em> z BASH-a, również używa się słowa kluczowego 
+      <code class="code-inline">in</code>. Jeśli chcielibyśmy przetłumaczyć na
+      język potoczny pętlę <em>for</em> to będzie to mniej więcej tak: "Dla 
+      zmiennej <em>value</em> przypisz element z listy, następnie wykonaj blok 
+      kodu, na koniec przesuń się na kolejny element listy". Ten rodzaj pętli
+      służy głównie iteracjom przez listy lub listy tworzone przez funkcję 
+      <em>range()</em> (określone zbiory danych). Przy pętli <em>for</em> po 
+      raz pierwszy spotkamy się z zagnieżdżaniem bloków kodu. Przy każdej 
+      konstrukcji operującej na bloku kodu pojawia się dwukropek 
+      (<strong>:</strong>), oznaczający początek blok kodu. Wszystkie linie, 
+      które mają znaleźć się w owym bloku przesuwamy o jeden tab. Ponieważ 
+      wcięcia Pythonie są wykorzystywane do oznaczania bloku kodu, trzeba 
+      uważać przy ich stosowaniu.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+for car in cars:
+       print(car)
+</pre>
+    <h2 id="1.5.rangefunction">1.5. Funkcja range</h2>
+               <p>
+                       Za generowanie serii liczb ujętych w listę odpowiedzialna jest funkcja 
+      <code class="code-inline">range()</code>. Jako argumenty przyjmuje ona 
+      zakres dla generowanej serii liczb. Cechą funkcji, o której warto 
+      wiedzieć to to, że ostatnia liczba z zakresu jest traktowana w sposób 
+      wyłączny, to znaczy, że jeśli użyjemy funkcji <em>range()</em> do 
+      wygenerowania listy od 1 do 10, to jeśli podamy argumenty 1,10 to listę 
+      otrzymamy od 1 do 9.
+               </p>
+<pre class="code-block">
+for number in range(1,10):
+print(number)
+</pre>
+               <p>
+                       Funkcja <em>range()</em> może przyjmować jeden argument, zakres końcowy.
+               </p>
+<pre class="code-block">
+for number in range(5):
+       print(number)
+</pre>
+               <p>
+                       Dane wyjściowe takiej pętli będą od 0 od 4 - 5 elementów.
+               </p>
+               <p>
+                       Funkcję <em>range()</em>możemy wykorzystać wraz inna funkcją - 
+      <code class="code-inline">list()</code> do tworzenia list liczbowych.
+               </p>
+<pre class="code-block">
+numbers = list(range(1,11))
+for number in numbers:
+       print(number)
+</pre>
+               <p>
+                       Po za określeniem zakresu funkcja <em>range()</em> przyjmuje również 
+      <strong>krok</strong>, czyli o ile ma zwiększyć kolejne elementy.
+               </p>
+<pre class="code-block">
+even_numbers = list(range(2,11,2))
+for evenn in even_numbers:
+       print(evenn)
+</pre>
+    <h2 id="1.6.simplestatsfunctions">1.6. Proste funkcje statystyczne</h2>
+               <p>
+                       W Pythonie mamy dostępnych kilka bardzo prostych wybudowanych funkcji 
+      statystycznych. Mianowicie:
+               </p>
+               <ul>
+                       <li><strong>min()</strong> - zwraca najmniejszą wartość na liście</li>
+                       <li><strong>max()</strong> - zwraca największa wartość na liście</li>
+                       <li><strong>sum() </strong>- zwraca sumę wszystkich elementów listy</li>
+               </ul>
+    <h2 id="1.7.listcomprehension">1.7. Lista składana</h2>
+               <p>
+                       Aby ograniczyć  do minimum proces tworzenie list. Python wprowadza coś 
+      takiego co nazywa się <strong>listą składaną</strong>. Taka lista składa 
+      się z modelu wartości elementu (np. <em>value**2</em>) oraz z pętli for 
+      wraz z funkcją <em>range()</em>. Liczba stworzonych elementów znajduje 
+      się w argumencie funkcji <em>range()</em>. Elementy będą miały wartość 
+      obliczoną w modelu.
+               </p>
+<pre class="code-block">
+squares = [value**2 for value in range(1,11)]
+print(squares)
+</pre>
+    <h2 id="1.8.pieceoflist">1.8. Wycinek listy.</h2>
+               <p>
+                       Powiedzmy, że do obliczeń potrzebujemy dwóch środkowych wartości z listy.
+      Aby wydobyć je w najbardziej efektywny sposób możemy użyć 
+      <strong>wycinka listy</strong>. Wycinek tworzymy, podając w miejscu 
+      indeksu przy normalnym odwoływaniu się do listy, zakres składający się z 
+      wartości początkowej (<strong>uwaga</strong>, liczonej od 0), dwukropka 
+      (<strong>:</strong>) oraz wartości końcowej, z tym, że z wartością 
+      końcową jest identycznie co w przypadku funkcji <em>range().</em> Chcąc 
+      stworzyć wycinek z drugiego oraz trzeciego elementu, należy policzyć od 0,
+      czyli drugi element będzie mieć indeks 1, zakres końcowy trzeba podać o 1
+      większy więc licząc od 0 trzeci element to 2 oraz jeszcze 1 więc koniec, 
+      końców zakres końcowy to 3.
+               </p>
+<pre class="code-block">
+even_numbers = list(range(2,11,2))
+evenn_slice = even_numbers[1:3]
+</pre>
+               <p>
+                       Zakres wartości w wycinkach, jest nieco bardziej elastyczny. Na przykład 
+      chcemy wszystkie elementy do czwartego to zamiast <em>[0:4]</em> podajemy
+      po prostu <em>[:4]</em> możemy pominąć wartość początkową, wtedy 
+      domyślnie będzie <em>0</em>. Podobnie jest z wartością końcową 
+      <em>[2:]</em> ten zakres oznacza, że wycinek będzie zawierał wszystkie 
+      elementy od 3 do końca listy. Podobnie jak w przypadku indeksów, możemy 
+      podać ujemne wartości, przyczym podajemy tylko wartość początkową. Taki 
+      wycinek będzie zawierać elementy od tego wskazanego do końca listy. Przy 
+      podawaniu warto pamiętać że ostatni element to -1, im większa wartość ujemna tym bliżej początku listy jesteśmy.
+               </p>
+<pre class="code-block">
+even_numbers = list(range(2,11,2))
+end_values = even_numbers[-2:]
+</pre>
+    <h3 id="1.8.1.stepinpieceoflist">1.8.1. Krok w wycinku listy</h3>
+               <p>
+                       Zakres wycinku ma możliwość podania trzeciego argumentu, wartości kroku 
+      przy tworzeniu wycinka.
+               </p>
+<pre class="code-block">
+numbers = list(range(1,11))
+non_even_numbers=numbers[0::2]
+</pre>
+    <h3 id="1.8.2.iterationviapieceoflist">1.8.2. Iteracja przez wycinek listy</h3>
+               <p>
+                       Do wskazania pętli <em>for</em> możemy użyć wycinka listy. Na poniższym
+      przykładzie zaprezentowano jak należy to wykonać:
+               </p>
+<pre class="code-block">
+numbers = list(range(1,11))
+for value in numbers[0::2]:
+       print(value)
+</pre>
+    <h3 id="1.8.3.copyoflist">1.8.3. Kopia listy</h3>
+               <p>
+                       Często może zdarzyć się taka sytuacja, że chcemy zachować pierwotną 
+      wersję listy, ale musimy użyć jej wartości do jakiś operacji, które mogą 
+      naruszyć wartości jakiś jej elementów, w tym wypadku możemy stworzyć 
+      kopię listy.
+               </p>
+<pre class="code-block">
+cars = ['audi', 'bmw', 'renault', 'honda']
+cars_bkp = cars[:]
+</pre>
+    <h2 id="1.9.tuplets">1.9. Krotki</h2>
+               <p>
+                       Może zdarzyć się potrzeba posiadania listy stałych, których wartość nie 
+      może zmienić się przez cały cykl życia programu. Z taką listą jest już 
+      lepiej w niż ze zwykłymi stałymi. Taką listę nazywa się 
+      <strong>krotką</strong>. Definiowanie krotki, przypomina definiowanie 
+      listy, jednak zamiast nawiasów kwadratowych, mamy zwykłe okrągłe. 
+      Definicja wygląda w następujący sposób:
+               </p>
+<pre class="code-block">
+rgb = ('red', 'green', 'blue')
+print(rgb[0])
+print(rgb[1])
+print(rgb[2])
+</pre>
+               <p>
+                       Dostęp do elementów krotki, jest identyczny jak do elementów listy, co 
+      zostało zobrazowane powyżej. Teraz dla eksperymentu możemy spróbować 
+      zmienić jeden z elementów krotki.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; rgb = ('red', 'green', 'blue')
+&gt;&gt;&gt; rgb
+('red', 'green', 'blue')
+&gt;&gt;&gt; rgb[0]='yellow'
+&gt;&gt;&gt; Traceback (most recent call last):
+       File "<stdin>", line 1, in <module>
+TypeError: 'tuple' object does not support item assignment
+</pre>
+               <p>
+                       Iteracja przebiega tak samo jak na listach. Jedyną rzeczą jaką możemy 
+      zrobić przy krotce aby zmodyfikować jej zawartość, jest jej nadpisanie.
+               </p>
+<pre class="code-block">
+rgb = ('red', 'green', 'blue')
+print(rgb[0])
+print(rgb[1])
+print(rgb[2])
+
+rgb = ('cyan', 'yellow', 'magenta', 'black')
+</pre>
+               <p>
+                       Krotka zawierająca jedną wartość musi zawierać przecinek na końcu, 
+      ponieważ dzięki niemu zmienna jest rozpoznawana jako krotka.
+               </p>
+    <h2 id="1.10.conditionalexpressions">1.10. Wyrażenia warunkowe</h2>
+               <p>
+                       Każdy bardziej rozbudowany program będzie potrzebował instrukcji 
+      decyzyjnej. Te instrukcje uruchamiają blok kodu na podstawie testów 
+      warunkowych. Najprostszym z nich jest sprawdzenie równości.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; car = 'Audi'
+&gt;&gt;&gt; car == 'audi'
+False
+</pre>
+               <p>
+                       W powyższym przykładzie wyszedł na jaw bardzo ważny szczegół, Python jest
+      <em>case-sensitive</em>, rozróżnia wielkość liter. Dlatego warto przed 
+      jakimkolwiek testami warunkowymi przeprowadzić normalizacje.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; car = 'Audi'
+&gt;&gt;&gt; car.lower() == 'audi'
+True
+</pre>
+               <p>
+                       Kolejnym testem jaki możemy przeprowadzić na wszystkich typach danych 
+      jest sprawdzenie nierówności.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt;  car = 'Audi'
+&gt;&gt;&gt;  car.lower() != 'audi'
+False
+</pre>
+               <p>
+                       Porównania mniejsze niż, mniejsze bądź równe, większe niż, większe bądź 
+      równe, są testami wykonywanymi na liczbach. Nawet jeśli zestawimy sobie w
+      porównaniu dwa ciągi znaków, to Python porówna wartości z tablicy ASCII 
+      pierwszych znaków i na podstawie tego zostanie zwrócona 
+      wartość logiczna <em>True</em> lub <em>False</em>.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; age = 19
+&gt;&gt;&gt; age &gt; 21
+True
+&gt;&gt;&gt; age &gt;= 21
+True
+&gt;&gt;&gt; age &gt; 21
+False
+&gt;&gt;&gt; age &gt;= 21
+False
+car1 = 'audi'
+&gt;&gt;&gt; car2 = 'bmw'
+&gt;&gt;&gt; car1 &gt; car2
+False
+&gt;&gt;&gt; car2 &gt; car1
+True
+&gt;&gt;&gt; car2='Kamaz'
+&gt;&gt;&gt; car1 &gt; car2
+True
+</pre>
+               <p>
+                       Czasami może być tak, że takie najzwyklejsze testy jak te przeprowadzone 
+      powyżej nie wystarczą, aby instrukcja warunkowa uruchomiła blok kodu 
+      potrzebne będzie sprawdzenie kilku połączonych ze sobą warunków do 
+      łączenia ze sobą testów służą operatory logiczne.
+               </p>
+               <ul>
+                       <li><strong>and</strong> - operator służy do mnożenia wyników 
+          pomniejszych wyrażeń logicznych, używany gdy wszystkie warunki muszą
+          zwrócić tę samą wartość logiczną.</li>
+                       <li><strong>or</strong> - operator służy do dodawania wyników 
+          pomniejszych wyrażeń logicznych, używany gdy ocena końcowa testu 
+          wynika z sum poszczególnych wyrażeń.</li>
+                       <li><strong>not</strong> - operator służy do negowania wyniku całego 
+          wyrażenia. Negowanie polega na odwróceniu wartość, kiedy mamy 
+          <em>True</em> to po zanegowaniu otrzymamy <em>False</em> i vice 
+          versa.</li>
+               </ul>
+<pre class="code-block">
+age = 19
+(age &gt;= 13) and (age &gt; 20)
+True
+</pre>
+               <p>
+                       Słowa kluczowego <code class="code-inline">in</code> nie wykorzystujemy 
+      tylko w pętli <em>for</em>, możemy również je wykorzystać do wyrażenia 
+      warunkowego, w którym to możemy określić czy dana wartość znajduje się na
+      liście.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt;  pojazdy = ['audi', 'bmw', 'Kamaz']
+&gt;&gt;&gt; 'audi' in pojazdy
+True
+</pre>
+               <p>
+                       Dodając słowo kluczowe <code class="code-inline">not</code> przed słowem 
+      <em>in</em> możemy sprawdzić czy danej wartości nie ma na liście.
+               </p>
+<pre class="code-block">
+pojazdy = ['audi', 'bmw', 'Kamaz']
+'audi' not in pojazdy
+False
+</pre>
+               <h2 id="1.11.ifinstruction">1.11. Konstrukcja if</h2>
+               <p>
+                       Oczywiście do sterowania wykonaniem programu za pomocą testów warunkowych
+      służy 
+      instrukcja <strong>if</strong>, które jest częścią dużej konstrukcji
+      warunkowej, składającej się z polecenia <em>if</em>, rozpoczynającego 
+      całą konstrukcje i definiującego pierwszy test warunkowy, jeśli test 
+      zwrócić wartość <em>True</em> zostanie wykonany blok kodu instrukcji 
+      <em>if</em>.
+               </p>
+<pre class="code-block">
+if test_warunkowy:
+       #blok_kodu_instrukcji_if
+</pre>
+               <p>
+                       A co jeśli test warunkowy zwróci wartość <em>False</em>, w tym wypadku 
+      możemy poddać wykonanie programu jeszcze jednemu warunkowi za pomocą
+      instrukcji <strong>elif</strong> lub za pomocą ogólnego bloku
+      przeznaczonego dla tego przypadku - <strong>else</strong>. Powiedzmy, że
+      chcemy sprawdzić jeszcze jeden warunek.
+               </p>
+<pre class="code-block">
+if test_warunkowy:
+       #blok_kodu_instrukcji_if
+elif test_warunkowy2:
+       #blok_kodu_instrukcji_elif
+</pre>
+               <p>
+                       Co jeśli oba warunki zawiodą to powinniśmy zdefiniować kod blok kodu dla 
+      takiej sytuacji. Z racji tego iż można pominąć w Pythonie blok 
+      <strong>else</strong>, ja zachęcam do jego stosowania. Autor książki 
+      podaje że:
+               </p>
+               <blockquote>
+                       <p>
+                               Blok else jest wykorzystywany w sytuacji, gdy nie został spełniony 
+        żaden warunek z warunków wcześniej zdefiniowanych za pomocą poleceń 
+        <em>if</em> lub <em>elif</em>. Brak spełnienia warunku może wynikać z 
+        podania nieprawidłowych danych lub danych o złośliwym działaniu. 
+        Jeżeli istnieje konkretny, ostateczny warunek do sprawdzenia, rozważ 
+        użycie bloku <em>elif</em> i całkowite pominięcie bloku <em>else</em>.
+        W ten sposób zyskasz absolutną pewność, że kod będzie wykonywany 
+        jedynie po spełnieniu oczekiwanych warunków.
+                       </p>
+               </blockquote>
+               <p>
+                       Moim zdaniem blok domyślny przy nie spełnieniu żadnego warunku, daje nam 
+      szanse na reakcje na nieprawidłowe dane wejściowe. Najprościej jeśli nie 
+      spełniony został żaden warunek to kończymy działanie programu.
+               </p>
+<pre class="code-block">
+if test_warunkowy:
+       #blok_kodu_instrukcji_if
+elif test_warunkowy2:
+       #blok_kodu_instrukcji_elif
+else:
+       #blok_kodu_else
+</pre>
+               <p>
+                       Przydatną rzeczą jaką możemy zrobić z poleceniem 
+      <code class="code-inline">if</code> jest sprawdzenie przed rozpoczęciem 
+      pracy z listą, czy lista aby nie jest pusta.
+               </p>
+<pre class="code-block">
+cars=[]
+
+if cars:
+       for value in cars:
+               print(value)
+else:
+       print("Lista jest pusta")
+</pre>
+               <p>
+                       Jak widać powyżej, aby sprawdzić czy lista jest pusta w Pythonie 
+      wystarczy podać jej nazwę w miejscu testu warunkowego.
+               </p>
+               <h2 id="1.12.dictionaries">1.12. Słowniki</h2>
+               <p>
+                       <strong>Słowniki </strong>przypominają trochę format JSON 
+      zaimplementowany do języka programowania. Najprostszy słownik wygląda 
+      tak:
+               </p>
+<pre class="code-block">
+miasto1 = { 'kraj': 'Polska', 'powierzchnia': 517.14, 'populacja': 1_790_658, }
+</pre>
+               <p>
+                       Nie, przecinek na końcu nie jest błędem. Wskazuje tylko, że do słownika 
+      mogą zostać wprowadzone nowe <strong>pary klucz-wartość</strong>. 
+      <strong>Kluczem</strong> określamy wartość występującą w słowniku, 
+      zawsze ujętą w apostrofy lub cudzysłowie, z dwukropkiem na końcu, dzięki 
+      kluczowi będziemy odwoływać się do wartości pary. Dostęp do dowolnej 
+      wartości słownika:
+               </p>
+<pre class="code-block">
+miasto1 = { 'kraj': 'Polska', 'powierzchnia': 517.14, 'populacja': 1_790_658, }
+print(miasto1['powierzchnia'])
+</pre>
+               <p>
+                       Kiedy chcemy uzyskać dostęp do konkretnej wartości to przy słowniku, 
+      klucz zapisujemy w nawiasie kwadratowym. Analogicznie do tablic 
+      asocjacyjnych w innych językach programowania.
+               </p>
+               <p>
+                       Pusty słownik definiujemy podobnie jak pustą listę tylko
+      inne są znaki.
+               </p>
+<pre class="code-block">
+empty_dict={}
+</pre>
+               <p>
+                       Jeśli chcemy zmodyfikować wartość z jakieś pary, to tak 
+      samo jak w przypadku list, tylko że klucz zapisujemy w miejscu indeksu.
+               </p>
+<pre class="code-block">
+miasto1['kraj'] = 'Polska'
+</pre>
+               <p>
+                       Kiedy jakieś dane w słowniku staną nam się zbędne, możemy je usunąć przy 
+      pomocy polecenia <code class="code-inline">del</code>.
+               </p>
+<pre class="code-block">
+del miasto1['populacja']
+</pre>
+    <h3 id="1.12.1.addingnewvalues">1.12.1. Dodawanie nowych wartości do słownika</h3>
+               <p>
+                       Dodawanie nowych par klucz-wartość jest analogiczne do modyfikacji. Jeśli
+      będzie modyfikować wartość pod kluczem, który nie istnieje w słowniku to 
+      zostanie ona dodana jako nowa para.
+               </p>
+               <p>
+                       Co jeśli podczas pracy z słownikiem odwołamy się do klucza, który nie 
+      istnieje? Python zwróci błąd.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; print(miasto1['gestosc'])
+Traceback (most recent call last):
+       File "<stdin>", line 1, in <module>
+KeyError: 'gestosc'
+</pre>
+               <p>
+                       Python daje możliwość użycia specjalnej metody 
+      <code class="code-inline">get()</code>, która jest wstanie zwrócić 
+      wartość podanego jako argument klucza, lub też zdefiniowanego jako 
+      kolejny argument komunikatu, w momencie kiedy dany klucz nie istnieje. 
+      Komunikat nie jest wymagany w przypadku jego braku nie zostanie nam nic 
+      zwrócone. Metoda <em>get()</em> nadaje się jako test czy dany klucz 
+      istnieje.
+               </p>
+<pre class="code-block">
+if miasto1.get('gestosc'):
+       #Gęstość istnieje, zrób to i to
+else:
+       #Gęstość nie istnieje, zrób to i to
+</pre>
+    <h3 id="1.12.2.interationthroughthedictionary">1.12.2. Iteracja przez słownik</h3>
+               <p>
+                       Iteracji przez słownik w sumie są trzy rodzaje: przez pary, przez klucze 
+      i przez wartości. Przez pary, będzie prawdopodobnie najpopularniejszą z 
+      wszystkich rodzajów.
+               </p>
+<pre class="code-block">
+miasto1 = { 'kraj': 'Polska', 'powierzchnia': 517.14, 'populacja': 1_790_658, }
+
+for key,value in miasto1.items():
+       print(f"Klucz: {key}")
+       print(f"Wartość: {value}\n")
+</pre>
+               <p>
+                       Metoda <code class="code-inline">items()</code> w dużym skrócie rozbije
+      na dwie listy wszystkie klucze i wszystkie wartości, i to na nich pętla 
+      <em>for</em> w pamięci będzie przeprowadzać iteracje.
+               </p>
+    <h4 id="1.12.2.1.iterationthroughkeysandvalues">1.12.2.1. Iteracja przez klucze i wartości.</h4>
+               <p>
+                       Iteracja przez klucze, zadziała na podobnej zasadzie co przez parę jednak
+      do iteracji wykorzystuje się tylko jedną listę, listę z kluczami. 
+      Analogicznie z iteracją przez wartości tylko że listę z wartościami.
+               </p>
+<pre class="code-block">
+miasto1 = { 'kraj': 'Polska', 'powierzchnia': 517.14, 'populacja': 1_790_658, }
+
+for key in miasto1.keys():
+       print(f"Klucz: {key}\n")
+
+for value in miasto1.values():
+       print(f"Wartość: {value}\n")
+</pre>
+               <p>
+                       Metody <code class="code-inline">keys()</code> i 
+      <code class="code-inline">values()</code> tworzą listy, dlatego też
+      możemy przeprowadzić na nich iterację z wykorzystaniem pętli <em>for</em>
+      oraz <code class="code-inline">in</code>.
+               </p>
+               <p>
+                       W wydaniach Pythona począwszy od 3.7, słownik zachowuje kolejność, w 
+      której były dodawane pary. Podczas pracy z słownikiem jego domyślną 
+      uporządkowaniem jest kolejność dodawania par.
+               </p>
+               <p>
+                       Listę kluczy możemy obudować funkcją <em>sorted()</em> aby je 
+      uporządkować.
+               </p>
+    <h2 id="1.13.collections">1.13. Zbiory</h2>
+               <p>
+                       Klucze muszą być unikatowe, aby wartości się na siebie nie nakładały. Ale
+      wśród wartości już takich wymagań nie ma. Python udostępnia funkcję 
+      <strong>set()</strong>, która na podstawie przekazanej listy tworzy zbiór
+      z unikatowych elementów. Zbiór jest składniowo bardzo podobny do 
+      słownika, jednak zawiera sam wartości, nie zawiera on żadnych danych
+      porządkowych.
+               </p>
+<pre class="code-block">
+jezyki = {'python', 'ruby', 'c', 'python'}
+&gt;&gt;&gt; jezyki
+{'python', 'ruby', 'c'}
+</pre>
+               <p>
+                       Sposobem na to aby uzyskać dostęp do danych zapisanych na zbiorze jest 
+      iteracja lub konwersja na listę za pomocą funkcji <em>sorted()</em>. 
+      Należy pamiętać aby zapisać gdzieś listę zwróconą przez <em>sorted()</em>
+               </p>
+    <h2 id="1.14.nestingindatatypes">1.14. Zagnieżdznie złożonych typów danych</h2>
+               <p>
+                       Przedstawienie słowników umożliwia zaprezentowanie 
+      <strong>zagnieżdżania</strong>. Pozwala ono na umieszczenie jednego 
+      złożonego typu w drugim, możemy stworzyć między innymi 
+      listę słowników, listę w słowniku czy też słownik w słowniku. Listę 
+      słowników najlepiej rozpocząć od pustej listy, następnie czy to w skutek 
+      iteracji czy danych napływających do programu tworzyć nowy słownik i 
+      załadować go do listy za pomocą metody <em>append()</em>. Trochę 
+      eksperymentując zauważyłem ciekawą rzecz, mianowicie kiedy stworzyłem 
+      sobie model słownika powyżej iteracji, i chciałem odpowiednio według 
+      testów warunkowych modyfikować wartości modelu, to na listę trafiała 
+      tylko pierwsza aktualizacja przez całą iterację. Dostęp do danych 
+      zagnieżdżonych wygląda trochę jak tablice wielowymiarowe. 
+      W zależności od tego czy jest to lista słowników, to na początku podajemy
+      indeks a później klucz, w przypadku zagnieżdżenia listy w słowniku, 
+      sytuacja jest odwrotna.
+    </p>
+    <p>
+                       Ostatnim przypadkiem jest słownik w słowniku, tu podajemy klucz - klucz. 
+      Do operacji na zagnieżdżeniach warto wykorzystać metody stosowane do 
+      iteracji na słownikach. Ważną rzeczą stosowaną przy zagnieżdżeniach jest 
+      ich jak największe ograniczenie, jeśli algorytm zakłada większe 
+      zagnieżdżenie niż powyżej jednego poziomu (tj. każdy klucz zawiera 
+      pojedynczą listę lub każdy element listy zawiera słownik bez zagnieżdżeń),
+      to oznacza że ma on poważne wady konstrukcyjne i na pewno jest jakiś 
+      lepszy sposób na rozwiązanie tego problemu.
+               </p>
+    <h2 id="1.15.gettingdatafromuser">1.15. Pobieranie danych od użytkownika.</h2>
+               <p>
+                       Pobieranie danych od użytkowników jest realizowane dzięki funkcji 
+      <code class="code-inline">input()</code>. Funkcja ta jako argument 
+      przyjmuje, komunikat zachęcający użytkownika do wpisania danych tzw. 
+      znak zachęty. Dane wpisane przez użytkownika są zwracane w postaci ciągu
+      tekstowego.
+               </p>
+               <p>
+                       Jeśli musimy pobrać od użytkownika dane do obliczeń, to wartością 
+      zwracaną przez funkcje <em>input()</em> jest ciąg tekstowy. W tym wypadku
+      musimy dokonać konwersji na typ całkowity. Odpowiada za to funkcja 
+      <code class="code-inline">int()</code>, której wartością zwracaną jest
+      liczba całkowita, a argumentem dowolna wartość przypominająca liczbę, 
+      która ma zostać skonwertowana ja postać liczby całkowitej. Do obliczeń 
+      nie zawsze będziemy potrzebowali wartości całkowitej. Może zdarzyć się,
+      że będziemy potrzebować wartości zmiennoprzecinkowej, aby uzyskać wartość
+      w postaci liczby zmiennoprzecinkowej należy użyć funkcji 
+      <code class="code-inline">float()</code>. Te konwersje można odwrócić 
+      uzyskując ciąg tekstowy z liczb za pomocą funkcji 
+      <code class="code-inline">str()</code>.
+               </p>
+<pre  class="code-block">
+&gt;&gt;&gt; age = input("Ile masz lat?")
+Ile masz lat? 12
+&gt;&gt;&gt; age
+'12'
+&gt;&gt;&gt; age = int(age)
+&gt;&gt;&gt; age
+12
+&gt;&gt;&gt; age &gt;= 18
+False
+</pre>
+               <p>
+                       Konwersje można skrócić do jednej linii, obudowując funkcję 
+      <code class="code-inline">input()</code> funkcją funkcją 
+      <code class="code-inline">int()</code>.
+               </p>
+<pre class="code-block">
+age = int(input("Ile masz lat? "))
+Ile masz lat? 18
+&gt;&gt;&gt; age
+18
+&gt;&gt;&gt; age &gt;= 18
+True
+</pre>
+    <h2 id="1.16.modulooperator">1.16. Operator modulo (reszty z dzielenia).</h2>
+               <p>
+                       Przydatną rzeczą jeśli chodzi o obliczenia liczbowe wykorzystywane w 
+      programowaniu napewno jest operator modulo (<code class="code-inline">%</code>). 
+      Przyjmuje dwa operandy (dzielną i dzielnik), zwraca resztę z dzielenia 
+      dzielnej przez dzielnik. Najprostszym przykładem użycia operatora modulo 
+      (<strong>%</strong>) jest sprawdzenie czy dana wartość jest parzysta czy 
+      też nie.
+               </p>
+<pre class="code-block">
+if number % 2 == 0:
+       print(f"{number} jest liczbą parzystą.")
+else:
+       print(f"{number} nie jest liczbą parzystą.")
+</pre>
+               <h2 id="1.17.whileloop">1.17. Pętla while.</h2>
+               <p>
+                       Jeśli potrzebujemy pętli która działa do pewnego momentu, np. dopóki dana
+      zmienna ma wartość taką a taką, to wtedy musimy skorzystać z pętli 
+      <strong>while</strong>. Pętla ta działa dopóty, dopóki warunek 
+      umieszczony obok słowa kluczowego <code class="code-inline">while</code>
+      będzie zwracał wartość <em>True</em>. Pętla <em>while</em> nie posiada 
+      wbudowanego licznika, dlatego takowy licznik musimy sobie zbudować sami.
+               </p>
+<pre class="code-block">
+number=1
+while number &gt;= 10:
+       if number % 2 == 0:
+               print(f"{number} jest parzysta.")
+  else:
+               print(f"{number} nie jest parzysta.")
+  number += 1
+</pre>
+               <p>
+                       Wynik działania powyższego przykładu:
+               </p>
+<pre class="code-block">
+1 nie jest parzysta.
+2 jest parzysta.
+3 nie jest parzysta.
+4 jest parzysta.
+5 nie jest parzysta.
+6 jest parzysta.
+7 nie jest parzysta.
+8 jest parzysta.
+9 nie jest parzysta.
+10 jest parzysta.
+</pre>
+               <p>
+                       Zmienna number przybrała w tym przykładzie rolę danych, na których 
+      operujemy oraz licznika.
+               </p>
+               <p>
+                       Czasami może zajść potrzeba aby kontrolować wykonanie programu za pomocą 
+      pętli <em>while</em>. Powiedzmy że mamy aplikacje, która wyświetla nam 
+      listę opcji, następnie prosi nas jej wybór, wybieramy jedną z opcji, 
+      następnie po wykonaniu czynności dedykowanych dla tych opcji wracamy do
+      menu, gdzie znów możemy wybrać jedną z opcji lub zakończyć program. 
+      Konstrukcja takie aplikacji może opierać się na pętli <em>while</em>, 
+      której warunek zwraca wartość <em>True</em>, kiedy wybieramy opcje 
+      "Exit/Wyjście", no właśnie co się dzieje? Możliwości są trzy.
+               </p>
+               <ul>
+                       <li>Możliwość 1: Wybór konkretnej opcji przypisuje do zmiennej określoną 
+          wartość, pętla wykonuje się dopóty, dopóki wyżej wymieniona zmienna 
+          jest nie równa wartości przypisywanej po wyborze opcji 
+          "Exit/Wyjście".</li>
+                       <li>Możliwość 2: Przed rozpoczęciem pętli deklarowana zmienna tzw. flaga,
+          której przypisywana jest wartość <em>True</em>. Pętla wykonuje się do
+          momentu gdy wartość wartość flagi jest równa <em>True</em>. Wybranie 
+          opcji "Exit/Wyjście", zmienia wartość flagi na <em>False</em>, co 
+          powoduje nie spełnienie warunku, czego następstwem jest przerwanie 
+          pracy pętli.</li>
+                       <li>Możliwość 3: Kod zdefiniowany pod opcją "Exit/Wyjście" zawiera tylko
+          jedną instrukcję słowo kluczowe 
+          <code class="code-inline">break</code>. Instrukcja ta
+          powoduje zatrzymanie wykonania bloku kodu i przejście wykonania na 
+          pierwszą instrukcję po bloku kodu pętli.</li>
+               </ul>
+               <p>
+                       Istotną rzeczą dla każdej iteracji jest możliwość jej zrestartowania, 
+      kiedy gdzieś w kodzie pętli zostanie umieszczone słowo kluczowe 
+      <code class="code-inline">continue</code>, spowoduje powrót do 
+      sprawdzenia warunku a następnie wykonania bloku pętli od początku. To 
+      polecenie przydatne może być gdy chcemy pominąć jakieś elementy
+               </p>
+               <p>
+                       Przy pracy z pętlami while warto pamiętać o prawidłowym warunku, zmianie
+      licznika czy o zakończeniu pętli w odpowiednim momencie. Patrząc na pętle,
+      o której mówiłem akapit wcześniej, odnośnie sterowania programem to są to
+      pętle, które bez odpowiednich mechanizmów zatrzymujących będą wykonywać
+      się w nieskończoność. Warunek nie zawiera licznika. Zmienna w teście 
+      warunkowym bez mechanizmów stopujących nie zmieni swojej wartości. 
+      Chociaż i w pętlach <em>while</em> opartych na licznikach też łatwo o 
+      nieskończoną pętle. Wystarczy zapomnieć zmienić licznik na końcu bloku.
+               </p>
+               <p>
+                       Pętla <em>while</em> również nadaje się do pracy z listami czy słownikami,
+      jedną taką ciekawą rzeczą jeśli chodzi o listy jest taki mechanizm, że 
+      jeśli umieścimy w warunku pętli nazwę listy, to pętla będzie wykonywać 
+      się dopóki na tej liście będą jakieś elementy, mechanizmem kontroli tutaj
+      będzie pobieranie elementów listy za pomocą metody <em>pop()</em>. Jak w 
+      każdym innym teście warunkowym w warunku pętli <em>while</em> również 
+      istnieje możliwość użycia operatora <em>in</em>
+               </p>
+               <h2 id="1.18.function">1.18. Funkcje</h2>
+               <p>
+                       <strong>Funkcje</strong> służą do przygotowania bloku kodu , który możemy
+      później wykorzystać wielokrotnie w części głównej programu. Funkcje 
+      ułatwiają zarządzanie kodem, testowanie oraz ewentualne debugowanie z 
+      racji tego, iż jest to wydzielony fragment kodu, który możemy wykonywać 
+      niezależnie od pozostałej części programu.
+               </p>
+    <h3 id="1.18.1.functiondefinition">1.18.1. Definiowanie funkcji</h3>
+               <p>
+                       Definiowane funkcji rozpoczynamy od słowa kluczowego 
+      <code class="code-inline">def</code> następnie podajemy nazwę funkcji po 
+      nazwie umieszczamy <span style="text-decoration: underline;">bez spacji</span>
+      parę nawiasów okrągłych po nawiasach oczywiście występuje dwukropek. 
+      W nowej linii od pojedynczego tabulatora rozpoczynamy blok kodu funkcji.
+               </p>
+    <h4 id="1.18.1.1.commentsinfunction">1.18.1.1 Komentarze w funkcji</h4>
+               <p>
+                       Komentarze w funkcji umieszcza się jako tzw. <strong>docstring</strong>, 
+      którego zadaniem jest opis działania funkcji. Wszystko co zostało ujęte 
+      pomiędzy parą potrójnych cudzysłowów (<strong>"""..."""</strong>) jest 
+      traktowane jako <em>docstring</em>.
+               </p>
+<pre class="code-block">
+def hello_user():
+       """To jest funkcja, która wita użytkownika"""
+</pre>
+               <p>
+                       <em>Docstring</em> wykorzystywany jest przez Python do tworzenia opisów 
+      funkcji podczas generowania dokumentacji dla poszczególnych projektów.
+               </p>
+    <h4 id="1.18.1.2.functionparameters">1.18.1.2. Parametry funkcji</h4>
+               <p>
+                       Bardziej zaawansowane funkcje, które mają nieco więcej czynności niż 
+      wypisane "Witaj świecie!", zazwyczaj potrzebują jakiś danych z zewnątrz.
+      Dane, <strong>parametry funkcji</strong> deklarujemy w nawiasie zaraz 
+      obok nazwy funkcji, w ten sposób zaznaczamy że nasza funkcją będzie 
+      wymagać jakiś informacji do działania.
+               </p>
+<pre class="code-block">
+def hello_user(username):
+       """To jest funkcja, która wita użytkownika"""
+       print(f"Witaj, {username}!")
+</pre>
+               <p>
+                       Prawdziwe dane przekazujemy w momencie wywołania funkcji w części głównej.
+      <strong>Wywołanie funkcji</strong> jest realizowane poprzez podanie jej 
+      nazwy w raz parą nawiasów okrągłych, w których w zależności od definicji
+      umieszczamy dane niezbędne do jej wykonania. Oczywiście jeśli funkcja nie
+      potrzebuje żadnych danych, para nawiasów pozostaje pusta.
+               </p>
+<pre class="code-block">
+uname = 'xf0r3m'
+hello_user(uname)
+</pre>
+    <h4 id="1.18.1.3.positionalarguments">1.18.1.3. Argumenty pozycjne</h4>
+               <p>
+                       Zmienne lub też dane umieszczone w wywołaniu funkcji nazywamy 
+      <strong>argumentami</strong>. Argumenty może przekazać do funkcji na dwa
+      różne sposoby. Pierwszy sposób to sposób klasyczny, sposób 
+      <strong>argumentów pozycyjnych</strong>, opera się on kolejności. 
+      W jakiej kolejności parametry zostały podane w definicji funkcji, to w 
+      takiej samej kolejności należy przekazać do funkcji argumenty.
+               </p>
+<pre class="code-block">
+def func1(para1, para2, para3):
+       print(f"{para1} {para2} {para3}")
+
+func1('Ala', 'ma', 'kota')
+# Ala ma kota
+</pre>
+               <p>
+                       Python nie zwróci błędu jeśli pomylimy kolejność. Ale wynik działania 
+      funkcji może być nieoczekiwany.
+               </p>
+<pre class="code-block">
+def func1(para1, para2, para3):
+       print(f"{para1} {para2} {para3}")
+       #arg1=param3, arg2=param2 arg3=param1
+
+func1('kota', 'ma', 'Ala')
+# kota ma Ala
+</pre>
+    <h4 id"1.18.1.4.keywordsarguments">1.18.1.4. Argumenty w postaci słów kluczowych</h4>
+               <p>
+                       Drugą metodą jest przekazywanie argumentów w postaci słów kluczowych. 
+      Opiera się ona zasadzie par "nazwa=wartość", w tym przypadku 
+      "parametr=argument". Tutaj kolejność nie ma znaczenia. Ponieważ już 
+      podczas wywołania przypisujemy parametrowi wartość <em>argumentu</em>.
+               </p>
+<pre class="code-block">
+def func1(para1, para2, para3):
+       print(f"{para1} {para2} {para3}")
+
+func1(para3='kota', para1='Ala', para2='ma')
+# Ala ma kota
+</pre>
+               <p>
+                       Może zdarzyć się że musimy przygotować funkcję dla typowych, ciągle 
+      powtarzających się danych, które mogli byśmy podać już podczas definicji
+      funkcji. A jeśli zajdzie taka potrzeba będziemy mogli nadpisać 
+      <strong>wartość domyślną</strong> parametrów funkcji dla innych danych.
+               </p>
+<pre class="code-block">
+def func1(para3, para1='Ala', para2='ma'):
+       print(f"{para1} {para2} {para3}"
+
+func1('psa')
+# Ala ma psa
+func1('kota')
+# Ala ma kota
+func1('nierówno pod sufitem')
+# Ala ma nierówno pod sufitem
+
+func1('w LoL-a', 'Tola', 'gra')
+# Tola gra w LoL-a
+</pre>
+               <p>
+                       Jak można zauważyć parametry w definicji funkcji zmieniły kolejność, jest
+      wymagane przez Python, aby parametry, które będą przekazywane jako 
+      argumenty pozycyjne zawsze były na pierwszym miejscu i tak też należy 
+      przekazywać argumenty.
+               </p>
+    <h4 id="1.18.1.5.returnvaluesfromfunction">1.18.1.5. Zwracanie wartości przez funkcje</h4>
+               <p>
+                       Funkcje często są wykorzystywane do obliczeń. Niestety co nam po 
+      obliczonych wartościach kiedy pozostają one w bloku kodu funkcji. Możemy 
+      oczywiście zwrócić wartość uzyskaną przez funkcje. Służy do tego słowo 
+      kluczowe <code class="code-inline">return</code>.
+               </p>
+<pre class="code-block">
+def pitagoras_need_c_square(a,b):
+       return (a**2 + b**2)
+
+c_square = pitagoras_need_c_square(3,4)
+print(c_square)
+# 25
+</pre>
+               <p>
+                       Jak widać przy zwrocie wartości wywołanie funkcji musimy przypisać do 
+      zmiennej.
+               </p>
+    <h3 id="1.18.2.passingcomplexdatatypestofunc">1.18.2. Przekazywanie do funkcji złożonych typów dancyh</h3>
+               <p>
+                       Do funkcji możemy przekazać nie tylko pojedyncze dane oraz zmienne, ale 
+      również całe listy i składniowo nie rożni się to przekazania pojedynczych
+      danych.
+               </p>
+<pre class="code-block">
+def iteration_via_list(l):
+       for list_element in l:
+               print(f"{list_element}")
+</pre>
+               <p>
+                       Warto zaznaczyć, że tak jak przekazujemy zmienne, to przekazujemy ich 
+      wartość. W przypadku listy prawdopodobnie zamiast wartość przekazywane 
+      jest miejsce w pamięci rozpoczęcia listy, przez to lista zdefiniowana w 
+      głównej części programu może zostać przez tą funkcję zmodyfikowana. 
+      Istnieje technika dzięki, której możemy się przed tym uchronić, możemy 
+      przekazać kopię listy (wycinek od pierwszego do ostatniego elementu).
+               </p>
+<pre class="code-block">
+received_cars = ['audi', 'bmw', 'toyota', 'subaru'];
+repaired_cars = [];
+
+def repair_car(rcev_cars, rep_cars):
+
+       while rcev_cars:
+               repaired_car = rcev_cars.pop()
+               print(f"Naprawiam: {repaired_car}")
+               rep_cars.append(repaired_car)
+
+def print_raport(rcev_cars, rep_cars):
+       print("Otrzymano następujące samochody: ")
+       for rcev_car in rcev_cars:
+               print(f"\t - {rcev_car}")
+
+       print("\nNaprawiono następujące samochody: ")
+       for rep_car in rep_cars:
+               print(f"\t - {rep_car}")
+
+repair_car(received_cars[:], repaired_cars)
+repaired_cars.reverse()
+print_raport(received_cars, repaired_cars)
+</pre>
+               <p>
+                       O ile nie istnieje żaden ważny powód należy przekazywać funkcjom 
+      prawdziwą listę, użycie kopii może być mniej efektywne oraz zajmować 
+      więcej pamięci.
+               </p>
+    <h3 id="1.18.3.undefinedamountofargs">1.18.3. Przekazywanie nieokreślonej liczy argumentów</h3>
+               <p>
+                       Podczas prac z kodem możemy spotkać się z takim problemem że nie będziemy
+      potrafili przewidzieć ile może być potrzebnych argumentów. W Pythonie 
+      możliwe jest przekazanie dla parametru dowolnej liczby argumentów. Taki 
+      parametr definiuje się z gwiazdka (<strong>*</strong>) przed nazwą.
+      Przekazanie kilku argumentów pod ten parametr powoduje utworzenie krotki
+      z tymi argumentami, przez które możemy normalnie iterować.
+               </p>
+<pre class="code-block">
+def make_pizza(*toppings):
+    print("Tworze pizzę: ")
+    for toping in topings:
+        print(f"\tDodaję: {topping}")
+
+make_pizza('ser', 'szynka', 'pieczarki')
+</pre>
+               <p>
+                       Nic nie stoi na przeszkodzie aby użyć np. argumenty pozycyjnego wraz z 
+      <strong>krotką argumentów</strong>. Należy oczywiście pamiętać o 
+      kolejności. Python zwróci błąd ponieważ za parametrem tego typu nie 
+      powinny znajdować się już żadne inne parametry.
+               </p>
+               <p>
+                       Istnieje również metoda, która umożliwi przekazanie wielu argumentów jako
+      słów kluczowych. Podobnie do powyższego przypadku wykorzystane są 
+      gwiazdki (<strong>**</strong>), dwie a nie jedna. Po przekazaniu par 
+      nazwa-wartość w funkcji zostanie utworzony słownik.
+               </p>
+<pre class="code-block">
+def make_car(make, model, **car):
+    car2={}
+    car2['make'] = make.title()
+    car2['model'] = model.title()
+
+    for k,v in car.items():
+        car2[k]=v
+
+    return car2
+
+car = make_car('subaru', 'outback', color='blue', towPackage=True)
+
+print(car)
+</pre>
+               <p>
+                       Ten przykład jest nieco bardziej skomplikowany. Przy korzystaniu z 
+      przekazywania wielu argumentów za pomocą słów kluczowych należy pamiętać
+      o tym że dane w słowniku są ułożone według kolejności dodawania 
+      danych do słownika <span style="text-decoration: underline;">(Ta 
+      zależność pojawiła się dopiero od Pythona &gt;=3.7)</span>. W tym 
+      przypadku dane do słownika przekazane przez '<em>**car</em>' trafiają 
+      jeszcze przed przejściem do wykonywania kodu funkcji. Dlatego jeśli 
+      chcemy mieszać argumenty jak na powyższym przykładzie, należy o tym
+      pamiętać. Poprzez utworzenie nowego słownika i na początku dodanie 
+      argumentów pozycyjnych następnie przepisanie danych ze słownika 
+      <code class="code-inline">car</code> do słownika 
+      <code class="code-inline">car2</code> danych dodanych jako wielu 
+      argumentów słów kluczowych. W ten sposób uzyskaliśmy słownik o kolejności
+      identycznej jak argumenty podane w funkcji.
+               </p>
+    <h2 id="1.19.modules">1.19. Moduły</h2>
+               <p>
+                       W Pythonie w prosty sposób możemy utworzyć tzw. <strong>moduły</strong> w
+      innych językach możemy nazwać je np. plikami nagłówkowymi. Tworzymy je 
+      poprzez utworzenie oddzielnego pliku i wpisanie tam wszystkich funkcji. 
+      Kiedy mamy funkcje w oddzielnym pliku pozostaje je tylko zaimportować. 
+      Poniżej znajdują się metody importu, wraz z przykładem użycia funkcji z 
+      zaimportowanego modułu.
+               </p>
+<pre class="code-block">
+#import sandwich
+#sandwich.make_sandwich('pszenne', 'szynka', 'ser', 'ketchup')
+
+#from sandwich import make_sandwich
+#make_sandwich('pszenne', 'szynka', 'ser', 'ketchup')
+
+#from sandwich import make_sandwich as fn
+#fn('pszenne', 'szynka', 'ser', 'ketchup')
+
+#import sandwich as mn
+#mn.make_sandwich('pszenne', 'szynka', 'ser', 'ketchup')
+
+#from sandwich import *
+#make_sandwich('pszenne', 'szynka', 'ser', 'ketchup')
+</pre>
+                       <p>
+                               Możemy używać słowa kluczowego <code class="code-inline">import</code> 
+        do zaimportowania całego modułu, lub zaimportować konkretną funkcję z 
+        danego modułu poprzez kombinacje słów kluczowych 
+        <code class="code-inline">from</code> oraz <em>import</em>. Gdzie po 
+        słowie <em>from</em> podajemy nazwę modułu, po słowie <em>import</em> 
+        podajemy nazwę funkcji. Ciekawą techniką jest tworzenie 
+        <strong>aliasów</strong> dla zaimportowanych modułów lub funkcji. Po 
+        nazwie modułu lub funkcji oraz po słowie kluczomym 
+        <code class="code-inline">as</code> podajemy alias czyli taką nazwę 
+        zastępczą lub pseudonim. Tworzenie aliasów przydaje się gdy np. mamy 
+        podejrzenie, że funkcja w module ma taką samą nazwę jak funkcja w 
+        głównej części programu. Linia przed ostatnia z powyższego przykładu 
+        mogą wydawać się równoznaczne, ale ostatnii przykład pokazuje nam w
+        jaki sposób możemy zaimportować funkcje z modułu. Ta czynność pozwala
+        na pominięcie prefixu nazwy modułu
+                       </p>
+                       <h2 id="1.20.objectorientedprograming">1.20. Programowanie zorientowane obiektowo</h2>
+                       <p>
+                               <strong>Programowanie zorientowane obiektowo</strong> jest metodą, 
+        która pozwala programistom przedstawiać przy użyciu komputera rzeczy 
+        znane nam z realnego świata. Weźmy takiego człowieka. Człowiek jest 
+        <strong>obiektem</strong> zarówno w znanym nam świecie, jak i również 
+        może zostać przedstawiony jako obiekt w świecie wirtualnym. Jeśli 
+        człowiek staje się obiektem w ujęciu programistycznym, to jego cechy 
+        szczególne stają się <strong>właściwościami/atrybutami</strong> obiektu.
+        Czynności jakie wykonuje mogą być <strong>metodami</strong>.
+      </p>
+      <p>
+        Człowiek jest przedstawicielem gatunku. Gatunku ludzkiego. Obiekty są 
+        również przedstawicielami gatunku jaki sobie zdefiniujemy. Tym 
+        gatunkiem są <strong>klasy</strong>.
+                       </p>
+                       <p>
+                               <strong>Definicje klasy</strong> rozpoczynamy od słowa kluczowego 
+        <code class="code-inline">class</code><em> </em>następnie podajemy 
+        nazwę tej klasy oraz zaraz obok nazwy bez spacji parę nawiasów
+        okrągłych oraz dwukropek. W następnej linii po jednym znaku tabulacji 
+        możemy rozpoczynać definicję klasy. Klasa z poziomu kodu źródłowego 
+        składa się głównie z funkcji, które tutaj nazywają się metodami. 
+        Pierwszą definiowaną metodą jest metoda 
+        <code class="code-inline">__init__</code>. <strong>Uwaga</strong>, przy
+        zapisie tej nazwy należy uważać na to, że jest ona obudowana dwoma 
+        znaki podkreślenia (<strong>__</strong>). Ta metoda jest metodą 
+        specjalną, ma za zadanie zainicjować właściwości zapisane w jej bloku.
+        Te atrybuty będą atrybutami obiektu. Argumenty dla tej metody są 
+        przekazywane podczas tworzenia egzemplarza klasy, czyli obiektu.
+                       </p>
+<pre class="code-block">
+class User():
+    def __init__(self,firstname,lastname,age,sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+</pre>
+                 <p>
+                         Parametr <code class="code-inline">self</code> jest obiektem, który 
+        będzie tworzony na podstawie tej klasy. Słowo kluczowe <em>self</em> 
+        będzie oznaczać po prostu obiekt tej klasy. To atrybutowi obiektu tej 
+        klasy w metodzie <em>__init__</em> nadajemy wartość parametru 
+        <code class="code-inline">firstname</code>. Z racji tego że obiekt jest 
+        egzemplarzem klasy stąd słowo self (samemu sobie).
+                 </p>
+      <h3 id="1.20.1.object">1.20.1. Objekt</h3>
+                 <p>
+                         Egzemplarz klasy (obiekt) tworzymy nadając zmiennej wartości w postaci 
+        wywołania zdefiniowanej wcześniej klasy.
+                 </p>
+<pre class="code-block">
+user1 = User('Jan', 'Nowak', '47', 'M')
+</pre>
+                 <p>
+                         Argumentami przekazywanymi klasie są tak naprawę argumenty dla metody 
+        <em>__init__</em>, ponieważ to ona jest uruchamiana podczas tworzenia 
+        obiektu. Argument <em>self</em> jest przekazywany automatycznie.
+                 </p>
+                 <p>
+                         Powiedzmy że mamy utworzy obiekt 'user1'. Dostęp do jego właściwości 
+        uzyskujemy dzięki notacji kropki (<code class="code-inline">.</code>).
+               </p>
+<pre class="code-block">
+print(f"Witaj {user1.firstname} {user1.lastname}")
+# &gt;&gt;&gt; Witaj Jan Nowak
+</pre>
+    <h3 id="1.20.2.methods">1.20.2. Metody</h3>
+               <p>
+                       Mamy już cechy szczególne, to teraz pora na czynności jakie ten obiekt 
+      może wykonać. Do opisu czynności obiektu wykorzystuje się metody, czyli 
+      funkcje w kontekście obiektowym. Z pierwszą metodą mieliśmy już do 
+      czynienia przy okazji metody <em>__init__</em>, może jest ona nieco 
+      przezroczysta, jednak to nadal metoda. W poniższym przykładzie stworzymy
+      sobie metodę, która opisze nam tego użytkownika, bo na razie właściwości
+      to suche dane.
+               </p>
+<pre class="code-block">
+def describe_user(self):
+    print(f"Imie i nazwisko: {self.firstname} {self.lastname}")
+    print(f"\t-wiek: {self.age}\n\t-płeć: {self.sex}")
+</pre>
+               <p>
+                       Metoda tym różni się od funkcji, że znajduje się wewnątrz klasy oraz tym,
+      że zawsze ma parametr <em>self</em>, który pozwala jej na dostęp do 
+      właściwości obiektu. Metody wywołujemy prawie przez cały czas pod czas 
+      zabawy Pythonem, więc wywołanie metody naszej klasy nie powinno być 
+      problemem.
+               </p>
+<pre class="code-block">
+user1.describe_user()
+</pre>
+    <h3 id="1.20.3.workingonattributs">1.20.3. Praca z atrybutami obiektów.</h3> 
+               <p>
+                       Właściwości/atrybuty obiektu nie muszą być zawsze przekazywane przez 
+      użytkownika podczas tworzenia obiektu mogą przyjmować 
+      <strong>wartości domyślne</strong> w zdefiniowane wewnątrz<em> 
+      </em>metody <em>__init__</em>.
+               </p>
+<pre class="code-block">
+class User():
+    def __init__(self, firstname, lastname, age, sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+        self.rank = 'Junior user'
+</pre>
+               <p>
+                       Wraz z biegiem programu opartego na obiektach ich właściwości mogą, 
+      czasami wręcz muszą się zmienić. W Pythonie możemy to zrealizować na trzy
+      sposoby.
+               </p>
+               <ul>
+                       <li><strong>Sposób 1</strong>: Zmiana bezpośrednia. Po prostu bierzemy 
+          obiekt następnie za pomocą <strong>notacji kropki</strong> uzyskujemy
+          dostęp
+          do właściwości i za pomocą operatora przypisania (<strong>=</strong>) 
+          nadajemy atrybutowi nową wartość. Ta technika generalnie nie jest 
+          polecana.</li>
+                       <li><strong>Sposób 2</strong>: Nowa metoda przeznaczona do aktualizowania
+          wartości poszczególnych właściwości. Tworzymy metodę w parametrem 
+          <em>self</em> oraz z parametrem, który będzie przechowywał nową 
+          wartość metody, w bloku w metody do atrybutów uzyskujemy dostęp 
+          poprzez parametr <em>self</em> oraz notację kropki i nadajemy mu nową
+          wartość parametru, która ma zostać przekazana w postaci argumentu z 
+          głównej części programu.</li>
+                       <li><strong>Sposób 3</strong>: Nowa metoda inkrementująca lub 
+          dekrementując wartość właściwość. Ta metoda od tej ze sposobu nr. 2 
+          różni się w zasadzie tylko znakiem w tym wypadku jest to 
+          <strong>+=</strong> a nie <strong>=</strong>. Wartość o jaką będziemy
+          zmieniać naszą właściwość również podajemy w postaci parametru. 
+          Oczywiście może to zależeć od metody.</li>
+               </ul>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 1:</span>
+               </p>
+<pre class="code-block">
+user1.rank = 'Standard user'
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 2:</span>
+               </p>
+<pre class="code-block">
+class User():
+    def __init__(self, firstname, lastname, age, sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+        self.rank = 'Junior user'
+
+    def promote_user(self, new_rank):
+        self.rank = new_rank
+
+user1 = User('Jan', 'Nowak', '47', 'M')
+user1.promote_user('Standard user')
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 3:</span>
+               </p>
+<pre class="code-block">
+class User():
+    def __init__(self, firstname, lastname, age, sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+        self.rank = 'Junior user'
+
+    def promote_user(self, new_rank):
+        self.rank = new_rank
+
+    def happy_birthday(self):
+        print(f"Happy Birthday {self.firstname.title()}")
+        self.age += 1
+
+user1 = User('Jan', 'Nowak', '47', 'M')
+user1.promote_user('Standard user')
+user1.happy_birthday()
+</pre>
+  <h3 id="1.20.4.inheritance">1.20.4. Dziedziczenie</h3>
+       <p>
+               Mamy sobie naszych użytkowników. Jednak potrzebujemy specjalnego 
+    użytkownika, który będzie tym wszystkim zarządzał - Administratora. Problem
+    napotykamy wtedy kiedy chcemy zdefiniować jakieś ekstra metody dla admina, 
+    ale nie chcemy umieszczać ich w tej samej klasie do definiowania 
+    użytkowników, musimy również pamiętać, że admin to też użytkownik, i 
+    wypadało by mieć w bazie jego dane. Przekopiowanie kodu jest nieefektywne,
+    ale z pomocą przechodzi na <strong>dziedziczenie</strong>, czyli tworzenie 
+    <strong>klas potomnych</strong> na podstawie istniejącej już klasy.
+       </p>
+       <p>
+               Przy tworzeniu klas potomnych warto pamiętać o jednej rzeczy. Klasa potomna
+    jest to oddzielna klasa zawierająca połączenie z <strong>klasą nadrzędną</strong>. 
+    Klasy potomne mogą inicjować dla swoich obiektów właściwość klasy 
+    nadrzędnej oraz obiekty klas potomnych mogą korzystać z metod klasy 
+    nadrzędnej. Definicja takiej klasy wygląda następująco.
+       </p>
+<pre class="code-block">
+class User():
+    def __init__(self, firstname, lastname, age, sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+        self.rank = 'Junior user'
+        self.quota = 100_000_000
+
+    def promote_user(self, new_rank):
+        self.rank = new_rank
+
+    def happy_birthday(self):
+        print(f"Happy Birthday {self.firstname.title()}")
+        self.age += 1
+
+    def check_quota_type(self):
+        if self.quota &lt; 0:
+            print('Unlimited')
+        else:
+            print('100MB')
+
+class Admin(User):
+    def __init__(self, firstname, lastname, age, sex):
+        super().__init__(firstname, lastname, age, sex)
+        self.quota = -1
+        self.rank = 'Admin'
+
+    def ban_user(self, username):
+        print(f'Użytkownik {username} został zbanowany')
+</pre>
+               <p>
+                       Cechami po których można poznać że dana klasa jest klasą potomną, jest to,
+      że w parametrach klasy znajduje się nazwa klasy nadrzędnej. W metodzie 
+      <code class="code-inline">__init__</code> występuje metoda 
+      <code class="code-inline">super()</code>, której celem jest realizowanie 
+      połączenia pomiędzy klasą potomną a klasą nadrzędną. Użycie metody 
+      <em>super()</em> zależy od konstrukcji klasy nadrzędnej.  Utworzenie 
+      takiego obiektu różni się tylko nazwą klasy.
+               </p>
+<pre class="code-block">
+root = Admin('Jan' 'Kowalski', 25, 'M')
+root.happy_birthday()
+# Happy Birthday Jan
+root.check_quota_type()
+# Unlimited
+</pre>
+               <p>
+                       Atrybuty mogą przechowywać wiele rzeczy, od pojedynczych wartość po 
+      obiekty innych klas. Istnieje możliwość wewnątrz klasy 
+      przekazać atrybutowi jako wartość egzemplarz obiektu. Rozważmy to że 
+      musimy każdemu z naszych użytkowników zdefiniować uprawnienia, co im 
+      wolno, a co nie. Możemy spojrzeć na zestaw uprawnień jak na obiekt.
+               </p>
+<pre class="code-block">
+class User():
+    def __init__(self, firstname, lastname, age, sex):
+        self.firstname = firstname
+        self.lastname = lastname
+        self.age = age
+        self.sex = sex
+        self.rank = 'Junior user'
+        self.quota = 100_000_000
+        self.permissions = Permissions('User')
+
+    def promote_user(self, new_rank):
+        self.rank = new_rank
+
+    def happy_birthday(self):
+        print(f"Happy Birthday {self.firstname.title()}")
+        self.age += 1
+
+    def check_quota_type(self):
+        if self.quota &gt; 0:
+            print('Unlimited')
+        else:
+            print('100MB')
+
+class Permissions():
+    def __init__(self, user_type):
+        if user_type == 'Administrator':
+           self.permissions = ['może dodać post',
+               'może usunac post',
+               'może zbanować użytkownika']
+        else:
+           self.permissions = ['może dodać post', 'może usunać post']
+
+    def show_permissions(self):
+        for permission in self.permissions:
+            print(f"- {permission}")
+
+
+class Admin(User):
+    def __init__(self, firstname, lastname, age, sex):
+        super().__init__(firstname, lastname, age, sex)
+        self.quota = -1
+        self.rank = 'Admin'
+        self.permissions = Permissions('Administrator')
+
+    def ban_user(self, username):
+        print(f'Użytkownik {username} został zbanowany')
+
+root = Admin('Jacek', 'xf0r3m', 25, 'M')
+root.permissions.show_permissions()
+print('\n')
+user1 = User('Jan', 'Nowak', 47, 'M')
+user1.permissions.show_permissions()
+</pre>
+               <p>
+                       W powyższym przykładzie pokazano jak można użyć obiektu jako wartości 
+      atrybutu innego obiektu oraz jak uzyskać dostęp do metod takiego obiektu.
+      <code class="code-inline">root</code> jest obiektem w klasie
+      <code class="code-inline">Admin</code>, następnie po kropce podajemy 
+      nazwę atrybutu w tym przypadku jest 
+      <code class="code-inline">permissions</code>, aby po następnej kropce 
+      (z racji tego że wartość <code class="code-inline">permissions</code> to
+      też obiekt) podajemy nazwę metody 
+      <code class="code-inline">show_permissions()</code> i w ten sposób 
+      uzyskaliśmy dostęp do zdefiniowanych w innym obiekcie uprawnień 
+      przypisanych do obiektów użytkowników jako atrybuty.
+               </p>
+               <p>
+                       Klasy podobnie jak funkcje też można umieszczać w modułach, klasy 
+      umieszcza się w modułach w identyczny sposób jak funkcje. Identycznie też
+      się je importuje. Kilka akapitów wyżej jest opis jak to zrobić.
+               </p>
+    <h2 id="1.21.standardlibrary">1.21. Biblioteka standardowa</h2>
+               <p>
+                       Wiele modułów zwierających pomocne klasy oraz funkcje jest dostarczanych 
+      wraz z Python jako standardowe biblioteki. Wśród nich możemy znaleźć taki
+      moduł jak <code class="code-inline">random</code >, który zawiera funkcje
+      służące do generowania liczb pseudolosowych - 
+      <code class="code-inline">randint()</code> oraz np. 
+      <code class="code-inline">choice()</code>, która zwraca nam losowo 
+      wybraną wartość z listy lub krotki.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; from random import choice
+&gt;&gt;&gt; cars = ['Shelby Cobra', 'Chevy', 'Pontiac', 'Dodge', 'Mustang']
+&gt;&gt;&gt; today_car = choice(cars)
+&gt;&gt;&gt; today_car
+'Dodge'
+</pre>
+               <h2 id="1.22.filehandling">1.22. Obsługa plików</h2>
+               <p>
+                       Python tak wiele języków programowania umożliwia pracę z plikami. Dostęp
+      do pliku uzyskujemy w dość dziwny, ale bezpieczny (dla pliku) oraz 
+      efektywny sposób.
+               </p>
+<pre class="code-block">
+with open('filename.txt') as file_object
+</pre>
+               <p>
+                       Samemu otwarciu pliku służy funkcja <code class="code-inline">open()</code>, 
+      jednak jeśli skorzystalibyśmy z niej bez tej specyficznej obudowy, po 
+      zakończeniu wykonywania na nim jakiś operacji, musielibyśmy go zamknąć. 
+      Tylko pytanie, kiedy? Po ostatniej czynności na nim wykonanej? Nie 
+      wiadomo. Dlatego też w Pythonie pliki otwiera się za pomocą słowa 
+      kluczowego <code class="code-inline">with</code>, które to zamyka plik 
+      kiedy przestaje być potrzebny, czy to naszemu programowi, czy to 
+      Pythonowi podczas interpretacji kodu. Sekcja 
+      <code class="code-inline">as file_object</code>, będzie nam przedstawić 
+      odniesie do pliku jako obiekt <em>file_object</em>. Wielu przypadkach 
+      możemy spotkać się ze skróceniem <em>file_object</em> do 
+      <strong>f</strong>. Czynności wykonywane na pliku są umieszczane w bloku
+      kodu pod linią otwarcia pliku z użyciem słowa kluczowego <em>with</em>.
+               </p>
+               <p>
+                       W powyższym przykładzie, wewnątrz funkcji 
+      <code class="code-inline">open()</code> znajduje się argument o nazwie 
+      <code class="code-inline">filename.txt</code>, jest to ścieżka dostępowa
+      do pliku, która może być względna - odnosić się od danego miejsca, lub 
+      też bezwzględna - pełna ścieżka od najwyższego katalogu na systemie 
+      plików w systemach uniksopodobnych (<em>root</em>, katalog głowny -
+      <strong>/</strong>), w systemach MS Windows (Katalog dysku np. 
+      <em>c:\</em> itp.). Argument <code class="code-inline">filename.txt</code>
+      jest ścieżką względną, ponieważ odnosi się od CWD (obecnego katalogu 
+      roboczego - katalogu, w którym się znajdujemy, mamy otwarte IDE lub w 
+      katalogu lub w którym wykonuje się skrypt Pythona). W MS Windows 
+      stosujemy ten sam ukośnik (<em>/</em>) co w systemach uniksopodobnych, 
+      lub jeśli się już upieramy przy Windowsowych lewych ukośnikach 
+      (<strong>\</strong>), to musimy podać je podwójnie, ponieważ lewy ukośnik
+      w Python oznacza rozpoczęcie białego znaku.
+               </p>
+               <p>
+                       Dane z plików możemy odczytać na trzy różne sposoby.
+               </p>
+               <ul>
+                       <li><strong>Sposób 1</strong> - Ściągnięcie całej zawartości pliku jako ciągu tekstowego do zmiennej. </li>
+                       <li><strong>Sposób 2</strong> - Iteracja przez odniesienie do pliku.</li>
+                       <li><strong>Sposób 3</strong> - Przechowanie pliku jako lista wierszy występujących w pliku.</li>
+               </ul>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 1:</span>
+               </p>
+<pre class="code-block">
+with open('filename.txt') as f:
+    plik = f.read()
+</pre>
+               <p>
+                       Warto zwrócić uwagę na dodatkowy ostatni pusty wiersz. 
+      Metoda <code class="code-inline">read()</code> po napotkaniu końca pliku
+      zwraca pusty wiesz. Z racji tego, że pusty wiersz (znak przejścia do 
+      nowej linii '<em>\n</em>') to biały znak, cały plik ściągnęliśmy do 
+      zmiennej w postaci pojedynczego ciągu tekstowego, to oznacza to, że znak 
+      znajduje się po prawej stronie ciągu, więc za pomocą metody operującej na
+      ciągach tekstowych <em>rstrip()</em> możemy usunąć ten pusty wiersz.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 2:</span>
+               </p>
+<pre class="code-block">
+with open('filename.txt') as f:
+    for line in f:
+        print(f"{line.replace('Python', 'C')}")
+</pre>
+               <p>
+                       Metoda <strong>replace()</strong> zamienia wszystkie wystąpienia w ciągu
+      pierwszego argumentu na drugi argument.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Sposób 3:</span>
+               </p>
+<pre class="code-block">
+with open('filename.txt') as f:
+    plik = f.readlines()
+
+for linia in plik:
+    print(f"{linia.replace('Python', 'C')}")
+</pre>
+               <p>
+                       Metoda <code class="code-inline">readlines()</code> zwraca nam listę 
+      wierszy znajdujących się w pliku. 
+               </p>
+    <h3 id="1.22.1.openfunction">1.22.1. Funkcja open</h3>
+               <p>
+                       Funkcja <em>open()</em> pozwala na wybranie atrybutu dla otwieranego 
+      pliku.
+               </p>
+               <ul>
+                       <li><strong>'r'</strong> - Atrybut domyślny, otwiera tylko plik do odczytu.</li>
+                       <li><strong>'w'</strong> - Otwiera plik do zapisu. Jeśli nie może znaleźć
+      pliku, nie generuje błędu. Tworzy nowy plik pod podaną funkcji ścieżką. 
+      Jeśli plik o takiej nazwie już istnieje to zostaje nadpisany.</li>
+                       <li><strong>'a'</strong> - Otwiera plik do dopisywania. Dopisuje dane do
+      pliku. Nie nadpisuje danych w pliku. Podobnie jak atrybut <em>w</em> w
+      przypadku braku pliku na ścieżce, to zostanie o utworzony.</li>
+                       <li><strong>'r+'</strong> - Rozszerza otwarcie pliku do odczytu o 
+      możliwości dopisania danych. </li>
+               </ul>
+               <p>
+                       Zapis danych w pliku polega na otwarciu pliku do zapisu lub dopisywania 
+      używając wyżej wymienionych atrybutów jako drugiego argumenty funkcji 
+      <em>open()</em>. Plik nie musi istnieć na podanej ścieżce, zostanie 
+      utworzony w momencie zamknięcia odniesienia prze słowo kluczowe 
+      <em>with</em>
+               </p>
+<pre class="code-block">
+with open('filename.txt', 'w') as f:
+    f.write('xf0r3m')
+
+with open('filename.txt') as f:
+    plik = f.read()
+
+print(f"{plik}")
+# xf0r3m
+</pre>
+               <h2 id="1.23.try-except">1.23. Obsługa błędów</h2>
+               <p>
+                       Python posiada konstrukcję do obsługi błędów, to znaczy, że jeżeli w 
+      pewnym bloku umieścimy kod (technicznie, umieszcza się tam tylko jedną 
+      linię do której nie możemy być pewni, że uruchomienie jej nie spowoduje
+      błędu), to jeśli spowoduje on błąd określony w drugiej części 
+      konstrukcji, zostanie wykonany kod z bloku tej drugiej części. Tą 
+      konstrukcją jest <code class="code-inline">try-except</code>. Koronnym 
+      przykładem jest chyba dzielenie przez zero.
+               </p>
+<pre class="code-block">
+try:
+    print(8 / 0)
+except ZeroDivisionError:
+    print("Nie wolno dzielić przez 0")
+</pre>
+               <p>
+                       Jeśli kod w bloku <em>try</em> wykona się bez błędu, to zostanie 
+      wyświetlony wynik z dzielenia. Jednak nigdy nie się to nie stanie. 
+      Ponieważ wykonanie linii <code class="code-inline">print(8/0)</code> 
+      spowoduje wygenerowanie błędu <em>division by zero</em>. Błędy w 
+      programowaniu możemy nazwać wyjątkami od wykonania. Każdy błąd jest 
+      częścią <strong>obiektu wyjątku</strong> w tym przypadku obiektem wyjątku
+      dla błędu jest <code class="code-inline">ZeroDivisionError</code>. Skąd 
+      to wiadomo ? Otóż z komunikatów zwróconych przez sam Python jako 
+      <strong>stos wywołań.</strong> Ostatnia linia komunikatu o błędzie. 
+      Mówi nam: '<em>obiekt wyjątku:</em> <em>błąd</em>'.  Aby obsłużyć błąd, 
+      w linii <em>except</em> podajemy <em>obiekt wyjątku</em>, następnie w jej
+      bloku definiujemy kod, który ma się wykonać kiedy Python napotka błąd 
+      tego typu. Jeśli potrzebujemy obiektu wyjątku, to spróbujmy zmusić tę 
+      niepewną linię do wygenerowania błędu bez jego obsługi. Python poda nam 
+      nazwę obiektu wyjątku.
+               </p>
+               <p>
+                       W skład tej konstrukcji wchodzi jeszcze 
+      <code class="code-inline">else</code>, w tym bloku definiowany jest kod,
+      który jest wykonywany, kiedy kod w bloku <em>try</em> nie spowoduje 
+      błędu.
+               </p>
+<pre class="code-block">
+a = input("Podaj pierwszą liczbę: ")
+b = input("Podaj drugą liczbę: ")
+
+try:
+    result = int(a) + int(b)
+except ValueError:
+    print("Jedna z podanych wartości jest tekstem nie liczbą!")
+else:
+    print(f"{result}")
+</pre>
+               <p>
+                       Często będzie tak, że nie będziemy chcieli wykonywać żadnego kodu, ani 
+      informować nikogo o tym, że wystąpił wyjątek. Wtedy możemy skorzystać ze
+      słowa kluczowego <strong>pass</strong>, którego celem jest rezerwacja 
+      miejsca w bloku, na potrzeby późniejsze rozbudowy. Użycie instrukcji 
+      <em>pass</em> możemy tłumaczyć jako <em>do nothing</em>. Z racji tego, 
+      że instrukcja <em>pass</em> pozwala na ciche przyzwolenie na błędy. 
+      Musimy zdecydować kiedy użytkownik naszego programu powinien być 
+      informowany o błędzie. Na pewno wtedy gdy wyjątek powoduje jakaś 
+      informacja, która pochodzi od niego samego.
+               </p>
+    <h2 id="1.24.usingJSONformatwithpython">1.24. Wykorzystanie formatu JSON w Pythonie</h2>
+               <p>
+                       Z racji tego iż mamy omówione pliki oraz wyjątki, czyli możemy definiować
+      kod, który obsłuży sytuacje, gdy próbujemy odczytać plik który nie 
+      istnieje. Możemy zapisywać dane z naszych programów do pliku, a przy 
+      następnym uruchomieniu je wczytywać. Do tego celu wykorzystamy moduł 
+      <code class="code-inline">json</code>, który umożliwia użycie formatu 
+      JSON (JavaScript Object Notation) do przechowywania danych. A w 
+      szczególności dwie funkcje, <code class="code-inline">dump()</code> oraz
+      <code class="code-inline">load()</code>.
+               </p>
+               <p>
+                       Funkcja <em>dump()</em> jak argumenty pobiera, dane (jako pierwszy 
+      argument pozycyjny) np. zmienną, równie dobrze może być to lista. Drugim 
+      argumentem jest odniesie do pliku.
+               </p>
+<pre class="code-block">
+import json
+
+username = 'xf0r3m'
+
+with open('filename.json', 'w') as f:
+    json.dump(username,f)
+</pre>
+               <p>
+                       Dane zostaną za pisane w pliku. Nie koniecznie w formacie JSON jaki znamy
+      z JavaScript. Idealnie funkcja <em>dump()</em> na JSON przerabia słowniki,
+      którym chyba najbliżej do tego formatu. Odczyt danych z takiego pliku 
+      jest wykonywany jest za pomocą funkcji <em>load()</em>.
+               </p>
+<pre class="code-block">
+import json
+
+with open('filename.json') as f:
+    username = json.load(f)
+
+print(f"{username})
+# xf0r3m
+</pre>
+               <h2 id="1.25.unittests">1.25. Testy jednostkowe</h2>
+               <p>
+                       Python za pomocą modułów biblioteki standardowej umożliwia nam 
+      przeprowadzenie testów jednostkowych dla stworzonych przez nas funkcji 
+      oraz klas. Jeśli chcemy tworzyć naprawdę dobry kod, i to nie zależnie od 
+      języka powinniśmy go testować. Nie mówię o tworzeniu testów jednostkowych
+      dla <em>hello world</em>, ale kiedy nasz projekt dość pokaźnie urósł. 
+      Zawiera klasy lub/i funkcję, to powinien on zawierać testy tych 
+      konstrukcji. Na czym polega test jednostkowy? Najprościej rzecz biorąc na
+      sprawdzeniu czy wartość zwracana przez funkcje lub atrybut modyfikowany
+      przez metodę jest równy z predefiniowaną przez nas wartością, którą 
+      uznajemy za poprawną. Takie porównanie nazywamy asercją. Zakładamy, że 
+      wartość użyta do asercji jest równa zdefiniowanej wartości.
+                       Jeśli tak jest to test zostaje zaliczony, w przeciwnym wypadku wykonanie
+      zostaje przerwane (w przypadku asercji jako funkcji). Asercja w Pythonie
+      nie organiczna się tylko do sprawdzenia równości. Poniżej znajduje się 
+      tabelka z możliwymi funkcjami asercji zaimplementowanymi w module 
+      <strong>unittest</strong>. To ten moduł odpowiada za testy jednostkowe.
+               </p>
+               <figure>
+                       <table>
+                               <tbody>
+                                       <tr>
+                                               <td><strong>Metoda</strong></td>
+                                               <td><strong>Opis</strong></td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>assertEqual(a, b)</em></td>
+                                               <td>Sprawdza czy <em>a == b</em></td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>assertNotEqual(a, b)</em></td>
+                                               <td>Sprawdza czy <em>a != b</em></td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>assertTrue(x)</em></td>
+                                               <td>Sprawdza czy <em>x</em> przyjmuje wartość <em>True</em></td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>assertFalse(x)</em></td>
+                                               <td>Sprawdza czy <em>x</em> przyjmuje wartość False</td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>assertIn(element, lista)</em></td>
+                                               <td>Sprawdza czy <em>element</em> jest na <em>liście</em></td>
+                                       </tr>
+                                       <tr>
+                                               <td><em>asserNotIn(element, lista)</em></td>
+                                               <td>Sprawdza czy <em>element</em> nie znajduje się na <em>liście</em></td>
+                                       </tr>
+                               </tbody>
+                       </table>
+                       <figcaption>Metody asercji oferowane przez moduł unittest</figcaption>
+               </figure>
+    <h3 id="1.25.1.unittestsoffunction">1.25.1. Testy jednostkowe funkcji</h3>
+               <p>
+                       Na potrzeby przedstawienia testów zaczniemy od zdefiniowania sobie w 
+      module (<em>city_functions.py</em>) prostej funkcji '<em>city_countries</em>',
+      która pobiera od użytkownika nazwę miast oraz nazwę kraju, w którym to 
+      miasto leży następnie zwraca ciąg np. dla danych Warszawa Polska: 
+      Warszawa, Polska.
+               </p>
+<pre class="code-block">
+def city_countries(city, country):
+  cc = f"{city.title()}, {country.title()}"
+  return cc
+</pre>
+               <p>
+                       Aby wywołać taką funkcje z racji tego, że jest plik modułu w nowym pliku
+      musimy zaimportować moduł i wywołać funkcję:
+               </p>
+<pre class="code-block">
+from city_functions import city_countries
+city_countries('Warszawa', 'Polska')
+# Warszawa, Polska
+</pre>
+               <p>
+                       Powiedzmy z racji tego, że jest to funkcja dużego projektu, musimy 
+      stworzyć dla niej test jednostkowy. Testy definiuje się w klasie potomnej
+      klasy TestCase modułu unittest. Jedna metoda w wewnątrz klasy = jeden 
+      test. Taka klasa staje się zbiorem testów. Kiedy dla każdej funkcji w 
+      naszym projekcie zdefiniujemy chociaż jeden test, to możemy mówić wówczas
+      o <strong>całkowitym pokryciu zbioru testów</strong>. Zatem dla testów 
+      jednostkowych utworzymy nowy plik, nazwiemy go <em>test_cities.py</em>
+               </p>
+<pre class="code-block">
+import unittest
+from city_functions import city_countries
+
+class TestCitiesFunctions(unittest.TestCase):
+
+    def test_city_countries(self):
+        cc = city_countries('Warszawa', 'Polska')
+        self.assertEqual(cc, 'Warszawa, Polska')
+
+unittest.main()
+</pre>
+               <p>
+                       importujemy moduł <code class="code-inline">unittest</code>, następnie 
+      importujemy naszą funkcję. Tworzymy klasę potomną klasy 
+      <code class="code-inline">unittest.TestCase</code>, w tym przypadku o 
+      nazwie <code class="code-inline">TestCitiesFunctions</code>. Wewnątrz 
+      niej jako metodę definiujemy test. Funkcja 
+      <code class="code-inline">main()</code> modułu <em>unittest</em> 
+      uruchomi automatycznie każdą metodę w zbiorze, których nazwy zaczynają 
+      się od ciągu <strong>test_</strong>, zatem nie potrzeba jej wywoływać. 
+      Wewnątrz metody wywołujemy naszą funkcję zachowując jej wartość zwracaną
+      w zmiennej <code class="code-inline">cc</code> następnie w jednej z metod
+      asercji w tym przypadku <code class="code-inline">assertEqual</code>
+      podstawiamy otrzymaną wartość następnie wartość, którą naszym zdaniem 
+      powinniśmy otrzymać od funkcji dla podanych w wywołaniu argumentów. Na 
+      końcu uruchamiamy zbiór testów. Wynik testu znajduje się poniżej.
+               </p>
+<pre class="code-block">
+.
+----------------------------------------------------------------------
+Ran 1 test in 0.000s
+
+OK
+</pre>
+
+               <p>
+                       W prawdzie nie wiele informacji, choć nas powinna zaciekawić pierwsza 
+      linijka, zwracany jest w niej rezultat testu, jeśli widzimy kropkę 
+      (<code class="code-inline">.</code>), oznacza to że test zakończył się 
+      sukcesem. Innymi wartościami zwrotnymi jest wielka litera 
+      <strong>F</strong>, oznaczająca nie powodzenie asercji, otrzymaliśmy inny
+      wynik niż zakładaliśmy, oraz wielka litera <strong>E</strong>, 
+      oznaczająca błąd gdzieś w kodzie. Np. jeśli rozbudowujemy funkcje o 
+      kolejne parametry, ale już zapomnimy w teście tych parametrach.
+               </p>
+               <p>
+                       Rozbudujemy naszą funkcję o kolejny parametr pozwalający przedstawić populacje.
+               </p>
+<pre class="code-block">
+def city_country(city, country, population):
+    cc = f"{city.title()}, {country.title()} - populacja {population}"
+    return cc
+</pre>
+               <p>
+                       Próbując wykonać test dla tej funkcji dostaniemy o taką odpowiedź:
+               </p>
+<pre class="code-block">
+E
+======================================================================
+ERROR: test_city_country (__main__.TestCitiesFunctions)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/xf0r3m/python/test_cities.py", line 8, in test_city_country
+    cc = city_country('Warszawa', 'Polska')
+TypeError: city_country() missing 1 required positional argument: 'population'
+
+----------------------------------------------------------------------
+Ran 1 test in 0.001s
+
+FAILED (errors=1)
+</pre>
+               <p>
+                       Błąd polega na tym, że zapomnieliśmy jednym argumencie, jeśli zmienimy 
+      ten argument na opcjonalny, wtedy test zostanie pomyślnie wykonany. 
+      Poniżej zamieszczam również dane zwracane, kiedy wartość rzeczywista 
+      różni się od przez nas założonej, pojawia się wtedy błąd asercji.
+               </p>
+<pre class="code-block">
+F
+======================================================================
+FAIL: test_city_country (__main__.TestCitiesFunctions)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/xf0r3m/python/test_cities.py", line 9, in test_city_country
+    self.assertEqual(cc, 'Warszawa, Polska')
+AssertionError: 'Warszawa, Polska - populacja ' != 'Warszawa, Polska'
+- Warszawa, Polska - populacja
++ Warszawa, Polska
+
+
+----------------------------------------------------------------------
+Ran 1 test in 0.001s
+
+FAILED (failures=1)
+</pre>
+               <p>
+                       Oczywiście kiedy zdefiniujemy kolejne testy, to będą pojawiać się 
+      w pierwszej linijce kropki lub litery E czy F,  wszystko w zależności od 
+      wyniku testu.
+               </p>
+    <h3 id="1.25.2.unittestsofmethods">1.25.2. Testy jednostkowe metod</h3>
+               <p>
+                       Testy jednostkowe możemy tworzyć nie tylko dla funkcji ale i dla klas 
+      (bardziej metod). Przygotowałem poniżej klasę modelującą pracownika w 
+      swoich atrybutach zawiera imię, nazwisko oraz roczne zarobki. W klasie 
+      znajduje się również metoda odpowiedzialna za przyznawanie podwyżki, 
+      domyślną wartością podwyżki jest 5000. Naszym zadaniem jest stworzenie 
+      dwóch testów sprawdzających ową metodę. Jak w przykładzie z funkcją, 
+      klasę umieszczamy w odrębnym pliku modułu.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Plik: pracownik.py</span>
+               </p>
+<pre class="code-block">
+class Employee():
+
+    def __init__(self, imie, nazwisko, y_salary):
+        self.imie = imie
+        self.nazwisko = nazwisko
+        self.y_salary = y_salary
+
+    def give_raise(self, amount_raise=5000):
+        self.y_salary += amount_raise
+</pre>
+               <p>
+                       Poniżej znajduje się plik ze zbiorem testów. Dla klas tworzymy go w 
+      identyczny sposób jak dla funkcji, z jedną różnicą. Dla poprawności testu,
+      każdy test powinien otrzymać oddzielny egzemplarz klasy, aby nie 
+      powtarzać kodu tworzenia egzemplarza, z pomocą przychodzi nam metoda 
+      <em>unittest</em> o nazwie <code class="code-inline">setUp</code>. 
+      Kiedy <span style="text-decoration: underline;">definiujemy</span> taką 
+      metodę w wewnątrz zbioru testów, powinna zawierać kod przeznaczony do 
+      utworzenia egzemplarza danej klasy. Ta metoda będzie wywoływana przez 
+      Python przed każdym wywołaniem testu.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Plik: test_employee.py</span>
+               </p>
+<pre class="code-block">
+import unittest
+from pracownik import Employee
+
+class EmployeeTest(unittest.TestCase):
+
+    def setUp(self):
+
+        imie = 'Jan'
+        nazwisko = 'Nowak'
+        y_salary = 140_000
+
+        self.new_employee = Employee(imie, nazwisko, y_salary)
+
+    def test_give_default_raise(self):
+
+        self.new_employee.give_raise()
+        self.assertEqual(self.new_employee.y_salary, 145_000)
+
+    def test_give_custom_raise(self):
+        self.new_employee.give_raise(25_000)
+        self.assertEqual(self.new_employee.y_salary, 165_000)
+
+unittest.main()
+</pre>
+               <p>
+                       Naszymi testami było sprawdzenie metody odpowiedzialnej za przyznawanie 
+      podwyżek. Pierwszy test to podwyżka o wartość domyślnej a drugi to 
+      podwyżka zdefiniowana przez użytkownika. Danymi zwracanymi przez Python 
+      dla uruchomienia tych testów są:
+               </p>
+<pre class="code-block">
+..
+----------------------------------------------------------------------
+Ran 2 tests in 0.001s
+
+OK
+</pre>
+               <h2 id="1.26.sourcecodestyle">1.26. Koncepcje stylu kodu źródłowego</h2>
+               <p>
+                       Poniżej przedstawiam koncepcje stylu nadawanego zapisom kodu źródłowego,
+      ponieważ <em>Now is better than never</em> oraz 
+      <em>Beautiful is better than ugly</em>.
+               </p>
+               <p>
+                       Kilka reguł, których należy stosować pod czas używania zmiennych w 
+      Pythonie.
+               </p>
+               <ul>
+                       <li>W nazwach zmiennych mogą znajdować się jedynie, cyfry i znaki 
+          podkreślenia. Nazwa może rozpoczynać się od litery lub znaku 
+          podkreślenia ale nie od cyfry.</li>
+                       <li>Niedozwolone jest stosowanie spacji w nazwach zmiennych, choć znak 
+          podkreślenia można stosować w charakterze separatora.</li>
+                       <li>Należy unikać używania w nazwach zmiennych słów kluczowych Pythona 
+          oraz nazw funkcji.</li>
+                       <li>Nazwa zmiennej powinna być krótka, choć jednocześnie czytelna.</li>
+                       <li>Ostrożnie należy używać małej litery <em>l</em> oraz wielkiej litery
+          <em>O</em>. Mogą zostać mylnie odczytane jako 1 lub 0.</li>
+               </ul>
+               <p>
+                       Zmienne w Pythonie zapisujemy z małych liter.
+               </p>
+               <p>
+                       Odnośnie komentarzy, to warto sobie opisywać jakieś bardziej złożone 
+      fragmenty naszego programu, żeby później, kiedy powrócimy do kodu po 
+      jakimś czasie, nie tracić czasu na próbę zrozumienia co autor miał na 
+      myśli.
+               </p>
+               <p>
+                       Generalnie konwencje stylu, będą stosowane nie po to aby kod był łatwy do
+      zapisu, ale do odczytu właśnie. Jest dokument w sieci nazywa się PEP 8 
+      (<em>Python Enhancement Proposal</em>), który opisuje sposoby nakładania
+      stylu na tworzony kod. Pierwszą rzeczą którą jest podczas zapisu kodu 
+      łatwego do odczytu, są <strong>wcięcia</strong>. W Pythonie sprawa jest 
+      nieco paradoksalna, ponieważ nie możemy sobie szastać wcięciami na prawo
+      i lewo, ponieważ wcięcia często oznaczają blok kodu, ale jednocześnie 
+      przez to Python sam nakazuje nam stosowanie wcięć przy definiowaniu bloku
+      kodu. Specyfikacja PEP 8 zaleca użycia czterech spacji jako jednego 
+      poziomu wcięcia. Najnowsze wersje edytorów ustawiają jeden znak tabulacji
+      na wielkość czterech spacji. Kolejną rzeczą jest 
+      <strong>długość wiersza</strong>, która nie powinna przekraczać 80 znaków
+      takie zalecenie później ułatwi nam pracę kiedy na jednym ekranie będziemy
+      musieli mieć podzielone okno edytora na kilka plików naraz.
+                       W oknie edytora możemy zobaczyć taką pionową kreskę, właśnie ona stoi na 
+      miejscu 80-tego znaku. Taka linia powinna być już włączona, jeśli nie 
+      jest to zawsze można ją włączyć. Do organizacji kodu w schludny plik 
+      tekstowy mogą pomóc nam <strong>puste wiersze</strong>. Nie należy ich 
+      jednak nadużywać. Metodę jaką ja stosuje jest rozdzielanie kodu ze 
+      względu na jego kontekst. Np. mam sobie wywołanie funkcji, która zwraca 
+      mi wartość do zmiennej - jest jedna linia. Teraz chcę to wypisać - to 
+      jest druga linia operująca na tych samych danych, czyli umieszczam ją 
+      jedna pod drugą. Kiedy muszę wywołać podobnie inną funkcję muszę robię 
+      linię odstępu przed kolejnymi instrukcjami.
+               </p>
+               <p>
+                       PEP 8 opisuje również styl dla testów warunkowych. W tego zalecenia 
+      powinniśmy rozdzielać operandy od operatora spacją, zarówno w test 
+      prostych jak i złożonych.
+               </p>
+               <p>
+                       Podczas nadawania stylu funkcjom powinniśmy pamiętać o kilku kwestiach. 
+      Nazwa funkcji powinna sugerować jej przeznaczenie i składać się z małych 
+      liter i znaków podkreślenia. W kodzie każdej funkcji powinien znajdować 
+      się komentarz zaraz na początku bloku kodu funkcji, dla komentarza 
+      należy użyć formatu <strong>docstring</strong>. W przypadku definiowania 
+      parametrów domyślnych lub też opcjonalnych po obu stronach znaku równości
+      nie należy umieszczać żadnych spacji. Jeżeli parametry w definicji nam 
+      się nie mieszczą 80 znakach, to możemy bez trudu złamać tą linię za 
+      przecinkiem, dać dwa znaki tabulatora aby nie zostało to potraktowane 
+      jako blok funkcji i kontynuować zapisywanie parametrów na końcu 
+      zamykając nawias, podając znak dwukropka. Jeśli przechowujemy naszą 
+      funkcję w module i ta funkcja nie jest jedyna w tym module, to możemy 
+      poszczególne funkcje w module rozdzielić dwoma pustymi wierszami.
+               </p>
+               <p>
+                       Nazwa klasy powinna stosować styl CamelCase: każde słowo nazwy pisane 
+      wielką literą, brak znaków podkreślenia. Z kolei nazwy egzemplarzy klas 
+      powinny być zapisane małymi literami, a wykorzystanie w tych nazwach 
+      znaków podkreślenia między słowami jest dopuszczalne. Na początku każdej
+      klasy należy umieścić komentarz typu <em>docstring</em> wyjaśniający 
+      przeznaczenie klas znajdujących się w danym module. W kodzie klasy 
+      umieszczamy pusty wiersz pomiędzy metodami. Klasy w module rozdzielamy 
+      dwoma pustymi wierszami.
+               </p>
+               <p>
+                       Importując moduły z biblioteki standardowej oraz swoje, w pierwszej 
+      kolejności należy podać polecenia import modułów biblioteki a dopiero 
+      później swoje moduły.
+               </p>
+               <p>
+                       Ostatnim pojęciem ze stylów będzie <strong>refaktoryzacja</strong>. Jest
+      to podział dużego kodu na funkcje wykonujące zazwyczaj konkretne zadanie.
+               </p>
+               <p>
+                       Tutaj kończy się część pierwsza, czyli poznawanie Pythona, jego składni,
+      poleceń i konstrukcji. Teraz przejdziemy do konkretnego zagadnienia, 
+      gdzie raczej będziemy analizować studium przypadku. Przypadku tworzenia 
+      aplikacji internetowej, podobnej do tej jaką tworzy się za pomocą takich
+      języków jak np. PHP.
+               </p>
+    <p>
+                 <strong>Koniec części pierwszej.</strong>
+    </p>
+               <h1 id="2.part2">Część 2: Aplikacje internetowe</h1>
+               <p>
+                       <strong>Django</strong> to zestaw narzędzi 
+      (czyt. <em>framework</em>) pozwalający na tworzenie aplikacji 
+      internetowych/interaktywnych witryn za pomocą Pythona.
+               </p>
+               <p>
+                       Tworząc witrynę czy też aplikacje w Django, tworzymy projekt. Każdy 
+      projekt składa się z wielu mniejszych części zwanych 
+      <strong>aplikacjami</strong> stworzonych za pomocą Pythona według zasad 
+      Django. Każdy porządny projekt powinien mieć jasno określone założenia, 
+      na których skupiają się programiści podczas pracy, taki określony zbiór 
+      cech i funkcjonalności nazywamy specyfikacją.
+               </p>
+               <h2 id="2.1.virtualenv">Środowisko wirtualne</h2>
+               <p>
+                       Rozpoczynając pracę z Django musimy skonfigurować 
+      <strong>środowisko wirtualne</strong>, w którym będziemy mogli dowolnie 
+      instalować rzeczy, nie powodując bałaganu w modułach Pythona na naszym 
+      systemie. Każde środowisko można bez problemu usunąć wydając odpowiednie 
+      dla systemu polecenie powłoki służące do usuwania plików. W tej części 
+      będę przedstawiał polecenia z systemu Linux, dystrybucji opartych o 
+      Debian, takich jak np. Ubuntu. Przepraszam za pominięcie innych systemów.
+      Konfiguracje środowiska wirtualnego zaczynamy od zainstalowania modułu w
+      systemie.
+               </p>
+<pre class="code-block">
+$ sudo apt install python3-venv
+</pre>
+               <p>
+                       Po zainstalowaniu pakietu, dla większego porządku tworzymy sobie katalog,
+      w którym będziemy przechowywać nasz projekt. Wewnątrz katalogu wydajemy 
+      poniższe polecenie.
+               </p>
+<pre class="code-block">
+$ python3 -m venv project_env
+</pre>
+               <p>
+                       Za <code class="code-inline">project_env</code> możemy podstawić swoją 
+      nazwę. Po wydaniu tego polecenia Python utworzy katalog 
+      <em>project_env</em>, w którym będą przechowywane wszystkie pliki 
+      utworzonego środowiska wirtualnego. Na tym konfiguracja się kończy. 
+      Kiedy chcemy uruchomić nasze środowisko wydajemy poniższe polecenie.
+               </p>
+<pre class="code-block">
+$ source project_env/bin/activate
+</pre>
+               <p>
+                       Polecenie powinno zakończyć działanie zaraz po uruchomieniu nie zwracając
+      żadnych danych. Jedyną rzeczą, która się zmieni jest <em>prompt</em> 
+      (znak zachęty), przednim będzie znajdował się nawias, zawierający nazwę 
+      naszego katalogu ze środowiskiem wirtualnym.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:/python/django$
+</pre>
+               <p>
+                       Środowisko możemy wyłączyć wydając polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:/python/django$ deactivate
+</pre>
+               <p>
+                       lub po prostu zamykając powłokę, w której je aktywowaliśmy. Po 
+      uruchomieniu środowiska będziemy używać polecenia 
+      <code class="code-inline">python</code>, to polecenie będzie odnosić się
+      do wersji Pythona jakiej użyliśmy to stworzenia środowiska, w tym 
+      przypadku <strong>nie będziemy używać polecenia <em>python3</em></strong>.
+      Teraz możemy przejść do instalacji Django. Wydajemy polecenie w 
+      aktywowanym środowisku wirtualnym:
+               </p>
+               <h2 id="2.2.djangobasics">Podstawy pracy z frameworkiem Django</h2>
+    <h3 id="2.2.1.installationofdjango">2.2.1. Instalacja django</h3>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ pip install django
+</pre>
+               <p>
+                       Kiedy polecenie skończy działanie, przechodzimy do utworzenia naszego 
+      projektu.
+    </p>
+    <h3 id="2.2.2.creatingnewproject">2.2.2. Stworzenie nowego projektu w Django</h3>
+    <p>
+      Powiedzmy że stworzymy stronę pizzerii, gdzie będzie można 
+      zamówić pizzę i przejrzeć menu dla zamówień telefonicznych. Aby utworzyć
+      projekt wydajemy poniższe polecenie.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ django-admin startproject pizzeria .
+</pre>
+               <p>
+                       W tym poleceniu najważniejsza jest <strong>kropka na końcu</strong> 
+      powodująca, że projekt zostanie utworzony w katalogu, w którym się 
+      znajdujemy. Brak kropki spowoduje utworzenie projektu w jeszcze jednym 
+      wewnętrznym katalogu. Spoglądając na pliki umieszczone w naszym folderze
+      powinniśmy dostrzec plik <em>manage.py</em>, folder środowiska 
+      wirtualnego zakończony sufiksem <em>_env</em> oraz folder o nazwie 
+      <em>pizzeria</em> zawierający pliki naszego projektu.
+               </p>
+    <h3 id="2.2.3.cratetindbforproject">2.2.3. Tworzenie bazy danych dla projektu</h3>
+               <p>
+                       Jak wszyscy wiemy, aplikacje internetowe często przetwarzają jakieś dane.
+      Te dane należy gdzieś składować, najpopularniejszą metodą magazynowania 
+      danych przez aplikacje sieci WWW są <strong>bazy danych</strong>. Django
+      również korzysta z baz danych, a my wykorzystamy najprostszą z nich, w 
+      postaci jednego pliku - bazy <strong> SQLite3</strong>. W przypadku 
+      innych systemów bazodanowych niezbędna będzie instalacja dodatkowych 
+      modułów Pythona. Na tym etapie po prostu stworzymy bazę danych dla 
+      naszego projektu aby wszystko funkcjonowało poprawnie. Wydajemy 
+      polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py migrate
+</pre>
+               <p>
+                       W Django, czynności na bazie wykonujemy za pomocą opcji 
+      <code class="code-inline">migrate</code> skryptu <em>manage.py</em>. 
+      Teraz kiedy nasza baza nie istnieje, polecenie <em>migrate</em> spowoduje
+      jej utworzenie. 
+    </p>
+    <h3 id="2.2.4.startaprojectserver">2.2.4. Uruchomienie serwera projektu</h3>
+    <p>
+      Teraz możemy uruchomić nasz 
+      <strong>serwer aplikacji</strong>. Wydajemy polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py runserver
+</pre>
+               <p>
+                       Po uruchomieniu tego polecenia, z danych przeznie zwracanych powinniśmy
+      dowiedzieć się, że nasz serwer nasłuchuje na pętli zwrotnej 
+      (<em>localhost</em>/127.0.0.1) na porcie 8000. Możemy przejść pod ten 
+      adres za pomocą przeglądarki, a naszym oczom ukaże się strona domyślna 
+      projektu, predefiniowana przez Django.
+               </p>
+    <h3 id="2.2.5.creatinganapplication">2.2.5. Tworzenie aplikacji Django</h3>
+               <p>
+                       Jak wiemy z początkowych akapitów, na projekt w Django składają się na
+      mniejsze części nazywane aplikacjami, często odpowiadają one za konkretne
+      rzeczy. Teraz stworzymy aplikacje odpowiedzialną za nasze pizze i ich 
+      dodatki.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py startapp pizzas
+</pre>
+               <p>
+                       Po wykonaniu tego polecenia na chwilę się zatrzymamy. Na początku 
+      wyświetlimy sobie zawartość utworzonego katalogu aplikacji.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ ls pizzas
+admin.py  __init__.py  models.py    templates  urls.py
+apps.py   migrations   __pycache__  tests.py   views.py
+</pre>
+    <h3 id="2.2.6.models">2.2.6. Modele</h3>
+               <p>
+                       Katalogiem <em>templates</em> zajmiemy się później, natomiast katalog 
+      <em>__pycache__</em> nie jest w ogóle istotny, jest on tworzony przez 
+      Python podczas uruchamiania skryptu. Każda aplikacja w Django 
+      reprezentuje wzorzec <strong>model-view-template</strong>, na 
+      <strong>modele</strong> składają się reprezentacje danych w postaci klas.
+      Weźmy sobie zatem taką pizzę, co może ją opisać? Na przykład nazwa. 
+      Każda pizza ma swoją nazwę, mamy zatem jakąś właściwość, która składa się
+      na ten model, modele posiadają także metodę, która pozwala na 
+      reprezentowanie danego modelu. Kiedy wyciągniemy egzemplarz modelu z 
+      bazy, to odwołując się do niego uzyskamy, jakąś wartość. Może być to po 
+      prostu nazwa. Z technicznego punktu widzenia modele to klasy potomne, 
+      klasy <code class="code-inline">Model</code> z modułu 
+      <em>django.db.models</em>. Wewnątrz tej klasy znajdują się atrybuty, 
+      oraz metoda <code class="code-inline">__str__</code>.
+                       Modele przypominają tabele relacyjnych baz danych, nawet są do nich 
+      konwertowane podczas <strong>migracji</strong>, każda właściwość takiego 
+      modelu staje się kolumną w bazie. Modele definiujemy w pliku 
+      <em>models.py</em> w folderze aplikacji, a tak przedstawia się model naszej pizzy.
+               </p>
+<pre class="code-block">
+class Pizza(models.Model):
+    name = models.CharField(max_length=30)
+
+    def __str__(self):
+        return self.name
+</pre>
+               <p>
+                       W powyższym przykładzie mamy jeden atrybut znakowy 
+      (<code class="code-inline">CharField</code>) o długość 30 znaków. 
+      Odpowiada to SQL-owemu <em>VARCHAR(30)</em>. Mamy również w naszej klasie
+      metodę odpowiadającą za reprezentacje danego modelu. W tym wypadku 
+      zwracamy po prostu nazwę. Modele mogą być ze sobą połączone. Rozważmy 
+      przykład, posiadamy model pizzy i mamy model dodatku na pizzę, teraz 
+      chcieli byśmy dowiedzieć się jakie są dodatki dla konkretnej pizzy, aby 
+      metaforycznie położyć dodatki na pizzy skorzystamy z tak zwanego klucz 
+      obcego lub klucza zewnętrznego - odniesienia się do innego modelu.
+               </p>
+<pre class="code-block">
+class Toping(models.Model):
+    pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)
+    name = models.CharField(max_length=200)
+
+    def __str__(self):
+        return self.name
+</pre>
+               <p>
+                       Za nasze połączenie opowiada metoda 
+      <code class="code-inline">ForeignKey</code>, która jako argumenty pobiera
+      nazwę modelu, do którego będzie odnosić się właściwość 
+      <code class="code-inline">pizza</code>, drugi argument jest zachowaniem,
+      w przypadku usunięcia egzemplarza pizzy, do którego odnoszą się 
+      egzemplarze dodatków, kiedy jest ustawiony na 
+      <code class="code-inline">models.CASCADE</code>, to gdy usuniemy pizzę to
+      również powiązane z nią dodatki zostaną usunięte.
+               </p>
+    <h3 id="2.2.7.instalationappinproject">2.2.7. Instalacja aplikacji w projekcie</h3>
+               <p>
+                       Kiedy mamy już zdefiniowane modele, to możemy je teraz wstawić do naszej 
+      bazy. Przed przeprowadzeniem migracji, trzeba ją najpierw przygotować. 
+      Jednak przed przygotowaniem migracji, należy na początku zainstalować 
+      naszą aplikacje, aby Python wiedział, że 
+      <code class="code-inline">pizzas</code> należy do projektu 
+      <em>pizzeria</em> i mógł w bazie danych projektu utworzyć tabele. 
+      Instalacja przebiega w następujący sposób, otóż w katalogu projektu 
+      odszukujemy plik <em>settings.py</em>. W nim szukamy zmiennej 
+      <code class="code-inline">INSTALLED_APPS</code>, a następnie umieszczamy 
+      nazwę naszej aplikacje w pojedynczych apostrofach na samym początku listy. 
+      Musimy pamiętać o przecinku po nazwie aplikacji.
+               </p>
+<pre class="code-block">
+INSTALLED_APPS = [
+    'pizzas',
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+]
+</pre>
+               <p>
+                       Dlaczego umieściliśmy naszą aplikacje, na samym początku listy? Lista 
+      zawiera aplikacje domyślnie instalowane przez Django w naszym projekcie 
+      aby zapewnić mu podstawową funkcjonalność, oraz zaoszczędzić czas na 
+      tworzenie aplikacji. Aplikacje te realizują identyczne zadania dla 
+      każdego projektu. Może jednak zdarzyć się tak że będzie trzeba nadpisać 
+      funkcje domyślnej aplikacji, dlatego też swoje aplikacje dopisujemy 
+      <strong>powyżej</strong> aplikacji domyślnych.
+    </p>
+    <h3 id="2.2.8.approvingmodels">2.2.8. Zatwierdzanie modeli w bazie danych.</h3>
+    <p>
+      Aby przygotować migrację wydajemy poniższe polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py makemigrations pizzas
+</pre>
+               <p>
+                       Jeśli modele są poprawne pod względem składni, to przez skrypt zostaniemy
+      poinformowani mniej więcej takim komunikatem.
+               </p>
+<pre class="code-block">
+Migrations for 'pizzas':
+  pizzas/migrations/0001_initial.py
+    - Create model Pizza
+    - Create model Topping
+</pre>
+               <p>
+                       Ten komunikat oznacza również wygenerowanie <strong>plik migracji</strong>.
+      Wydajemy poniższe polecenie aby zatwierdzić nasze zmiany w bazie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py migrate
+</pre>
+               <p>
+                       Wywołanie tego polecenia spowoduje utworzenie modeli. Warto zaznaczyć w 
+      tym momencie, że każda poważniejsza zmiana w modelu musi zostać 
+      zatwierdzona w bazie. Każdą zmianę na modelach możemy próbować migrować,
+      najwyżej Python nie wygeneruje pliku migracji, ponieważ uzna, że zmiana, 
+      którą wprowadziliśmy nie była istotna dla modelu w bazie. Najlepiej kiedy
+      jednak tworzymy model postarać się przemyśleć każdą właściwość, ponieważ
+      zmiany wprowadzane w trakcie jego działania są nieco bardziej 
+      skomplikowane. Zostały one (dodawnie kolumny) opisane pod koniec strony 
+      podczas zabezpieczania naszego projektu. Przypuszczam że zmiany w bloku 
+      metody <em>__str__</em> są takim zmianami, których nie trzeba 
+      zatwierdzać w bazie.
+               </p>
+    <h3 id="2.2.9.managingmodelsviaadminsite">2.2.9. Zarządzanie modelami za pomocą wirtyny administracyjnej Django</h3>
+               <p>
+                       Po dokonaniu migracji, możemy wprowadzić dane początkowe do naszych
+      modeli, do wprowadzania danych początkowych, możemy posłużyć się 
+      witryną administracyjną dostarczaną nam przez Django. Jednak przed samym
+      rozpoczęciem musimy wykonać dwie czynności. Pierwszą rzeczą jest 
+      utworzenie konta superużytkownika - użytkownika witryny administracyjnej.
+      Wydajemy poniższe polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py createsuperuser
+</pre>
+               <p>
+                       Skrypt zapyta nas o kilka rzeczy. Mianowicie o nazwę użytkownika, która 
+      może zostać domyślna - nazwa użytkownika systemowego, który wydał 
+      polecenie utworzenia superużytkownika. Adres skrzynki mailowej, który 
+      jest opcjonalny. Ostatnią rzeczą jaką będziemy musieli podać to hasło. 
+      Dwukrotnie aby je potwierdzić. Po utworzeniu superużytkownika, możemy 
+      przejść do drugiej czynności.
+               </p>
+               <p>
+                       Aby móc zarządzać danym z modeli za pomocą witryny administracyjnej, 
+      należy je najpierw <strong>zarejestrować</strong>.  Modele rejestrujemy w
+      pliku <em>admin.py</em>. Na początku importujemy nasz moduł z modelami za
+      pomocą linii:
+               </p>
+<pre class="code-block">
+from .models import Pizza,Toping
+</pre>
+               <p>
+                       <strong>Kropka przed <code class="code-inline">models</code></strong>
+      oznacza, że Python ma wziąć moduł z tego samego katalogu, w którym 
+      znajduje się interpretowany plik <em>admin.py</em>. Następnie przy pomocy
+      metody <code class="code-inline">register()</code> obiektu 
+      <code class="code-inline">admin.site</code> rejestrujemy każdy z
+      zaimportowanych modeli.
+               </p>
+<pre class="code-block">
+admin.site.register(Pizza)
+admin.site.register(Toping)
+</pre>
+               <p>
+                       Po zarejestrowaniu modeli możemy uruchomić nasz serwer deweloperski.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py runserver
+</pre>
+               <p>
+                       Otwieramy w przeglądarce następujący adres 
+      <em>http://127.0.0.1:8000/admin</em> . Następnie logujemy się na konto 
+      superużytkownika. Po zalogowaniu zobaczymy dwie sekcje w jednej są nasze 
+      modele, a w drugie modele użytkowników i grup. Na co chciałbym zwrócić 
+      uwagę, to fakt że nazwy modeli są zapisane w liczbie mnogiej. My tych 
+      zapisów nie generowaliśmy, Python sam sobie wywnioskował (dodał literę 
+      's' i tyle). Jednak wiemy, że tworzenie odmian nazw języków ludzi w 
+      świecie komputerów od zawsze było problemem. Tak jest i w tym przypadku.
+      Załóżmy że mamy (tylko tak dla przykładu), model o nazwie 'Entry'. Liczba
+      mnoga od 'Entry' to 'Entries'. Python domyślnie stworzy 'Entrys'. 
+      Oczywiście zostało to przewidziane. W celu zdefiniowania prawidłowej 
+      nazwy dla liczby mnogiej możemy użyć <strong>podklasy</strong> (klasy w 
+      klasie, nie mylić z klasą potomną) <strong>Meta</strong>, która definiuje
+      tak jakby atrybuty opisujące samą klasę, w niej definiujemy atrybut 
+      <em>verbose_name_plural</em>. Pamiętajmy o tym że klasa <em>Meta</em> 
+      musi być zawarta w innej klasie.
+               </p>
+               <p>
+                       Wracając do dodawania danych do modeli za pomocą witryny administracyjnej.
+      Dane dodajemy przy użyciu plusika - zostaniemy przeniesieni bezpośrednio 
+      do formularza wprowadzającego dane do bazy, albo klikając na nazwę modelu
+      - zostaniemy przeniesieni do strony zawierającej egzemplarze tego modelu,
+      gdzie klikamy przycisk "Add &lt;nazwa_modelu&gt; +". Kiedy dodamy jakiś 
+      egzemplarz (wypełniając formularz i klikając przycisk <em>save</em>), 
+      to podglądając listę egzemplarzy modelu to dane odnośnie egzemplarza 
+      jakie widzimy są właśnie wynikiem działania metody <em>__str__</em>. 
+      Jak widać panuje pełna dowolność, co zostanie nam przestawione jako 
+      reprezentacja danego modelu.
+               </p>
+    <h3 id="2.2.10.djangoshell">2.2.10. Powłoka Django</h3>
+               <p>
+                       Po dodaniu danych, możemy przejść do <strong>powłoki Django</strong>. Tę 
+      powłokę możemy wykorzystać (a nawet powinniśmy) testowania zapytań do 
+      bazy. Powłokę uruchamiamy poleceniem.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py shell
+</pre>
+               <p>
+                       Przed przystąpieniem do wydawania zapytań, należy zaimportować do powłoki
+      niezbędne nam modele. Najprostsze zapytanie wygląda następująco.
+               </p>
+<pre class="code-block">
+# Import modeli
+from pizzas.models import Pizza, Toping
+
+pizzas = Pizza.objects.all()
+</pre>
+               <p>
+                       W poleceniu <code class="code-inline">from</code>, 
+      <code class="code-inline">pizzas</code> jest nazwą aplikacji. 
+      Zmienna <code class="code">pizzas</code> będzie przechowywać listę (tzw.
+      <em>query set</em>) wszystkich rekordów z tabeli (egzemplarzy modelu).  
+      Aby pobrać konkretny rekord użyjemy innej metody. 
+      Metoda <code class="code-inline">get()</code> pobiera jako argument 
+      warunek, na podstawie którego ma wybrać danych rekord, jeśli nie podamy 
+      warunku, to zostanie zgłoszony błąd że funkcja zwróciła więcej niż jeden
+      egzemplarz.
+               </p>
+<pre class="code-block">
+pepperoni = Pizza.objects.get(name='Pepperoni')
+</pre>
+               <p>
+                       Teraz mając jeden rekord w zmiennej, mamy możliwość sprawdzenia jakie są 
+      dodatki na naszej pizzy, odwołując się do innego modelu za pomocą naszego
+      klucza zewnętrznego/obcego.
+               </p>
+<pre class="code-block">
+pepperoni_tops = pepperoni.toping_set.all()
+</pre>
+               <p>
+                       Aby odwołać się do innego modelu za pomocą klucza obcego, używamy 
+      atrybutu naszej wydobytej już pizzy (bo to jej dodatki chcemy obejrzeć), 
+      który jest obiektem o nazwie składającej się z nazwy modelu do, którego 
+      się odwołujemy, napisanego za pomocą małych liter (<strong>Uwaga</strong>,
+      zapis nazwy modelu małymi literami jest istotny!), zakończonego sufiksem
+      (przyrostkiem) <code class="code-inline">_set</code></strong> oraz metody,
+      która wydobędzie nam rekordy. Tak wydobyte dane możemy sobie posortować,
+      do sortowania służy metoda <code class="code-inline">order_by()</code> 
+      jako argument przyjmuje nazwę pola według jakiego ma sortować zwracane 
+      dane. Nazwę pola umieszczamy jako ciąg tekstowy, czy to w apostrofach, 
+      czy w cudzysłowie. Wynik sortowania możemy odwrócić, stawiając myślnik
+      (<strong>-</strong>) przed nazwą pola, nadal w ciągu tekstowym</strong>.
+               </p>
+<pre class="code-block">
+pepperoni_tops = pepperoni.toping_set.order_by('-name')
+</pre>
+               <p>
+                       Powłoka w naszej pracy z Django będzie odgrywać ważną rolę, dzięki niej 
+      możemy testować nasze zapytania zanim umieścimy je w widokach, co jest 
+      znacznie lepszym rozwiązaniem a niżeli używanie niepewnych zapytań.
+               </p>
+    <h2 id="2.3.creatingappspages">2.3. Tworzenie aplikacji</h2>
+               <p>
+                       Kiedy mamy omówione modele oraz zapytania to teraz możemy przejść do 
+      tworzenia naszych stron aplikacji. Tworzenie stron aplikacji możemy 
+      podzielić na trzy czynności: <strong>mapowanie adresów URL</strong>, 
+      utworzenie <strong>widoku</strong> oraz utworzenie 
+      <strong>szablonu strony</strong>. Skupimy się w tym momencie na stronie 
+      głównej. Strona główna powinna zostać wyświetlona, kiedy użytkownika poda
+      adres strony np. https://terminallog.morketsmerke.net. Kiedy my podamy 
+      teraz adres naszego serwera dostaniem stronę z informacją o tym, że nasz
+      projekt Django jest gotowy do pracy.
+    </p>
+    <h3 id="2.3.1.sitemappings">2.3.1. Mapowanie stron aplikacji</h3>
+    <p>
+      Aby moc mapować nasze adresy na 
+      konkretne strony, musimy przekierować adres serwera w pliku 
+      <em>urls.py</em> w katalogu naszego projektu na plik mapowania URL 
+      (<em>urls.py</em>) w katalogu naszej aplikacji. Jakby jeszcze tego było 
+      mało, Django mapując URL-e, całkowicie ignoruje adres serwera.
+               </p>
+               <p>
+                       Na początku w katalogu naszej aplikacji <em>pizzas</em> tworzymy plik o 
+      nazwie <em>urls.py</em>. Wewnątrz pliku importujemy funkcje 
+      <code class="code-inline">path</code> z modułu 
+      <code class="code-inline">django.urls</code> oraz importujemy widoki 
+      (o widokach za chwilę). Następnie definiujemy zmienną 
+      <code class="code-inline">app_name</code> z nazwą aplikacji, pozwoli nam
+      to na łatwe tworzenie odnośników, do innych podstron tej aplikacji, 
+      następnie wewnątrz listy <code class="code-inline">urlpatterns</code> 
+      deklarujemy nasze mapowania, zawartość pliku powinna wyglądać mniej 
+      więcej tak.
+               </p>
+<pre class="code-block">
+"""Definiuje wzorce adresów URL dla pizzas."""
+
+from django.urls import path
+
+from . import views
+
+app_name='pizzas'
+urlpatterns = [
+    path('', views.index, name='index'),
+]
+</pre>
+               <p>
+                       Funkcja <code class="code-inline">path</code> przyjmuje 
+      jak widzimy powyżej trzy argumenty. Pierwszy z nich, jest ciąg, który 
+      zostanie przekazany przez przeglądarkę w momencie żądania danej strony. 
+      Teraz ten ciąg jest pusty, ponieważ po przez adres serwera będziemy żądać
+      strony głównej naszej aplikacji. Drugim argumentem jest funkcja widoku, 
+      której zadaniem jest przetworzenie i przygotowanie danych do użycia w 
+      szablonie. Jeśli mówimy o czynnościach jakie wykonuje dana 
+      aplikacja internetowa w Django, to mówimy o czynnościach wykonywanych 
+      właśnie przez kod zdefiniowany ciele funkcji widoku. Przeważnie jedna 
+      podstrona to jedna funkcja widoku. Funkcja widoku jest uruchamiana w 
+      momencie gdy żądanie zostanie dopasowane do pierwszego argumentu funkcji
+      <em>path</em>. Ostatnim argumentem jest nazwa zmiennej używana przy 
+      tworzeniu odnośników w szablonach, Python podstawi wartość pierwszego 
+      parametru jeśli tworząc odnośnik odwołamy się do tej zmiennej.
+               </p>
+    <h3 id="2.3.2.creatingaview">2.3.2. Tworzenie widoku</h3>
+               <p>
+                       Po zdefiniowaniu mapowania, czas na drugą czynność. Na zdefiniowanie kodu
+      funkcji widoku. Przechodzimy do pliku <em>views.py</em> następnie 
+      tworzymy nową funkcję o nazwie <em>index</em> przyjmującej parametr o 
+      nazwie <em>request</em>. Z racji tego że jest to strona główna, to będzie
+      się ona opierać głównie na szablonie. Więc tutaj nasza funkcja widoku, 
+      będzie mieć tylko jedną linę, kiedy otworzymy plik <em>views.py</em> 
+      pierwsza linia zawiera import funkcji 
+      <code class="code-inline">render</code>, 
+      odpowiada ona za wygenerowanie gotowego pliku HTML z szablonu, który 
+      zrozumie każda przeglądarka. Funkcja <em>render</em> przyjmuje w tym 
+      przypadku dwa argumenty. Żądanie przechowywane w parametrze 
+      <code class="code-inline">request</code> oraz ścieżkę dostępu do 
+      szablonu. Plik <em>views.py</em> powinien wyglądać następująco.
+               </p>
+<pre class="code-block">
+from django.shortcuts import render
+
+# Create your views here.
+
+def index(request):
+    """Strona główna aplikacji Pizzas"""
+    return render(request, 'pizzas/index.html')
+</pre>
+    <h3 id="2.3.3.creatingatemplate">2.3.3. Tworzenie szablonu</h3>
+               <p>
+                       Ze ścieżką dostępu do szablonu jest o tyle zabawnie że, aby szablon był 
+      widziany przez Django musi być umieszczony w katalogu aplikacji następnie
+      w podkatalogu <em>templates</em>, w którym znajduje się kolejny 
+      podkatalog o nazwie aplikacji, a w nim dopiero szablon. Pliki szablonów 
+      to tak naprawdę pliki HTML, które zawierają 
+      <strong>znaczniki szablonu</strong>, dzięki którym możemy wprowadzać 
+      nasze dane na strony witryny, ale również w prosty sposób nią zarządzać. 
+      Szablon strony głównej nie zawiera wiele informacji, nie zawiera nawet 
+      żadnego znacznika szablonu.
+               </p>
+<pre class="code-block">
+&lt;p&gt;Pizzeria&lt;/p&gt;
+
+&lt;p&gt;Aplikacja ta pozwala na przymowanie zamówień oraz wyświetlanie menu pizzerii&lt;/p&gt;
+</pre>
+    <h3 id="2.3.4.mappingapps">2.3.4. Mapowanie aplikacji</h3>
+    <p>
+      Chcąc uruchomić do co zrobiliśmy do tej pory, musimy przed uruchomieniem
+      serwera wskazać w pliku mapowania URL-i projektu konkretną aplikację. Tę
+      czynność należy wykonać w pliku <em>&lt;nazwa_projektu&gt;/urls.py</em> w
+      tym konkrentym przypadku jest to <em>pizzeria/urls.py</em>. Wykonanie
+      czynności rozpoczynamy od zaimportowanie funkcji <em>include</em>.
+      Funkcją ta jest dostępna w module <em>django.urls</em> więc po 
+      <em>path</em> na górze pliku do pisujemy 
+      <code class="code-inline">, include</code>.
+    </p>
+<pre class="code-block">
+from django.urls import path, include
+</pre>
+    <p>
+      Następnie podobnie do mapowań stron aplikacji, jako kolejny element list
+      podajemy wywłołanie funkcji <code class="code-inline">path</code> wraz
+      z pustym żądaniem oraz zamiast podawać funkcję widoku oraz nazwę zmiennej
+      wywołujemy funkcję <code class="code-inline">include</code> wraz ze
+      wskazaniem pliku mapowania stron aplikacji w postaci 
+      <em>'nazwa_aplikacji.urls'</em> 
+    </p>
+<pre class="code-block">
+from django.contrib import admin
+from django.urls import path, include
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('', include('pizzas.urls')),
+]
+</pre>
+    <h3 id="2.3.5.anexampleexpanding">2.3.5. Rozszerzanie przykładu</h3>
+               <p>
+                       Z racji tego że mamy trochę za mało informacji, aby zaprezentować duże 
+      możliwości szablonów w Django, rozbudujemy trochę naszą aplikacje o jedną
+      podstronę zawierającą menu naszej pizzerii.
+               </p>
+               <p>
+                       Naszą rozbudowę zaczniemy od stworzenia szablonu, w którym to będą 
+      znajdować się same odnośniki do naszych podstron, Inne szablony będą 
+      dziedziczyć te elementy od niego. W naszym katalogu z szablonami 
+      tworzymy plik o nazwie <em>base.html</em>. Plik zawiera w sumie dwie linijki
+               </p>
+<pre class="code-block">
+&lt;a href="{% url 'pizzas:index' %}"&gt;Pizzeria&gt;/a&lt;
+
+{% block content %}{% endblock content %}
+</pre>
+               <p>
+                       Znacznik szablonu <code class="code-inline">url</code> w atrybucie 
+      <code class="code-inline">href</code> wstawi bezwzględny adres URL 
+      zawierający wzorzec przypisany do nazwy 
+      <code class="code-inline">index</code> w funkcji <em>path</em> w pliku 
+      <em>urls.py</em></strong>. Po przeniesieniu tytułu jako odnośnika do 
+      szablonu nadrzędnego. Możemy teraz wpisać linię ustawiającą
+      <strong>dziedziczenie w szablonie</strong> 
+      <em>index.html</em>. Linię wstawiamy na samej górze.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+</pre>
+               <p>
+                       Kiedy mamy już odpowiednie miejsce gdzie będziemy umieszczać odnośniki do
+      naszych podstron. Możemy przejść teraz do utworzenia widoku naszej 
+      podstrony, naszą stronę nazwiemy klasycznie 
+      <code class="code-inline">menu</code>. W pliku <em>views.py</em> naszej 
+      aplikacji <em>pizzas</em>, umieszczamy poniższy kod.
+               </p>
+<pre class="code-block">
+def menu(request):
+
+    from pizzas.models import Pizza,Toping
+
+    pizzas = Pizza.objects.all()
+
+    pizza_dict={}
+    pizzas_list=[]
+
+    class PizzaClass():
+        def __init__(self, name, topings):
+            self.name = name
+            self.topings = topings
+
+    for pizza in pizzas:
+        pizza_name = f"{pizza}"
+        topings = pizza.toping_set.all()
+        t=""
+        for toping in topings:
+            if len(t) == 0:
+                t=f"{toping}, "
+            else:
+                t=f"{t}{toping}, "
+        t=t.rstrip(', ')
+        some_pizza = PizzaClass(pizza_name, t)
+        pizzas_list.append(some_pizza)
+
+    pizza_dict['pizzas']=pizzas_list
+
+    return render(request, 'pizzas/menu.html', pizza_dict)
+</pre>
+               <p>
+                       Przed przystąpieniem do objaśniania chciałbym przestawić model 
+      wyświetlania danych, otóż chciałem uzyskać taki sam lub zbliżony ulotkom
+      z pizzerii wydruk menu, czyli:
+               </p>
+               <p>
+                       <strong>nazwa_pizzy - składniki/dodatki</strong>
+               </p>
+               <p>
+                       A więc problem nie był kod widoku, ponieważ tu mogliśmy zbudować kod 
+      realizujący to samo zadanie w znacznie prostszy sposób, ale kod szablonu.
+      Znaczniki szablonu mają duże możliwości, jednak nie są pełnym 
+      odwzorowaniem tego co można zrobić w Pythonie. Rozwiązanie było banalne.
+      Mamy listę z nazwami pizz, uruchamiamy pętle, wewnątrz tej iteracji, 
+      odwołujemy się nazwą pizzy do listy składników i problem rozwiązany. 
+      Jednak w szablonach Django, jedyne co możemy zrobić z zmiennymi to nadać
+      im wartość i wypisać. Nie możemy użyć zmiennej szablonu jako klucza aby 
+      odwołać się do kolejnej listy w zagnieżdżonej pętli 
+      <code class="code-inline">for</code>. Używanie zmiennej <em>context</em>
+      w szablonie zakończyło się fiaskiem, mogliśmy pisać kod szablonu, który 
+      niczego nie generował. Zajrzałem więc do oficjalnej dokumentacji Django,
+      rozwiązanie od razu nie przypadło mi do gustu, słownik + lista + obiekty,
+      jednak jak możemy się o tym przekonać rozwiązanie działa.
+                       Słownik w tym przypadku jest strukturą danych przekazywaną do szablonu za
+      sprawą funkcji <code class="code-inline">render</code>, lista jest
+      strukturą dzięki, której może odbyć się iteracja przez nasze pizze, 
+      obiekty pizzy został użyty w celu spięcia nazwy pizzy oraz jej dodatków w
+      jednej strukturze, do której będziemy mogli się odwołać w szablonie.
+      Zapewne istnieje inne rozwiązanie, jednak jeśli drogi czytelniku w życiu
+      stworzyłeś może jeden program w Pythonie, przeczytałeś całą pierwszą 
+      część <em>Crash Course</em> (uwaga wykonując większość ćwiczeń, 
+      wszystkich nie trzeba ponieważ się powtarzają, ewentualnie trzeba zmienić
+      jedną rzecz jednak logika pozostaje ta sama) i dotarłeś aż tutaj to moja
+      umiejętność programowania w Pythonie jest mniej więcej na Twoim poziomie.
+    </p>
+    <p>
+      Tak więc co się dzieje w widoku, już tłumaczę. Na początku importujemy 
+      nasze modele, żeby było skąd dane pobrać. Wydane zostaje zapytanie do 
+      modelu <code class="code-inline">Pizza</code> o wszystkie (egzemplarze 
+      modelu) rekordy, tworząc listę naszych pizz.
+                       Tworzymy klasę naszej pizzy, klasa będzie zawierać tylko metodę 
+      <code class="code-inline">__init__</code> a oraz dwie właściwości nazwę 
+      oraz dodatki jako ciągi tekstowe. Przeprowadzając iteracje z elementu 
+      naszej listy pizz tworzymy nazwę pizzy po prostu przechowując ją w 
+      zmiennej jako ciąg tekstowy, pobieramy listę naszych dodatków odwołując 
+      się kluczem obcym pizzy do modelu <code class="code-inline">Toping</code>.
+      Przerabiamy listę dodatków na ciąg tekstowy. Po utworzeniu listy dodatków
+      jako ciągu możemy, zacząć tworzyć obiekty. Nowo utworzone obiekty 
+      trafiają do listy i tak kończy się iteracja. Na samym końcu dodajmy naszą
+      listę obiektów do słownika, który w ostatniej linii naszego widoku jest 
+      przekazywany do szablonu za pomocą funkcji 
+      <code class="code-inline">render</code>. Poniżej znajduje się kod naszego
+      szablonu.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/index.html' %}
+
+{% block content %}
+
+&lt;p&gt;Menu&lt;/p&gt;
+
+&lt;ul&gt;
+    {% for pizza in pizzas %}
+        &lt;li&gt;
+            {{ pizza.name }}
+            &lt;small&gt;- {{ pizza.topings }}&lt;/small&gt;
+        &lt;/li&gt;
+    {% endfor %}
+&lt;/ul&gt;
+
+
+{% endblock content %}
+</pre>
+               <p>
+                       W tym momencie powinniśmy mieć gotowe menu. Teraz przygotujemy stronę, 
+      która wyświetli nam listę dodatków każdej z pizzy, abyś mogli zobaczyć 
+      jak działa przekazywanie danych do aplikacji za pomocą adresu URL.
+               </p>
+               <p>
+                       Naszą rozbudowę rozpoczęliśmy od utworzenia widoku dla nowej strony.
+      Widok jak widać poniżej jest bardzo prosty.
+               </p>
+<pre class="code-block">
+def pizza_site(request, pizza_id):
+
+    from pizzas.models import Pizza,Toping
+
+    context = {}
+
+    name = Pizza.objects.get(id=pizza_id)
+    topings = name.toping_set.all()
+
+    context['name'] = name
+    context['topings'] = topings
+
+    return render(request, 'pizzas/pizza_site.html', context)
+</pre>
+               <p>
+                 Zwrócić uwagę należy na dodatkowy parametr przekazywany do widoku. 
+      Parametr o nazwie <code class="code-inline">pizza_id</code> będzie 
+      przekazywali za pomocą adresu URL, taki parametr definiuje się we wzorcu
+      adresu URL. Wzorcem zajmiemy się pod koniec naszych prac.
+      Szablon dla tej strony został przedstawiony poniżej. Za pomocą słownika
+      <code class="code-inline">context</code> została przekazana nazwa pizzy 
+      oraz lista z jej składnikami, nową rzeczą wprowadzoną tutaj jest 
+      znacznik szablonu <code class="code-inline">{% empty %}</code> oznacza on
+      mniej więcej to że jeśli interpreter natrafi na pustą listę to możemy 
+      zdefiniować w bardzo prosty sposób komunikat o tym że składniki na tej 
+      pizzy są na życzenie.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+&lt;p&gt;{{ name }}&lt;/p&gt;
+  &lt;ul&gt;
+    {% for toping in topings %}
+        &lt;li&gt;{{ toping }}&lt;/li&gt;
+    {% empty %}
+        &lt;li&gt;Dodatki na życzenie&lt;/li&gt;
+    {% endfor %}
+&lt;/ul&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Mając już szablon możemy przejść do mapowania URL-i. W aplikacji 
+      <em>pizzas</em> w pliku <em>urls.py</em> za pomocą funkcji 
+      <code class="code-inline">path</code> dopisujemy do listy 
+      <em>urlspattern</em> kolejny wzorzec adresu.
+               </p>
+<pre class="code-block">
+path('pizza/&lt;int:pizza_id&gt;', views.pizza_site, name='pizza_site')
+</pre>
+       <p>
+               Stąd właśnie bierze się parametr widoku 
+    <code class="code-inline">pizza_site</code>, jeśli po <em>pizza/</em> 
+    podamy liczbę całkowitą to wywołamy widok <em>pizza_site</em> przekazując
+    tę liczbę jako identyfikator rekordu pizzy</strong>. Wszystko świetnie, 
+    jednak nie znamy <em>id</em> pizz. Należało by stworzyć odnośnik do 
+    konkretnej pizzy w menu. W obecnej formie naszego menu próżno szukać 
+    <em>id</em>. Dlatego też musimy zmodyfikować widok <em>menu</em> dodając do
+    naszej klasy atrybut id, który można pobrać bezpośrednio z egzemplarza 
+    modelu za pomocą notacji kropki i właściwości o nazwie <em>id</em>. Poniżej
+    wstawiam zmieniony kod widoku <code class="code-inline">menu</code>.
+       </p>
+<pre class="code-block">
+def menu(request):
+
+    from pizzas.models import Pizza,Toping
+
+    pizzas = Pizza.objects.all()
+
+    pizza_dict={}
+    pizzas_list=[]
+
+    class PizzaClass():
+        def __init__(self, id, name, topings):
+            self.id = id
+            self.name = name
+            self.topings = topings
+
+    for pizza in pizzas:
+        pizza_name = f"{pizza}"
+        topings = pizza.toping_set.all()
+        t=""
+        for toping in topings:
+            if len(t) == 0:
+                t=f"{toping}, "
+            else:
+                t=f"{t}{toping}, "
+        t=t.rstrip(', ')
+        some_pizza = PizzaClass(pizza.id, pizza_name, t)
+        pizzas_list.append(some_pizza)
+
+    pizza_dict['pizzas']=pizza_list
+
+    return render(request, 'pizzas/menu.html', pizza_dict)
+</pre>
+               <p>
+                       Teraz musimy utworzyć nasz odnośnik w pętli w pliku szablonu menu, aby 
+      pojawił się dla każdej pizzy.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/index.html' %}
+
+{% block content %}
+
+&lt;p&gt;Menu&lt;/p&gt;
+
+&lt;ul&gt;
+    {% for pizza in pizzas %}
+        &lt;li&gt;
+            {{ pizza.name }}
+            &lt;small&gt;- {{ pizza.topings }}&lt;/small&gt;
+            &lt;a href="{% url 'pizzas:pizza_site' pizza.id %}"&gt;Pokaż&lt;/a&gt;
+        &lt;/li&gt;
+    {% endfor %}
+&lt;/ul&gt;
+
+
+{% endblock content %}
+</pre>
+               <p>
+                       Podczas tworzenia adresu odnośnika za pomocą znacznika szablonu 
+      <code class="code-inline">url</code> odwołujemy się do wzorca 
+      zdefiniowanego za pomocą wartości nadanej parametrowi <em>name</em> 
+      funkcji <em>path</em>w pliku <em>urls.py</em>, tym razem wartość 
+      <em>pizza_id</em> podajemy obok odwołania się do wzorca. Teraz przy 
+      wywołaniu strony menu przy każdej z pizz powinien pokazać się odnośnik
+      "Pokaż" kierujący nas do konkretnej strony pizzy.
+               </p>
+               <h2 id="2.4.theuserapplication">2.4. Aplikacja users</h2>
+               <p>
+                       Skoro mamy już stronę główną, mamy menu i jest z czego wybierać możemy 
+      teraz przejść do składania zamówień. Złożenie zamówienia w naszej 
+      pizzerii będzie wymagało utworzenia konta. Obsługą kont zajmie się 
+      odrębna aplikacja <em>users</em>, którą teraz utworzymy. Przechodzimy do
+      katalogu naszego projektu i wydajemy następujące polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py startapp users
+</pre>
+               <p>
+                       Po wydaniu tego polecenia zostanie utworzona struktura plików identyczna
+      jak dla aplikacji <em>pizzas</em>. Teraz instalujemy aplikacje 
+      <em>users</em> w identyczny sposób jak instalowaliśmy aplikacje 
+      <em>pizzas</em>.
+               </p>
+<pre class="code-block">
+INSTALLED_APPS = [
+    'pizzas',
+    'users',
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+]
+</pre>
+               <h3 id="2.4.1.userslogin">2.4.1. Logowanie użytkowników</h3>
+               <p>
+                       Naszą przygodę z kontami użytkowników zaczniemy od dania możliwości 
+      logowania potencjalnym klientom naszej pizzerii. Samo logowanie w Django
+      jest banalne ponieważ korzystać będziemy z gotowego, przygotowanego przez
+      Django widoku dla logowania. Jedynego czego będziemy potrzebować to 
+      mapowania URL oraz szablonu. Zaczniemy od mapowania. 
+      W pliku <em>urls.py</em> projektu <em>pizzeria</em> na liście 
+      <code class="code-inline">urlpatterns</code> dokonujemy takiego samego 
+      przekierowania jak w przypadku przekierowania w aplikacji <em>pizzas</em>
+      jednak naszym wzorcem będzie <code class="code-inline">users/</code> a
+      pliku <em>urls.py</em> będzie znajdował się w katalogu aplikacji 
+      <em>users</em> (jako argument funkcji 
+      <code class="code-inline">include</code> podajemy 
+      <code class="code-inline">users.urls</code>).
+               </p>
+<pre class="code-block">
+urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('users/', include('users.urls')),
+    path('', include('pizzas.urls'))
+]
+</pre>
+
+               <p>
+                       W aplikacji <em>users</em> tworzymy plik urls.py. W nim importujemy 
+      funkcje <code class="code-inline">path</code> oraz 
+      <code class="code-inline">include</code> z modułu 
+      <code class="code-inline">django.urls</code>, definiujemy 
+      <code class="code-inline">app_name</code> następnie na liście 
+      <code class="code-inline">urlpatterns</code> dodajemy jedno wywołanie 
+      funkcji <code class="code-inline">path</code> kierujące puste domyślne
+      zapytanie do pliku zdefiniowanego przez Django 
+      <code class="code-inline">django.contrib.auth.urls</code>.
+               </p>
+<pre class="code-block">
+from django.urls import path,include
+
+app_name="users"
+urlpatterns = [
+    path('', include('django.contrib.auth.urls'))
+]
+</pre>
+               <p>
+                       Teraz kiedy mapowanie jest gotowe, możemy przejść do utworzenia szablonu.
+      Domyślna funkcja widoku stworzona do logowania generuje stronę na 
+      podstawie szablonu <em>login.html</em> umieszczonego w katalogu 
+      <em>templates/registration</em>. 
+      <strong>Te nazwy muszą zostać zachowane</strong>. Utwórzmy te katalogi 
+      wewnątrz katalogu aplikacji <em>users</em>. Następnie utworzymy plik z 
+      szablonem.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    &lt;form action="{% url 'users:login' %}" method="post"&gt;
+        {% csrf_token %}
+        {{ form.as_p }}
+        &lt;button name="submit"&gt;Zaloguj się&lt;/button&gt;
+       &lt;input type="hidden" name="next" value="{% url 'pizzas:index' %}" /&gt;
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Tak prezentuje się nasz szablon logowania. Warto zwrócić uwagę na to jak
+      łatwy jest dostęp do zasobów innej aplikacji wystarczy odpowiednia 
+      ścieżka (patrz znacznik <em>extends</em>), w atrybucie 
+      <em>action</em> zdefiniowana została strona, która ma obsłużyć dany 
+      formularz. Znacznik szablonu <code class="code-inline">csrf_token</code>
+      służy zabezpieczeniu formularza przez atakiem CSRF. Następnie wyświetlany
+      jest sam formularz, który przechowywany jest w zmiennej 
+      <code class="code-inline">form</code>. Wyświetlenie jej wraz z 
+      <code class="code-inline">as.p</code> spowoduje, że etykiety oraz pola 
+      wprowadzania danych zostaną wyświetlone jako jeden akapit i tak dla 
+      każdego z elementów formularza. Formularze w Django nie zawierają 
+      przycisków, trzeba je zdefiniować samemu. Ostatnią rzeczą jest 
+      przekazanie wraz z formularzem do widoku adres strony, do której ma 
+      zostać przekierowany użytkownik po poprawnym zalogowaniu. Jako 
+      ciekawostkę możemy sobie dodać warunek w formularzu, który wyświetli nam
+      komunikat z informacją o tym że formularz nie został poprawnie 
+      wypełniony. W ten czas nasz formularz wyglądać będzie tak:
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    {% if form.errors %}
+        &lt;p&gt;
+            Nazwa użytkownika i hasło są niepoprawne. Spróbuj ponownie.
+        &lt;/p&gt;
+    {% endif %}
+
+    &lt;form action="{% url 'users:login' %}" method="post"&gt;
+        {% csrf_token %}
+        {{ form.as_p }}
+        &lt;button name="submit"&gt;Zaloguj się&lt;/button&gt;
+        &lt;input type="hidden" name="next" value="{% url 'pizzas:index' %}" /&gt;
+   &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Dlaczego jednak jako ciekawostkę? Otóż Django sam dodaje takową 
+      informacje jeśli formularz nie przejdzie walidacji. Teraz dodamy warunek
+      w pliku w szablonie bazowym aplikacji <em>pizzas</em>, po to abyśmy 
+      wiedzieli, że zostaliśmy zalogowani oraz w przeciwnym wypadku wyświetli
+      odnośnik prowadzący do strony logowania. Poniżej znajduje się już 
+      uzupełniony kod szablonu bazowego aplikacji <em>pizzas</em>.
+               </p>
+<pre class="code-block">
+&lt;p&gt;
+    &lt;a href="{% url 'pizzas:index' %}"&gt;Pizzeria&lt;/a&gt;-
+    &lt;a href="{% url 'pizzas:menu' %}"&gt;Menu&lt;/a&gt;
+&lt;/p&gt;
+
+{% if user.is_authenticated %}
+    &lt;p&gt;
+        Witaj, {{ user.username }}
+    &lt;/p&gt;
+{% else %}
+    &lt;p&gt;
+        &lt;a href="{% url 'users:login' %}"&gt;Zaloguj się&lt;/a&gt;
+    &lt;/p&gt;
+{% endif %}
+
+{% block content %} {% endblock content%}
+</pre>
+               <p>
+                       Jednego użytkownika już mamy. Możemy się zalogować się jako 
+      superużytkownik. Po poprawnym zalogowaniu zostaniemy przeniesieni z 
+      powrotem na stronę główną, jednak teraz zamiast <em>Zaloguj się</em>
+      zobaczymy <em>Witaj, pizza_admin</em>. Teraz pod powitaniem umieścimy 
+      przycisk <em>Wyloguj</em>, który będzie kończył sesję użytkownika w 
+      aplikacji. Wylogowanie również jest funkcją, która jest dostarczana wraz
+      z Django. Mapowanie URL-u wylogowania jest również dostarczane przez 
+      Django, tak jak mapowanie URL-u logowania. Szablon bazowy wygląda 
+      następująco po dodaniu nowego odnośnika.
+               </p>
+<pre class="code-block">
+&lt;p&gt;
+    &lt;a href="{% url 'pizzas:index' %}"&gt;Pizzeria&lt;/a&gt;-
+    &lt;a href="{% url 'pizzas:menu' %}"&gt;Menu&lt;/a&gt;
+&lt;/p&gt;
+
+{% if user.is_authenticated %}
+    &lt;p&gt;
+        Witaj, {{ user.username }}
+    &lt;/p&gt;
+    &lt;p&gt;
+        &lt;a href="{% url 'users:logout' %}"&gt;Wyloguj&lt;/a&gt;
+    &lt;/p&gt;
+{% else %}
+    &lt;p&gt;
+        &lt;a href="{% url 'users:login' %}"&gt;Zaloguj się&lt;/a&gt;
+    &lt;/p&gt;
+    &lt;p&gt;
+        &lt;a href="{% url 'users:register' %}"&gt;Zarejestruj się&lt;/a&gt;
+    &lt;/p&gt;
+{% endif %}
+
+{% block content %} {% endblock content%}
+</pre>
+               <p>
+                       W ramach eksperymentu, kliknijmy w ten odnośnik. Zostaniemy poinformowani
+      o wylogowaniu z naszej aplikacji przez witrynę administracyjną Django. 
+      Nie zbyt fajnie, co? Oczywiście to zachowanie możemy zmienić, tworząc 
+      nowy szablon w katalogu <em>templates/registration</em>. 
+      <strong>Uwaga</strong>, Plik musi nazywać się: logged_out.html. 
+      Po rozszerzeniu pliku o szablon bazowy, między znacznikami szablonu 
+      oznaczającymi zawartość strony w tym szablonie możemy umieścić wszystko
+      co nam się podoba.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    &lt;p&gt;
+        Dziękujemy za skorzystanie z naszej aplikacji.
+   &lt;/p&gt;
+
+{% endblock content %}
+</pre>
+               <h3 id="2.4.2.theuserregistration">2.4.2. Rejestracja użytkowników</h3>
+               <p>
+                       Teraz możemy dać możliwość samodzielnego utworzenia konta na stronie 
+      naszej pizzerii. Tutaj nie jest już tak kolorowo. Jedyne co nam 
+      Django oferuje w tym przypadku jest formularz. Widok, szablon oraz 
+      mapowanie URL-u musimy utworzyć samodzielnie. Zaczynamy od widoku dla 
+      formularza rejestracji.
+               </p>
+<pre class="code-block">
+from django.shortcuts import render, redirect
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth import login
+
+def register(request):
+
+    if request.method != 'POST':
+        form = UserCreationForm()
+    else:
+        form = UserCreationForm(data=request.POST)
+        if form.is_valid():
+            new_user = form.save()
+            login(request, new_user)
+            return redirect('pizzas:index')
+   content = {'form': form}
+   return render(request, 'registration/register.html", context)
+</pre>
+               <p>
+                       W tym przypadku aby funkcja widoku mogła poprawnie działać oraz 
+      wyświetlać nam formularz, potrzebujemy modułów. Pierwszą funkcją jaką 
+      importujemy jest <code class="code-inline">redirect</code>, powoduje ona
+      przekierowanie HTTP, na stronę podaną jako argument. Adresy stron podane
+      jako argumenty funkcji <em>redirect</em> czy też w znacznikach szablonu 
+      <em>url</em> podajem w formacie 
+      <code class="code-inline">nazwa_aplikacji:nazwa_mapowania</code> -
+      wartość argumentu <em>name</em> funkcji <em>path</em> w pliku 
+      <em>urls.py</em>.</strong> Następnie importujemy nasz formularz oraz 
+      funkcję <em>login</em>. Za pomocą tej funkcji będzie możliwe automatyczne
+      zalogowanie nowo utworzonego użytkownika. Funkcje widoku obsługujące 
+      formularz posiadają pewien schemat. Taka funkcja rozpoczyna się od 
+      sprawdzenia użytej metody przesłania danych do serwera, protokół HTTP 
+      wyróżnia dwie <strong>GET</strong> oraz <strong>POST</strong>. 
+      Metoda <em>GET</em> służy głównie do obsługi żądań osób odwiedzających 
+      witrynę. Poniżej żądanie wyświetlenia strony konkretnej pizzy.
+               </p>
+<pre class="code-block">
+http://localhost:8000/pizza/1
+</pre>
+               <p>
+                       Żądanie wyświetlenia konkretnej pizzy zostało przesłane do serwera za 
+      pomocą żądania <em>GET</em>. Najprościej można to ująć w ten sposób, że
+      żądania <em>GET</em> są przesyłanie w adresie strony. Natomiast 
+      żądania <em>POST</em> są przesyłane oddzielnym pakietem transmisji.
+      W żądaniach <em>POST</em> najczęsciej są przesyłane dane formularzy.
+               </p>
+               <p>
+                       Jeśli nasz widok, ktoś wywołał za pomocą żądania <em>GET</em> to wtedy 
+      zmiennej <code class="code-inline">form</code> zostanie nadany pusty 
+      formularz. Następnie definiowana jest zmienna 
+      <code class="code-inline">context</code> zawierająca wszelkie dane dla 
+      szablonu w tym nasz formularz. Na sam koniec funkcja widoku zwraca 
+      wygenerowaną przed funkcję <code class="code-inline">render()</code> 
+      stronę, na której znajduje się nasz formularz rejestracji. W przeciwnym 
+      wypadku jeśli nasza funkcja została wywołana za pomocą żądania POST 
+      (np. kiedy użytkownik przesłał formularz), to tworzona jest zmienna z 
+      formularzem gdzie jego dane są pobierane z właściwości 
+      <code class="code-inline">POST</code> obiektu 
+      <code class="code-inline">request</code>.
+                       Za pomocą instrukcji warunkowej <code class="code-inline">if</code> oraz
+      metody formularza <code class="code-inline">is_valid()</code> sprawdza 
+      jest poprawność wypełnienia pól formularza, jeśli któraś z wartości pół 
+      nie przechodzi walidacji (sprawdzenia poprawności), to następną czynnością
+      jest wpisanie formularza do zmiennej 
+      <code class="code-inline">context</code> i wygenerowanej strony z 
+      formularzem oraz komunikatem błędu.
+                       Zaś kiedy formularz został wypełniony bezbłędnie to wykonywana jest 
+      metoda formularza <code class="code-inline">save()</code>, która powoduje
+      zapisanie danych z formularza w bazie danych na podstawie przypisanego do
+      niego modelu. Zwróćmy uwagę na to, że wartość zwraca przez metodę 
+      <em>save()</em> została zapisana do zmiennej 
+      <code class="code-inline">new_user</code>. Dzięki tej zmiennej będzie 
+      możliwe automatyczne zalogowanie zarejestrowanego użytkownika, kiedy mamy
+      tą zmienną możemy zalogować użytkownika za pomocą funkcji 
+      <code class="code-inline">login()</code> ta funkcja pobiera dwa argumenty
+      obiekt żądania (<em>request</em>) oraz odniesienie do użytkownika (
+      <em>new_user</em>).
+                       Kiedy użytkownik został zalogowany, możemy teraz przekierować go na 
+      stronę główną, która zostanie wyświetlona ze spersonalizowanym powitaniem
+      oraz odnośnikiem do wylogowania się z konta na naszej stronie. Teraz 
+      potrzebujemy jeszcze szablonu, który poza odnośnikiem nie różni się 
+      niczym do szablonu logowania.
+               </p>
+               <p>
+                       Plik szablonu formularza rejestracji znajduje się w folderze 
+      <em>templates/registration</em> pod nazwą <em>register.html</em>:
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    {% if form.errors %}
+        &lt;p&gt;Rejestracja nie powiodła się. Spróbuj ponownie&lt;/p&gt;
+    {% endif %}
+
+    &lt;form action="{% url 'users:register' %}" method="post"&lt;
+        {% csrf_token %}
+        {{ form.as_p }}
+        &lt;button name="submit"&gt;Zarejestruj się&lt;/button&gt;
+        &lt;input type="hidden" name="next" value="{% url 'pizzas:index' %}" /&gt;
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Funkcja mapowania w pliku <em>users/urls.py</em> wygląda następująco:
+               </p>
+<pre class="code-block">
+path('register/', views.register, name="register"),
+</pre>
+               <p>
+                       Teraz możemy do szablonu bazowego aplikacji <em>pizzas</em> dodać 
+      odnośnik dla niezalogowanych, prowadzący do naszej strony z rejestracją.
+               </p>
+<pre class="code-block">
+&lt;p&gt;
+    &lt;a href="{% url 'pizzas:index' %}"&gt;Pizzeria&lt;/a&gt;-
+    &lt;a href="{% url 'pizzas:menu' %}"&gt;Menu&lt;/a&gt;
+&lt;/p&gt;
+
+{% if user.is_authenticated %}
+    &lt;p&gt;
+        Witaj, {{ user.username }}
+    &lt;/p&gt;
+    &lt;p&gt;
+        &lt;a href="{% url 'users:logout' %}"&gt;Wyloguj&lt;/a&gt;
+    &lt;/p&gt;
+{% else %}
+    &lt;p&gt;
+        &lt;a href="{% url 'users:login' %}"&gt;Zaloguj się&lt;/a&gt;
+    &lt;/p&gt;
+    &lt;p&gt;
+        &lt;a href="{% url 'users:register' %}"&gt;Zarejestruj się&lt;/a&gt;
+    &lt;/p&lt;
+{% endif %}
+
+{% block content %} {% endblock content%}
+</pre>         
+    <h2 id="2.5.expandingpizzasapplication">2.5. Rozbudowa aplikacji 'pizzas'.</h2>
+               <p>
+                       Teraz kiedy mamy logowanie oraz rejestracje. To powinniśmy mieć możliwość
+      złożenia zamówienia w naszej pizzerii (aplikacja <em>pizzas</em>). Sama 
+      operacja jest dość złożona bo do realizacji tego zadania potrzebujemy 
+      aż 5 elementów: modelu zamówienia, widoku wyświetlającego zamówienia, 
+      widoku dodającego zamówienia, formularza, szablonu i mapowania URL. 
+      Zaczniemy od modelu zamówienia. Na nasze zamówienie będzie składać się 
+      pizza, wielkość, sos pierwszy oraz sos drugi, dowóz czy odbiór własny 
+      oraz datę zamówienia. Model prezentuje się poniżej. Stosować będziemy 
+      skróty, które nasz kucharz będzie stanie odszyfrować dlatego pola są 
+      takie małe.
+               </p>
+<pre class="code-block">
+class Order(models.Model):
+
+    pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)
+    size = models.CharField(max_length=10)
+    sauce1 = models.CharField(max_length=10)
+    sauce2 = models.CharField(max_length=10)
+    deliver = models.CharField(max_length=10)
+    date_order = models.DateTimeField(auto_now_add=True)
+
+    def __str__(self):
+        return f"{self.pizza.name} - {self.size},{self.sauce1},\
+        {self.sauce2},{self.deliver} - {self.date_order}"
+
+</pre>
+               <p>
+                       Po dopisaniu naszego modelu zamówienia musimy wykonać migrację.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py makemigrations pizzas
+(project_env) xf0r3m@macbook:python/django$ python manage.py migrate
+</pre>
+               <p>
+                       Po pomyślnej migracji zarejestrujemy nowy model na witrynie 
+      administracyjnej, po to aby dodać kilka testowych wartość do sprawdzenia
+      widoku wyświetlania złożonych zamówień. Widok złożonych zamówień 
+      prezentuje się następująco:
+               </p>
+<pre class="code-block">
+def orders_view(request):
+
+    from pizzas.models import Order
+
+    orders = Order.objects.order_by('-date_order')
+    context = {'orders': orders}
+    return render(request, 'pizzas/orders_view.html', context)
+</pre>
+               <p>
+                       W szablonie zamiast używać listy użyjemy tabeli. Poniżej znajduje się kod
+      szablonu.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+&lt;table&gt;
+    &lt;thead&gt;
+        &lt;tr&gt;
+            &lt;td&gt;Numer zamówienia&gt;/td&gt;
+            &lt;td&gt;Pizza&lt;td&gt;
+            &lt;td&gt;Wielkość&lt;/td&gt;
+            &lt;td&gt;Sos_1&gt;/td&gt;
+            &lt;td&gt;Sos_2&lt;td&gt;
+            &lt;td&gt;Dostawa&lt;/td&gt;
+        &lt;/tr&gt;
+    &lt;/thead&gt;
+    &lt;body&gt;
+    {% for order in orders %}
+        &lt;tr&gt;
+            &lt;td&gt;{{ order.id }}&lt;/td&gt;
+            &lt;d&gt;{{ order.pizza.name }}&lt;/td&gt;
+            &lt;td&gt;{{ order.size }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce1 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce2 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.deliver }}&lt;/td&gt;
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;&lt;td colspan="6"&gt;Brak zamówień&lt;/td&gt;&lt;/tr&gt;
+    {% endfor %}
+    &lt;/tbody&gt;
+&lt;/table&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Teraz możemy przejść do składania zamówień na naszą pizzę, zaczniemy od 
+      formularza. Nie jest on może trudny w interpretacji ale jest nieco 
+      bardziej złożony niż te przedstawione w książce.
+               </p>
+<pre class="code-block">
+from django import forms
+
+from .models import Order
+
+class NewOrder(forms.ModelForm):
+    class Meta:
+        model = Order
+        fields = ['pizza', 'size', 'sauce1', 'sauce2', 'deliver']
+        labels = {
+            'pizza': 'Pizza',
+            'size': 'Wielkość',
+            'sauce1': 'Pierwszy sos',
+            'sauce2': 'Drugi sos',
+            'deliver': 'Dostawa'
+        }
+        size_choice = [
+            (None, '-----------'),
+            ('S', 'Mała'),
+            ('M', 'Duża'),
+            ('L', 'Familijna'),
+            ('XL', 'XXL 55cm')
+        ]
+        sauce_choice = [
+            ('br', '-----------'),
+            ('k', 'Ketchup'),
+            ('m', 'Majonez'),
+            ('cz', 'Czosnkowy'),
+            ('pik', 'Pikantny')
+        ]
+        deliver_choice = [
+            (None, '-----------'),
+            ('odb', 'Odbiór osobisty'),
+            ('dwz', 'Dowóz')
+        ]
+        widgets = {
+            'size': forms.Select(choices=size_choice),
+            'sauce1': forms.Select(choices=sauce_choice),
+            'sauce2': forms.Select(choices=sauce_choice),
+            'deliver': forms.Select(choices=deliver_choice)
+        }
+</pre>
+               <p>
+                       Formularze w Django to nic innego jak klasy potomne, klasy 
+      <code class="code-inline">ModelForms</code> modułu 
+      <code class="code-inline">django.forms</code>, jednak kodu określającego
+      formularz nie tworzymy w samej klasie potomnej tylko w pod klasie 
+      <code class="code-inline">Meta</code>. Z racji tego, że klasa 
+      <em>ModelForm</em> bazuje na modelach (zresztą jak sama nazwa wskazuje) 
+      musimy pamiętać o ich imporcie jeszcze przed zdefiniowaniem samej klasy.
+                       W klasie <em>Meta</em> podajemy takie informacje jak 
+      model na jakim bazuje formularz 
+      (zmienna <code class="code-inline">model</code>), pola formularza 
+      (lista <code class="code-inline">fields</code>) oraz etykiety 
+      (słownik <code class="code-inline">labels</code>), z 
+      racji tego że informacje przekazywane przez zamawiającego mogą być 
+      predefiniowane, to cały formularz oprzemy na jednym elemencie, na liście
+      wyboru <em>select</em>.
+                       <strong>Jeśli nasz model zawiera klucz obcy, to pole z automatu jest 
+      ustawiane przez Django jako element <em>select</em></strong>. Resztę 
+      naszych pól musimy ustawić samodzielnie.
+                       Zmianie elementów przydzielanych przez Django, służy słownik 
+      <code class="code-inline">widgets</code></strong>, w którym każdemu polu
+      przypisujemy wyświetlany element, w tym przypadku jest to 
+      <code class="code-inline">forms.Select</code> czyli element HTML 
+      <em>select</em> jako argument <code class="code-inline">choices</code> 
+      podajemy listę z dwuelementowych krotek</strong>, w naszym przypadku 
+      zdefiniowaną powyżej słownika <em>widgets</em>.
+    </p>
+    <p>
+                       Jako ciekawostkę podam fakt, że jeśli w jakieś krotce w pierwszym 
+      elemencie podamy jako pierwszy argument, czyli wartość elementu 
+      <em>option</em>, wartość <em>None</em> to pole automatycznie stanie się 
+      polem <em>required</em></strong>, czyli jego wartość musi być ustawiona
+      inaczej przeglądarka nie pozwoli wysłać formularza. Poniżej znajduje się
+      kod widoku obsługującego ten formularz.
+               </p>
+<pre class="code-block">
+def new_order(request):
+
+    if request.method != 'POST':
+        form = NewOrder()
+    else:
+        form = NewOrder(data=request.POST)
+        if form.is_valid():
+            form.save()
+            return redirect('pizzas:thank_you')
+    context = {'form': form}
+    return render(request, 'pizzas/new_order.html', context)
+</pre>
+               <p>
+                       Ten przypadek obsługi jest chyba najprostszy. Nie ma tu nic złożonego, po
+      przejściu walidacji zamówienie jest zapisywane w bazie. Pod mapowaniem 
+      <em>thank_you</em> kryje się jeden akapit z podziękowanie za złożenie 
+      zamówienia. Poniżej znajduje kod szablonu.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    {% if form.errors %}
+        &lt;p&gt;
+            Złożenie zamówienia nie powiodło się. Spróbuj ponownie
+       &lt;/p&gt;
+    {% endif %}
+
+    &lt;form action="{% url 'pizzas:new_order' %}" method="post"&gt;
+        {% csrf_token %}
+        {{ form.as_p }}
+       &lt;button name="submit"&gt;Zamów&lt;/button&gt;
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Powiedzmy że zamówiliśmy pizzę, ale w pizzerii skończył się jeden jej 
+      składnik. Kelnerka po kontakcie telefonicznym z klientem doszła do 
+      porozumienia i klient wybrał inną pizzę. Jednak w systemie nie ma 
+      możliwości zmiany zamówienia. Utworzymy ją. Do tego celu potrzebujemy 
+      dodatkowego widoku, mapowania, szablonu oraz odnośnika do edycji 
+      zamówienia w tabeli z zamówieniami. Edycje danych wpisywanych za pomocą 
+      formularza tworzy się bardzo szybko ponieważ wystarczy skopiować widok 
+      oraz szablon. W widoku dodać kilka rzeczy, w szablonie zmieć dwie rzecz 
+      oraz dodać jedną. Poniżej znajduje się kod widoku, najważniejszy w tym 
+      przedsięwzięciu.
+               </p>
+<pre class="code-block">
+def edit_order(request, order_id):
+
+    from .models import Order
+
+    order = Order.objects.get(id=order_id)
+
+    if request.method != 'POST':
+        form = NewOrder(instance=order)
+    else:
+        form = NewOrder(instance=order, data=request.POST)
+        if form.is_valid():
+            form.save()
+            return redirect('pizzas:edit_ok')
+    context = {'form': form, 'order': order}
+    return render(request, 'pizzas/edit_order.html', context)
+</pre>
+               <p>
+                       Zatem po kolei żeby było wiadomo jakie zamówienie mamy zmienić 
+      potrzebujemy jego identyfikatora, <em>id</em> z tabeli w bazie danych. 
+      Potrzebne nam <em>id</em> będzie przekazywane w żądaniu <em>GET</em>, 
+      przez kliknięcie w łącze na stronie z zamówieniami. Na początku naszego 
+      widoku importujemy model <code class="code-inline">Order</code>, aby 
+      uzyskać dostęp do egzemplarzy tego modelu w bazie. Za pomocą zapytania 
+      <code class="code-inline">Order.objects.get(id=order_id)</code>, 
+      pobraliśmy rekord zamówienia do zmiennej 
+      <code class="code-inline">order</code>. Następnie wykonuje się klasyczna
+      obsługa formularza z tą jednak różnicą, że kiedy tworzone są egzemplarze 
+      formularza to przekazywany jest argument 
+      <code class="code-inline">instance</code>, któremu nadawana jest wartość
+      naszego zapytania, ustawienie argumentu <em>instance</em> powoduje 
+      wypełnienie pół formularza danymi z zapytania</strong>, 
+      strona <em>edit_ok</em> zawiera jeden akapit z informacją że zapisano 
+      zmiany w zamówieniu.
+                       W zmiennej <code class="code-inline">context</code> została dodana 
+      wartość obiektu <code class="code-inline">order</code> pod kluczem 
+      <code class="code-inline">order</code>. Jest to niezbędne kiedy zmieniamy
+      rekordy, ponieważ w atrybucie <code class="code-inline">action</code> 
+      formularza musimy podać <em>id</em> zmienianego rekordu, ponieważ ten 
+      widok będzie wykonywany po raz drugi gdy użytkownik prześle dane. Dlatego
+      też po słowie kluczowym <code class="code-inline">else</code> gdzie 
+      deklarowany jest formularz, podano argument 
+      <code class="code-inline">instance</code>, aby było wiadomo jaki rekord 
+      należy zmienić. Poniżej znajduje się kod szablonu.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+    {% if form.errors %}
+        &lt;p&gt;
+            Zmiana zamówienia nie powiodła się. Spróbuj ponownie
+        &lt;/p&gt;
+    {% endif %}
+
+    &lt;form action="{% url 'pizzas:edit_order' order.id %}" method="post"&gt;
+        {% csrf_token %}
+        {{ form.as_p }}
+        &lt;button name="submit"&t;Zapisz zmiany&lt;/button&gt;
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Tutaj zmieniono atrybut <code class="code-inline">action</code> na 
+      <code class="code-inline">edit_order</code>, dodano 
+      <code class="code -inline">order.id</code> oraz zmieniono treść 
+      przycisku. Poniżej znajduje się zawartość pliku <em>pizzas/urls.py</em> 
+      z uwzględnieniem nowego mapowania oraz zmieniony kod szablonu 
+      <em>pizzas/orders_view.html</em>.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Plik pizzas/urls.py</span>
+               </p>
+<pre class="code-block">
+from django.urls import path
+
+from . import views
+
+app_name='pizzas'
+urlpatterns = [
+    path('', views.index, name='index'),
+    path('menu', views.menu, name='menu'),
+    path('pizza/&lt;int:pizza_id&gt;', views.pizza_site, name='pizza_site'),
+    path('orders/', views.orders_view, name="orders"),
+    path('new_order/', views.new_order, name="new_order"),
+    path('edit_order/&lt;int:order_id&gt;', views.edit_order, name='edit_order')
+]
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Plik pizzas/templates/pizzas/orders_view.html</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+&lt;table border="1"&gt;
+    &lt;thead&gt;
+        &lt;tr&gt;
+            &lt;th&gt;Numer zamówienia&lt;/th&gt;
+            &lt;th&gt;Pizza&lt;/th&gt;
+            &lt;th&gt;Wielkość&lt;/th&gt;
+            &lt;th&gt;Sos_1&lt;/th&gt;
+            &lt;th&gt;Sos_2&lt;/th&gt;
+            &lt;th&gt;Dostawa&lt;/th&gt;
+            &lt;th&gt;&gt;/th&gt;
+        &lt;/tr&gt;
+    &lt;/thead&gt;
+    &lt;tbody&gt;
+    {% for order in orders %}
+        &lt;tr&gt;
+            &lt;td&gt;{{ order.id }}&lt;/td&gt;
+            &lt;td&gt;{{ order.pizza.name }}&gt;/td&gt;
+            &lt;td&gt;{{ order.size }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce1 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce2 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.deliver }}&lt;/td&gt;
+            &lt;td&gt;&lt;a href="{% url 'pizzas:edit_order' order.id %}"&gt;Zmień&lt;/a&gt;&lt;/td&gt;
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;&lt;td colspan="7"&gt;Brak zamówień&lt;/td&gt;&lt;/tr&gt;
+    {% endfor %}
+    &lt;tbody&gt;
+&lt;/table&gt;
+
+{% endblock content %}
+</pre>
+               <h2 id="2.6.securinganapplication">2.6. Zabezpieczenie aplikacji</h2>
+               <p>
+                       Kolejną rzeczą jak należy zrobić to zabezpieczyć pewne strony przed 
+      niepowołanym dostępem. W zależności od tego jakie restrykcje chcemy 
+      wprowadzić możemy użyć konkretnych metod. Pierwszą z nich jest wymaganie
+      logowania, jeśli nie zalogowani przejedziemy pod adres 
+      <em>http://localhost:8000/new_order</em>. Zostanie nam przedstawiona 
+      strona do składania zamówień. W ten sposób osoba złośliwa może po 
+      nabijać zamówień, zostawiając jedynie ślad w logach o ile uruchomiliśmy
+      serwer wraz z opcją zapisywania dziennika. Django daje nam banalny sposób
+      na zabezpieczenie się przed tego typu sytuacjami. 
+      W pliku <em>views.py</em> w aplikacji <em>pizzas</em> importujemy 
+      <strong>dekorator</strong> (dodatek/modyfikator do funkcji) o nazwie 
+      <code class="code-inline">login_required</code>.
+               </p>
+<pre class="code-block">
+from django.contrib.auth.decorators import login_required
+</pre>
+               <p>
+                       Dekorator <code class="code-inline">login_required</code> sprawdzi czy 
+      jesteśmy zalogowani, kiedy będziemy wywoływać funkcje widoku. Dekoratora
+      używamy w pomocą znaku <code class="code-inline">@</code> oraz nazwy 
+      dekoratora tuż nad definicją widoku</strong>, tak jak przedstawiono to 
+      poniżej:
+               </p>
+<pre class="code-block">
+@login_required
+def orders_view(request):
+    ...
+
+@login_required
+def new_order(request):
+    ...
+
+@login_required
+def edit_order(request, order_id):
+</pre>
+               <p>
+                       Aby działało to poprawnie w ustawieniach projektu pizzeria/settings.py 
+      musimy zdefiniować zmienną LOGIN_URL na samym dole pliku, jeśli tego nie
+      zrobimy niezalogowani użytkownicy, przechodzący pod zabezpieczoną przez 
+      dekorator stronę otrzymają stronę błędu, że nie znaleziono strony. 
+      Wartość zmiennej <code class="code-inline">LOGIN_URL</code> zapisujemy w 
+      klasycznym odniesieniu do strony, tak jak w przypadku znaczników szablonu 
+      URL, czy funkcji <em>redirect</em> 
+     (<em>nazwa_aplikacji:nazwa_mapowania_URL</em>).
+               </p>
+<pre class="code-block">
+LOGIN_URL = 'users:login'
+</pre>
+               <p>
+                       Teraz kiedy nie zalogowani, spróbujemy na przykład podejrzeć zamówienia. 
+      Zostaniemy przekierowani na stronę logowania, identycznie będzie z 
+      wywołaniem widoku <em>new_order</em>, czyli złożeniem nowego zamówienia
+      oraz z jego edycją.
+               </p>
+               <p>
+                       Drugi sposób w jaki możemy zabezpieczyć naszą aplikacje, jest 
+      wyświetlenie użytkownikom rzeczy stricte tyczących się ich. Powiedzmy że
+      użytkownik powinien mieć wgląd w swoje zamówienia. Ta zmiana będzie 
+      wymagać trochę pracy, ale myślę że jest ciekawy do opisania przypadek,
+      ponieważ musimy zmienić już wdrożony model danych. Dodać jedną kolumnę do
+      tabeli, to nie jest problem jeśli tabela była by pusta, ale co jeśli dane
+      do tej tabeli już zostały wprowadzone dane. Zaczniemy od zaimportowania
+      modelu User w pliku <em>pizzas/models.py</em>.
+               </p>
+<pre class="code-block">
+from django.contrib.auth.models import User
+</pre>
+               <p>
+                       Następnie dodamy do naszego modelu <code class="code-inline">Order</code>
+      nowe kolumnę o nazwie <code class="code-inline">owner</code>, która 
+      będzie kluczem obcym w modelu <em>User</em> dostarczanym przez Django.
+               </p>
+<pre class="code-block">
+class Order(models.Model):
+
+    pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)
+    size = models.CharField(max_length=10)
+    sauce1 = models.CharField(max_length=10)
+    sauce2 = models.CharField(max_length=10)
+    deliver = models.CharField(max_length=10)
+    date_order = models.DateTimeField(auto_now_add=True)
+    owner = models.ForeignKey(User, on_delete=models.CASCADE)
+
+    def __str__(self):
+        return f"{self.pizza.name} - {self.size},{self.sauce1},\
+        {self.sauce2},{self.deliver} - {self.date_order}"
+</pre>
+               <p>
+                       Aby wdrożyć nasze zmiany musimy wykonać migrację.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py makemigrations pizzas
+</pre>
+               <p>
+                       Podczas wykonywania tego polecenia Python wyświetli informacje o tym, że
+      próbujemy dodać nie-zerowe pole do modelu <em>Order</em> bez wartości 
+      domyślnej i nie jest to możliwe, ponieważ zmiany muszą być również 
+      uwzględnione na istniejących już rekordach. Python daje nam do wyboru 
+      dwie opcje, albo podanie teraz wartość jaka zostanie przypisana w polu 
+      <em>owner</em> dla istniejących już rekordów, lub porzucenie migracji i 
+      dodanie wartości domyślnej w deklaracji pola w klasie modelu.
+               </p>
+<pre class="code-block">
+You are trying to add a non-nullable field 'owner' to order without a default; 
+we can't do that (the database needs something to populate existing rows).
+Please select a fix:
+ 1) Provide a one-off default now (will be set on all existing rows with a null
+    value for this column)
+ 2) Quit, and let me add a default in models.py
+Select an option: 2
+</pre>
+               <p>
+                       Teraz wybierzemy opcje nr. 2. Jeśli podczas testowania rejestracji 
+      stworzyliśmy użytkownika to możemy mu nadać wszystkie zamówienia, 
+      <em>models.ForeignKey()</em> zawiera identyfikatory (<em>id</em>) z 
+      zewnętrznej tabeli</strong>. Aby dowiedzieć się jakie <em>id</em> mają 
+      nasi użytkownicy skorzystamy z pomocy powłoki Django.
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ python manage.py shell
+</pre>
+<pre class="code-block">
+&gt;&gt;&gt; from django.contrib.auth.models import User
+&gt;&gt;&gt; users = User.objects.all()
+&gt;&gt;&gt; for user in users:
+...     print(f"{user.id} {user.username}")
+...
+1 pizza_admin
+2 xf0r3m
+</pre>
+               <p>
+                       Na początku importujemy nasz model, następnie pobieramy wszystkie 
+      egzemplarze tego modelu aby poprzez iteracje wpisać <em>id</em> oraz 
+      nazwę użytkownika. Teraz wiemy, że nasz stworzony w celach testowych 
+      użytkownik ma <em>id</em> = 2.  Oczywiście moglibyśmy to pominąć i 
+      domyślić się że musi mieć <em>id</em> = 2. Jednak chciałem przedstawić 
+      tutaj sposób w jaki możemy to sprawdzić aby mieć pewność. Również możemy
+      wyszukać użytkownika za pomocą lekko zmodyfikowanego zapytania.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt; user = User.objects.get(username='xf0r3m')
+&gt;&gt;&gt; user.id
+2
+</pre>
+               <p>
+                       Teraz kiedy znamy już <em>id</em> możemy ponownie wydać polecenie 
+      migracji. Python znów nas zapyta o to samo, jednak teraz wybieramy opcje
+      nr. 1 a następnie po znaku zachęty <em>&gt;&gt;&gt;</em> wpiszemy 
+      <em>id</em> naszego użytkownika.
+               </p>
+<pre class="code-block">
+You are trying to add a non-nullable field 'owner' to order without a default;
+we can't do that (the database needs something to populate existing rows).
+Please select a fix:
+ 1) Provide a one-off default now (will be set on all existing rows
+       with a null value for this column)
+ 2) Quit, and let me add a default in models.py
+Select an option: 1
+Please enter the default value now, as valid Python
+The datetime and django.utils.timezone modules are available,
+so you can do e.g. timezone.now
+Type 'exit' to exit this prompt
+&gt;&gt;&gt; 2
+</pre>
+               <p>
+                       Teraz zmodyfikujemy widok <code class="code-inline">order_views</code>, 
+      tak aby wyświetlał zamówienia wszystkich użytkowników, jeśli zalogowanym
+      użytkownikiem jest <code class="code-inline">pizza_admin</code>, czyli 
+      nasz superużytkownik. A jeśli zalogowany jest kto inny, to widzi on 
+      tylko swoje zamówienia.
+               </p>
+<pre class="code-block">
+@login_required
+def orders_view(request):
+
+    from pizzas.models import Order
+
+    if request.user.username != 'pizza_admin':
+        orders = Order.objects.filter(owner=request.user).order_by('-date_order')
+    else:
+        orders = Order.objects.order_by('-date_order')
+
+
+    context = {'orders': orders}
+    return render(request, 'pizzas/orders_view.html', context)
+</pre>
+               <p>
+                       Ważną rzeczą użytą w tym przypadku jest to, iż egzemplarz klasy 
+      <em>User</em> zalogowanego użytkownika jest przechowywany w właściwości 
+      <code class="code-inline">user</code> obiektu 
+      <code class="code-inline">request</code></strong>. Jednak chcąc 
+      przyrównać nazwy użytkowników musimy użyć właściwości <em>username</em>. 
+      Ze względu na iż zmodyfikowaliśmy model <em>Order</em> teraz nie możliwe
+      jest dodanie nowego zamówienia bez zmian uwzględniających właściciela. 
+      Poniżej znajduje się kod widoku new_order uwzględniający właściciela.
+               </p>
+<pre class="code-block">
+@login_required
+def new_order(request):
+
+    if request.method != 'POST':
+        form = NewOrder()
+    else:
+        form = NewOrder(data=request.POST)
+        if form.is_valid():
+            new_order = form.save(commit=False)
+            new_order.owner = request.user
+            new_order.save()
+            return redirect('pizzas:index')
+    context = {'form': form}
+    return render(request, 'pizzas/new_order.html', context)
+</pre>
+               <p>
+                       Z założeń wynika iż użytkownik raz przypisany do zamówienia jest 
+      nietykalny, nie musimy w ogóle zmieniać kodu widoku <em>edit_order</em>. 
+      Wprowadziłem lekką zmianę do szablonu <em>orders_view.html</em> aby 
+      wyświetlał datę, według narzuconego formatu.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+&lt;table border="1"&gt;
+    &lt;thead&gt;
+        &lt;tr&gt;
+            &lt;th&gt;Numer zamówienia&lt;/th&gt;
+            &lt;th&gt;Pizza&lt;/th&gt;
+            &lt;th&gt;Wielkość&lt;/th&gt;
+            &lt;th&gt;Sos_1&lt;/th&gt;
+            &lt;th&gt;Sos_2&lt;/th&t;
+            &lt;th&gt;Dostawa&lt;/th&gt;
+            &lt;th&gt;Data zamówienia&lt;/th&gt;
+            &lt;th&gt;&lt;/th&gt;
+        &lt;/tr&gt;
+    &lt;/thead&gt;
+    &lt;tbody&gt;
+    {% for order in orders %}
+        &lt;tr&gt;
+            &lt;td&gt;{{ order.id }}&lt;/td&gt;
+           &lt;td&gt;{{ order.pizza.name }}&lt;/td&gt;
+            &lt;td&gt;{{ order.size }}&lt;/td&gt;
+           &lt;td&gt;{{ order.sauce1 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce2 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.deliver }}&lt;/td&gt;
+            &lt;td&gt;{{ order.date_order|date:'d M Y H:i'  }}&lt;/td&gt;
+           &lt;td&gt;&lt;a href="{% url 'pizzas:edit_order' order.id %}"&gt;Zmień&lt;/a&gt;&lt;/td&gt;
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;&lt;td colspan="7"&gt;Brak zamówień&lt;/td&gt;&lt;/tr&gt;
+    {% endfor %}
+    &lt;/tbody&gt;
+&lt;/table&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Pionowa kreska <code class="code-inline">|</code> oraz 
+      <code class="code-inline">date:'d M Y H:i'</code> są to filtry 
+      znaczników szablonu, w tym przypadku jest filtr daty, który wyświetla 
+      nam date w formacje 01 Jan 1970 00:00. </strong>
+               </p>
+               <p>
+                       Aby upewnić się ze wszystko działa utwórzmy trzeciego użytkownika i 
+      złóżmy zamówienie. Użytkownicy powinni widzieć tylko swoje zamówienia, 
+      z kolei superużytkownik powinien widzieć je wszystkie. Ostatnią rzeczą 
+      jaka pozostała do zabezpieczenia, jest wyłączność na edycje zamówień 
+      przez superużytkownika. Zwykli użytkownicy nie powinni mieć dostępu do 
+      zmiany zamówienia. Zmian musimy dokonać w dwóch miejscach: w szablonie 
+      oraz w widoku <em>edit_order</em>. Najpierw rozpoczniemy od szablonu. 
+      Poniżej zmieniony kod szablonu
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block content %}
+
+&lt;table border="1"&gt;
+    &lt;thead&gt;
+        &lt;tr&gt;
+            &lt;th&gt;Numer zamówienia&lt;/th&gt;
+            &lt;th&gt;Pizza&lt;/th&gt;
+            &lt;th&gt;Wielkość&lt;/th&gt;
+            &lt;th&gt;Sos_1&lt;/th&gt;
+            &lt;th&gt;Sos_2&lt;/th&gt;
+            &lt;th&gt;Dostawa&lt;/th&gt;
+            &lt;th&gt;Data zamówienia&lt;/th&gt;
+        {% if user.username == 'pizza_admin' %}
+            &lt;th&gt;&lt;/th&gt;
+        {% endif %}
+        &lt;/tr&gt;
+    &lt;/thead&gt;
+    &lt;tbody&gt;
+    {% for order in orders %}
+        &lt;tr&gt;
+            &lt;td&gt;{{ order.id }}&lt;/td&lt;
+            &lt;td&gt;{{ order.pizza.name }}&lt;/td&gt;
+            &lt;td&gt;{{ order.size }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce1 }}&lt;/td&lt;
+            &lt;td&gt;{{ order.sauce2 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.deliver }}&lt;/td&gt;
+            &lt;td&gt;{{ order.date_order|date:'d M Y H:i'  }}&lt;/td&gt;
+            {% if user.username == 'pizza_admin' %}
+                &lt;td&gt;&lt;a href="{% url 'pizzas:edit_order' order.id %}"&gt;Zmień&lt;/a&gt;&lt;/td&gt;
+            {% endif %}
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;&lt;td colspan="7"&gt;Brak zamówień&lt;/td&gt;&lt;/tr&gt;
+    {% endfor %}
+    &lt;/tbody&gt;
+&lt;/table&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Dodaliśmy dwa znaczniki warunkowe szablonu, sprawdzające czy 
+      uwierzytelniony użytkownik to 
+      <code class="code-inline">pizza_admin</code>. Teraz zajmiemy się kodem 
+      widoku, na początek importujemy dwie rzeczy z modułu 
+      <code class="code-inline">django.http</code>.
+               </p>
+<pre class="code-block">
+from django.http import HttpResponseRedirect, Http404
+</pre>
+               <p>
+                       Następnie w kodzie widoku dopisujemy warunek, który przyrówna 
+      <code class="code-inline">request.user.username</code> do ciągu 
+      <code class="code-inline">pizza_admin</code> jeśli się te wartości nie 
+      będą się zgadzać wtedy zostanie zgłoszony wyjątek 
+      <code class="code-inline">Http404</code></strong>. Poniżej znajduje się 
+      kod zmodyfikowanej funkcji widoku.
+               </p>
+<pre class="code-block">
+@login_required
+def edit_order(request, order_id):
+
+    if request.user.username != 'pizza_admin':
+        raise Http404
+
+    from .models import Order
+
+    order = Order.objects.get(id=order_id)
+
+    if request.method != 'POST':
+        form = NewOrder(instance=order)
+    else:
+        form = NewOrder(instance=order, data=request.POST)
+        if form.is_valid():
+            form.save()
+            return redirect('pizzas:index')
+    context = {'form': form, 'order': order}
+    return render(request, 'pizzas/edit_order.html', context)
+</pre>
+               <h2 id="2.7.usingbootstrap4fordjango">2.7. Nadawanie stylu aplikacji - Bootstrap 4</h2>
+               <p>
+                       Przed nami ostatni rozdział podróży przez Pythona oraz przez Django. 
+      Zostały jeszcze dwa zagadnienia, które należało by omówić w kontekście 
+      Django. Nadawanie stylu oraz oraz wdrożenie naszej aplikacji na 
+      platformie sieciowej Heroku</strong>. Zaczniemy od nadawania stylu, aby 
+      nasza aplikacja zaczęła wyglądać bardziej profesjonalnie za pomocą 
+      znanego zestawu narzędzi jakim jest <strong>Bootstrap 4</strong>. Dla 
+      naszej aplikacji skorzystamy z prostego motywu. Na początku instalujemy 
+      dodatek zawierający Bootstrap przygotowany do współpracy z Django. W 
+      aktywnym środowisku wirtualnym wydajemy polecenie:
+               </p>
+<pre class="code-block">
+(project_env) xf0r3m@macbook:python/django$ pip install django-bootstrap4
+</pre>
+               <p>
+                       Po zainstalowaniu Bootstrap, dopisujemy go zainstalowanych aplikacji w 
+      naszym projekcie. Plik <em>pizzeria/settings.py</em>, zmienna 
+      <code class="code-inline">INSTALLED_APPS</code>.
+               </p>
+<pre class="code-block">
+INSTALLED_APPS = &#91;
+    'users',
+    'pizzas',
+    'bootstrap4',
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+]
+</pre>
+               <p>
+                       Teraz kiedy nasz Bootstrap jest już zainstalowany. Możemy podmienić kod z
+      szablonu <em>base.html</em> na ten poniżej.
+               </p>
+               <p>
+                       Najprościej rzecz ujmując, ten szablony stworzy bazową stronę naszej 
+      aplikacji. Na górze strony zostanie umieszczony responsywny pasek 
+      nawigacyjny, zawierający wszystkie nasze dotychczasowe odnośniki oraz 
+      nazwę aplikacji. Responsywność wygląda w ten sposób że jeśli strona 
+      zostanie wyświetlona na wąskim ekranie, odnośniki zostaną schowane w 
+      wysuwanym na dół menu. A na pasku zostanie wyświetlona nazwa aplikacji 
+      czy już w tym przypadku projektu oraz przycisk aktywujący wysunięcie 
+      menu. Poniżej znajduje się kod szablonu bazowego.
+               </p>
+<pre class="code-block">
+{% load bootstrap4 %}
+
+&lt;!doctype html&gt;
+&lt;html lang="pl"&gt;
+    &lt;head&gt;
+        &lt;meta charset="utf-8"&gt;
+        &lt;meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"&gt;
+        &lt;title&gt;Pizzas&gt;/title&lt;
+        {% bootstrap_css %}
+        {% bootstrap_javascript jquery='full' %}
+    &lt;/head&gt;
+    &lt;body&lt;
+        &lt;nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border"&gt;
+            &lt;a class="navbar-brand" href="{% url 'pizzas:index' %}"&lt;
+                Dolce&amp;Gusto
+            &lt;/a&gt;
+            &lt;button class="navbar-toggler" type="button" data-toggle="collapse" 
+            data-target="#navbarCollapse" aria-controls="navbarCollapse" 
+            aria-expanded="false" aria-label="Toggle navigation"&gt;
+                &lt;span class="navbar-toggler-icon"&gt;&lt;/span&gt;
+            &lt;/button&gt;
+            &lt;div class="collapse navbar-collapse" id="navbarCollapse"&gt;
+                &lt;ul class="navbar-nav ml-auto"&gt;
+                    {% if user.is_authenticated %}
+                        &lt;li class="nav-item"&lt;
+                            &lt;span class="navbar-text"&gt;
+                                Witaj, {{ user.username }}
+                            &lt;/span&gt;
+                        &lt;/li&gt;
+                        {% if user.username == 'pizza_admin' %}
+                            &lt;li class="nav-item"&gt;
+                                &lt;a class="nav-link" href="{% url 'pizzas:orders' %}"&gt;
+                                    Zamówienia
+                                &lt;/a&gt;
+                            &lt;/li&gt;
+                        {% else %}
+                            &lt;li class="nav-item"&gt;
+                                &lt;a class="nav-link" href="{% url 'pizzas:new_order' %}"&gt;
+                                    Złóż zamówienie
+                                &lt;/a&gt;
+                            &lt;/li&gt;
+                            &lt;li class="nav-item"&gt;
+                                &lt;a class="nav-link" href="{% url 'pizzas:orders' %}"&gt;
+                                    Moje zamówienia
+                                &lt;/a&gt;
+                            &lt;/li&gt;
+                        {% endif %}
+                        &lt;li class="nav-item"&gt;
+                            &lt;a class="nav-link" href="{% url 'users:logout' %}"&gt;
+                                Wyloguj
+                            &lt;/a&gt;
+                        &lt;li&gt;
+                    {% else %}
+                        &lt;li class="nav-item"&gt;
+                            &lt;a class="nav-link" href="{% url 'users:register' %}"&gt;
+                                Rejestruj
+                            &lt;/a&gt;
+                        &lt;/li&gt;
+                        &lt;li class="nav-item"&gt;
+                            &lt;a class="nav-link" href="{% url 'users:login' %}"&gt;
+                                Zaloguj
+                            &lt;/a&lt;
+                        &lt;/li&gt;
+                    {% endif %}
+                &lt;/ul&gt;
+            &lt;/div&gt;
+        &lt;/nav&gt;
+        &lt;main role="main" class="container"&gt;
+            &lt;div class="pb-2 mb-2 border-bottom"&lt;
+                {% block page_header %} {% endblock page_header %}
+            &lt;/div&gt;
+            &lt;div&gt;
+                {% block content %}{% endblock content %}
+            &lt;/div&gt;
+        &lt;/main&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
+</pre>
+               <p>
+                       W tym szablonie na samy początku ładujemy Bootstrap 4 aby
+      mieć możliwość skorzystania ze znaczników szablonu przygotowanych przez 
+      tę aplikację. Następnie tworzona jest podstawowa struktura strony HTML, 
+      z zaznaczeniem użycia języka polskiego w atrybucie 
+      <code class="code-inline">lang</code> w znaczniku otwierającym HTML, w 
+      nagłówku strony - pomiędzy znacznikami 
+      <code class="code-inline">head</code>, przekazywane są informacje 
+      odpowiedzialne za kodowanie strony <code class="code-inline">&lt;meta 
+      charset="utf-8"&gt;</code>, responsywność 
+      <code class="code-inline">&lt;meta name="viewport" ...&gt;</code>, 
+      ustawienie tekstu wyświetlanego w tytule karty lub/i okna przeglądarki 
+      <code class="code-inline">&lt;title&gt;&lt;/title&gt;</code>.
+                       Następnie mamy dwa znaczniku szablonu Django, w których to ładowane są 
+      pliki arkusza stylów CSS oraz biblioteki JavaScript ze wskazaniem o 
+      użyciu pełnej biblioteki, a nie wersji odchudzonej (nie zawierającej 
+      obsługi AJAX-a oraz efektów - takich rzeczy jak np. slideToggle).
+    </p>
+    <p>
+                       W ciele strony - między znacznikami 
+      <code class="code-inline">&lt;body&gt;</code> umieszczamy nasz pasek 
+      nawigacyjny <code class="code-inline">&lt;nav ...&gt;</code>. Na pasku 
+      nawigacyjnym umieszczamy odnośnik do strony głównej zatytułowany nazwą 
+      projektu w Django, przycisk widoczny jedynie na małych ekranach, 
+      zwężonych oknach przeglądarki lub dużych zoomach, powodujący wyjechanie 
+      menu ukrytego w wyżej wymienionych sytuacjach zaraz pod przyciskiem 
+      znajduje się  znajduje się sekcja 
+      <code class="code-inline">&lt;div&gt;</code> z menu przedstawionym tutaj
+      za pomocą listy nieuporządkowanej. Wewnątrz listy znajdują się znaczniki
+      szablonu oraz odnośniki znane nam z poprzedniej wersji pliku 
+      <em>base.html</em>. Pod paskiem nawigacji znajduje się element główny 
+      naszej strony, zwierający dwa znaczniki sekcji.
+    </p>
+    <p>
+                       Pierwszy z nich zawiera, parę znaczników szablonu 
+      <code class="code-inline">block page_header</code>, dzięki temu 
+      zdefiniowany na innej stronie znaczniki <em>block page_header</em> 
+      zostanie wstawiony w to miejesce, nieco enigmatyczne wydają się użyte w 
+      tej sekcji klasy, pierwszy z nich <code class="code-inline">pb-2</code> 
+      oznacza wewnętrzny odstęp dolny treści elementu krawędzi elementu 
+      (<em>padding-bottom</em>) o wielkości 
+      <code class="code-inline">$spacer</code> * 0,5, gdzie <em>$spacer</em> 
+      (zmienna SASS - język pre procesora kompilowany do CSS) przyjmuje wartość
+      16px. klasa <em>pb</em> istnieje w 5 wariantach. od * 0,25 od * 3. 
+      Identycznie jest z drugą klasą, tylko że zamiast dopełnienia (odstęp 
+      pomiędzy treścią elementu a jego krawędzią), mamy margines czyli odstęp 
+      między krawędzią elementu a krawędzią następnego elementu, w naszym 
+      przypadku mamy margines dolny, ponieważ po literce 
+      <code class="code-inline">m</code> występuje literka 
+      <code class="code-inline">b</code> następnie po myślniku mamy warjant, 
+      klasa border-bottom powoduje nałożenie stylów zdefiniowanych w tej 
+      klasie na dolną krawędź elementów.
+                       Nie ma co rozwodzić się na wszystkimi użytymi tym przykładzie klasami. 
+      Ponieważ ten kod w 90% został zaczerpnięty z przykładów znajdujących 
+      się po tym adresem 
+      <a href="https://getbootstrap.com/docs/4.5/examples/">https://getbootstrap.com/docs/4.5/examples/</a> 
+      jedne co zostało zmienione to podział elementu 
+      <code class="code-inline">main</code> na dwie sekcje div i nadanie 
+      większego odstępu pierwszej sekcji od drugie wyżej wymienionymi stylami.
+      Teraz nadamy styl stronie głównej.
+               </p>
+               <p>
+                       Poniżej prezentuje się kod szablonu strony głównej, w przeciwieństwie do
+      poprzedniego nie jest tak obszerny.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block page_header %}
+&lt;div class="jumbotron"&gt;
+    &lt;div class="container"&gt;
+      &lt;h1 class="display-3"&gt;Dolce&amp;Gusto&lt;/h1&gt;
+      &lt;p&gt;Pyszna pizza tylko na dowóz. Zamów już dziś.&lt;/p&gt;
+      &lt;p&gt;&gt;a class="btn btn-primary btn-lg" href="{% url 'users:register' %}" role="button"&lt;Zarejestruj się &amp;raquo;&lt;/a&gt;&lt;/p&gt;
+    &lt;/div&gt;
+&lt;/div&gt;
+{% endblock page_header %}
+</pre>
+               <p>
+                       Tutaj zostaje wykorzystany blok <code class="code-inline">page_header</code> 
+      aby umieścić element nazwany przez Bootstap Jumbotronem. Jest to 
+      wyróżniający się duży prostokąt, przeważnie z dużym tytułem, drobnym 
+      opisem oraz łączem w postaci przycisku. "&amp;raquo;" to encja HTML 
+      (encje zawierają znaki specjalnej, cięzko jest wpisać za pomocą 
+      klawiatury) przedstawiąca dwa połączone znaki większości lub jak kto woli
+      dwa prawe ostre nawiasty "»" . Przycisk kieruje na formularz rejestracji,
+      teraz sobie obstylujemy formularze. Styl dla formularzy rejestracji 
+      będzie taki podstawowy, a styl dla formlarza logowania weźmiemy z 
+      przykładów na stronie Bootstrap.
+               </p>
+               <p>
+                       Poniżej znajduje się kod formularza rejestracji, jest to klasyczny 
+      książkowy przykład nadawania formularzom w Django stylów Bootstrap 4.
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+{% load bootstrap4 %}
+
+{% block page_header %}
+    &lt;h2&gt;Rejestracja&lt;/h2&gt;
+{% endblock page_header %}
+
+{% block content %}
+
+    &lt;form action="{% url 'users:register' %}" method="post"&gt;
+
+        {% csrf_token %}
+        {% bootstrap_form form %}
+        {% buttons %}
+            &lt;button name="submit" class="btn btn-primary"&gt;Zarejestruj się&lt;/button&gt;
+        {% endbuttons %}
+
+        &lt;input type="hidden" name="next" value="{% url 'pizzas:index' %}" /&gt;
+    &lt;/form&lt;
+
+{% endblock content %}
+</pre>
+    <p>
+           Ten formularz będzie nieco inny, dodamy obraz w bloku 
+      <code class="code-inline">page_header</code>. Musimy dodać również 
+      dostosowane dlatego tego formularza style. W tym przykładzie warto 
+      zwrócić uwagę na to że nie wykorzystaliśmy formularza przygotowanego 
+      przez Django, skorzystaliśmy jedynie z nazw pól odpowiednich dla 
+      formularza i przesłaliśmy nasz spersonalizowany formularz. Kod jest nieco
+      obszerny.
+    </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+{% block content %}
+&lt;style&gt;
+.form-signin {
+  width: 100%;
+  max-width: 330px;
+  padding: 15px;
+  margin: auto;
+}
+.form-signin .checkbox {
+  font-weight: 400;
+}
+.form-signin .form-control {
+  position: relative;
+  box-sizing: border-box;
+  height: auto;
+  padding: 10px;
+  font-size: 16px;
+}
+.form-signin .form-control:focus {
+  z-index: 2;
+}
+.form-signin input[type="email"] {
+  margin-bottom: -1px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.form-signin input[type="password"] {
+  margin-bottom: 10px;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+&lt;/style&gt;
+
+    {% if form.errors %}
+    &lt;div class="alert alert-danger alert-dismissible fade show" role="alert"&gt;
+        Niepoprawny login lub hasło. Spróbuj ponownie.
+        &lt;button type="button" class="close" data-dismiss="alert" aria-label="Close"&gt;
+          &lt;span aria-hidden="true"&gt;&amp;times;&lt;/span&gt;
+        &lt;/button&lt;
+      &lt;/div&gt;
+    {% endif %}
+
+    &lt;form class="form-signin" action="{% url 'users:login' %}" method="post"&gt;
+        {% csrf_token %}
+        &lt;h1 class="h3 mb-3 font-weight-normal text-center"&gt;Zaloguj się&lt;/h1&gt;
+        &lt;label for="username" class="sr-only"&gt;Nazwa użytkownika&lt;/label&gt;
+        &lt;input type="text" id="username" name="{{form.username.html_name}}" 
+        class="form-control" placeholder="Nazwa użytkownika" required autofocus&gt;
+        &lt;label for="form.password" class="sr-only"&gt;Hasło&lt;/label&gt;
+        &lt;input type="password" id="password" name="{{form.password.html_name}}" 
+        class="form-control" placeholder="Hasło" required&gt;
+        &lt;button class="btn btn-lg btn-primary btn-block" 
+        type="submit"&gt;Zaloguj&lt;/button&gt;
+        &lt;p class="mt-5 mb-3 text-muted text-center"&gt;&amp;copy; 2020&lt;/p&gt;
+        &lt;input type="hidden" name="next" value="{% url 'pizzas:index' %}" /&gt;
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Z racji tego iż nasz formularz jest dostosowywany. Musieliśmy też dodać 
+      również własny komunikat o tym że logowanie się nie powiodło. Alert z 
+      możliwością zamknięcia znajduje się w pomiędzy warunkowymi znacznikami 
+      szablonu. Do obstylowania pozostała jeszcze tabelka z zamówieniami, 
+      formularz zamówienia, edycja zamówienia, menu, strona pizzy oraz strona 
+      wylogowania. Poniżej znajdują sią szablony obstylowanych już stron.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Strona podglądu zamówień:</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&lt;
+{% endblock page_header %}
+
+{% block content %}
+
+&lt;table class="table"&gt;
+    &lt;thead&gt;
+        &lt;tr&gt;
+            &lt;th scope="col"&gt;Nr zamówienia&lt;/th&gt;
+            &lt;th scope="col"&gt;Pizza&lt;/th&gt;
+            &lt;th scope="col"&gt;Wielkość&lt;/th;&gt;
+            &lt;th scope="col"&gt;Sos_1&lt;/th&gt;
+            &lt;th scope="col"&gt;Sos_2&lt;/th&gt;
+            &lt;th scope="col"&gt;Dostawa&lt;/th&gt;
+            &lt;th scope="col"&gt;Data zamówienia&lt;/th&gt;
+        {% if user.username == 'pizza_admin' %}
+            &lt;th&gt;&lt;/th&gt;
+        {% endif %}
+        &lt;/tr&gt;
+    &lt;/thead&gt;
+    &lt;tbody&gt;
+    {% for order in orders %}
+        &lt;tr&gt;
+            &lt;th scope="row"&gt;{{ order.id }}&lt;/th&gt;
+            &lt;td&gt;{{ order.pizza.name }}&gt;/td&lt;
+            &lt;td&gt;{{ order.size }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce1 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.sauce2 }}&lt;/td&gt;
+            &lt;td&gt;{{ order.deliver }}&lt;/td&gt;
+            &lt;td&lt;{{ order.date_order|date:'d M Y H:i'  }}&lt;/td&gt;
+            {% if user.username == 'pizza_admin' %}
+                &lt;td&gt;&lt;a href="{% url 'pizzas:edit_order' order.id %}"&gt;Zmień&lt;/a&gt;&lt;/td&gt;
+            {% endif %}
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;&lt;td colspan="7"&gt;Brak zamówień&lt;/td&gt;&lt;/tr&gt;
+    {% endfor %}
+    &lt;/tbody&gt;
+&lt;/table&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Strona formularza zamówień</span>:
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+{% load bootstrap4 %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+{% block content %}
+
+    &lt;form action="{% url 'pizzas:new_order' %}" method="post"&gt;
+        {% csrf_token %}
+        {% bootstrap_form form %}
+        {% buttons %}
+            &lt;button name="submit" class="btn btn-primary"&gt;Zamów&lt;/button&gt;
+        {% endbuttons %}
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       Warto zaznaczyć że usunięto znacznik warunkowy, który wyświetlał 
+      informacje, o ile zapisanie zmian się nie powiodło, otóż jeśli 
+      wyświetlenie formularza pozostawiamy Bootstrapowi, to on sam wyświetli 
+      komunikat jeśli w formularzu pojawią się błędy.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Strona edycji zamówień:</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+{% load bootstrap4 %}
+
+{% block page_header %}
+    &gt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+
+{% block content %}
+
+    &lt;form action="{% url 'pizzas:edit_order' order.id %}" method="post"&gt;
+        {% csrf_token %}
+        {% bootstrap_form form %}
+        {% buttons %}
+        &lt;button name="submit" class="btn btn-primary"&gt;Zapisz zmiany&lt;/button&gt;
+        {% endbuttons %}
+    &lt;/form&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Strona menu:</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/index.html' %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+{% block content %}
+
+&lt;table class="table"&gt;
+    &lt;thead&lt;
+        &lt;th scope="col"&gt;Pizza&lt;/th&gt;
+        &lt;th scope="col"&gt;Składniki&lt;/th&gt;
+        &lt;th scope="col"&gt;&lt;/th&gt;
+    &lt;/thead&gt;
+    &lt;tbody&gt;
+        {% for pizza in pizzas %}
+        &lt;tr&lt;
+            &lt;th scope="row"&gt;{{ pizza.name }}&lt;/td&gt;
+            &lt;td&gt;{{ pizza.topings }}&lt;/td&gt;
+            &lt;td&gt;&lt;a href="{% url 'pizzas:pizza_site' pizza.id %}"&gt;Wybierz&lt;/a&gt;&lt;/td&gt;
+        &lt;/tr&gt;
+    {% empty %}
+        &lt;tr&gt;Nie ustalono jeszcze menu&lt;/tr&gt;
+    {% endfor %}
+    &lt;/tbody&gt;
+&lt;/table&gt;
+
+
+{% endblock content %}
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Strona pizzy:</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+{% block content %}
+
+&lt;h2&gt;{{ name }}&lt;/h2&gt;
+
+&lt;ul class="list-group list-group-flush"&gt;
+    {% for toping in topings %}
+        &lt;li class="list-group-item"&gt;{{ toping }}&lt;li&gt;
+    {% empty %}
+        &lt;li class="list-group-item"&gt;Dodatki na życzenie&gt;/li&gt;
+    {% endfor %}
+&lt;/ul&gt;
+
+{% endblock content %}
+</pre>
+               <p>
+                       <span style="text-decoration: underline;">Strona wylogowania:</span>
+               </p>
+<pre class="code-block">
+{% extends 'pizzas/base.html' %}
+
+{% block page_header %}
+    &lt;img src="https://i.imgur.com/olxvhk5.jpg" style="width: 100%;" /&gt;
+{% endblock page_header %}
+
+
+{% block content %}
+
+&lt;div class="alert alert-primary" role="alert"&gt;
+    Dziękujemy za skorzystanie z naszej aplikacji.
+  &lt;/div&gt;
+
+
+
+{% endblock content %}
+</pre>
+               <h2 id="2.8.herokuplatform">2.8. Platforma Heroku</h2>
+               <p>
+                       Teraz kiedy mamy obstylowaną naszą aplikacje, możemy wrzucić ją na 
+      <strong>platformę sieciową Heroku</strong>. Wdrożenie danych na platformę
+      Heroku, będzie wymagało trochę zachodu. Na początku sprawdzimy czy w 
+      naszym systemie są dostępne pakiety, które umożliwią kompilacje 
+      instalowanego przez <em>pip</em> oprogramowania. Poniższa procedurę 
+      testowano na Ubuntu LTS Desktop 20.04, w terminalu wydajemy następujące 
+      polecenie.
+               </p>
+<pre class="code-block">
+$ sudo apt install python3-psycopg2 python3-dev libpq-dev postgresql-server-dev-all build-essential
+</pre>
+               <p>
+                       Powyższe polecenie zainstaluje wybrane pakiety jeśli, któregoś brakuje w 
+      systemie. Aby móc w ogóle pracować z Heroku potrzebujemy założyć sobie na
+      platformie konto, aby to zrobić przechodzimy pod ten adres: 
+      <a href="https://signup.heroku.com/">https://signup.heroku.com/</a>.
+               </p>
+               <p>
+                       Po założeniu konta możemy zainstalować heroku w naszym systemie.
+               </p>
+<pre class="code-block">
+$ sudo snap install --classic heroku
+</pre>
+               <p>
+                       Kiedy nasze oprogramowanie zostanie zainstalowane, możemy przejść do 
+      katalogu naszą aplikacją i uruchomić środowisko wirtualne.
+               </p>
+<pre class="code-block">
+$ cd python/django3
+python/django3 $ source blog_env/bin/activate
+</pre>
+               <p>
+                       W środowisku wirtualnym instalujemy wymagane poniższe pakiety.
+               </p>
+<pre class="code-block">
+(blog_env) python/django3 $ pip install wheel
+(blog_env) python/django3 $ pip install psycopg2
+(blog_env) python/django3 $ pip install django-heroku
+(blog_env) python/django3 $ pip install gunicorn
+</pre>
+               <p>
+                       Aby nasza aplikacja mogła działać na platformie Heroku w sposób 
+      identyczny jak na komputerze lokalnym, musi mieć zainstalowane takie 
+      samo oprogramowanie jakie instalowaliśmy przez 
+      <code class="code-inline">pip</code> do tej pory. Nie było tego dużo, 
+      <em>django</em> oraz <em>django-bootstrap4</em>. Jednak Heroku nie 
+      rozwiąże sobie zależności samodzielnie, dlatego na liście trzeba 
+      uwzględnić wszystko razem z zależnościami, to zadanie możemy wykonać 
+      jednym poleceniem.
+               </p>
+<pre class="code-block">
+(blog_env) python/django3 $ pip freeze &gt; requirements.txt
+</pre>
+               <p>
+                       Plik musi nazywać <em>requirements.txt</em>. Tak wygląda jego zawrtość:
+               </p>
+<pre class="code-block">
+asgiref==3.2.10
+beautifulsoup4==4.9.1
+dj-database-url==0.5.0
+Django==3.1
+django-bootstrap4==2.2.0
+django-heroku==0.3.1
+gunicorn==20.0.4
+psycopg2==2.8.5
+pytz==2020.1
+soupsieve==2.0.1
+sqlparse==0.3.1
+whitenoise==5.2.0
+</pre>
+               <p>
+                       <strong>Uwaga</strong>, może się zdarzyć że w tym pliku znajdzie się taka
+      linia: <code class="code-inline">pkg-resources==0.0.0</code>. Należy ją 
+      usunąć, gdyż nasz projekt nie zostanie zbudowany na Heroku, bo nie będzie
+      mógł odnaleźć takiej zależności. Ta linia nie jest istotna, została 
+      wpisana do pliku przez błąd <code class="code-inline">pip</code>.
+               </p>
+               <p>
+                       Po utworzeniu listy zależności należy wskazać Heroku, jakiej 
+      wersji Pythona ma używać dla naszego projektu, wersje sprawdzimy 
+      poniższym poleceniem.
+               </p>
+<pre class="code-block">
+(blog_env) python/django3 $ python --version
+Python 3.8.2
+</pre>
+               <p>
+                       Natomiast zawartość pliku <em>runtime.txt</em> (nazwa pliku musi być 
+      identyczna) musi wyglądać następująco:
+               </p>
+<pre class="code-block">
+python-3.8.2
+</pre>
+               <p>
+                       Python z małej litery i myślnik zamiast spacji. Nastepnym a zarazem 
+      ostatnim potrzebnym nam plikiem, będzie plik stricte Heroku 
+      <em>Procfile</em>, w nim zostanie zdefiniowany proces maszyny wirtualnej
+      odpowiedzialny za hostowanie naszego projektu.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Zawrtość pliku Procfile</span>
+               </p>
+<pre class="code-block">
+web: gunicorn blog.wsgi --log-file -
+</pre>
+               <p>
+                       Teraz kiedy mamy wszystkie pliki możemy dopisać ustawienia dla Heroku w 
+      naszym projekcie. W głównym katalogu projektu w pliku 
+      <em>settings.py</em> na samym końcu pliku dopisujemy poniższe linie.
+               </p>
+<pre class="code-block">
+import django_heroku
+django_heroku.settings(locals())
+</pre>
+               <p>
+                       Aby móc synchronizować nasz kod źródłowy z platformą Heroku skorzystamy z
+      systemu kontroli wersji <strong>Git</strong>. Git w dużym skrócie tworzy
+      zatwierdzenie (<em>commit</em>) zmian w kodzie, które są tak jakby 
+      oddzielną jego wersją. Projekty tworzą repozytoria, w których 
+      przechowywane są zatwierdzenia, każda nowa funkcjonalność może być 
+      (nawet dobrze, gdyby była) kolejnym zatwierdzeniem. Daje nam to 
+      możliwość powrotu do poprzedniej wersji w razie problemów. Git jest 
+      obecnie standardem zarządania kodem źródłowym, w nie długim czasie od 
+      publikacji tego materiału pojawi się kolejny tym razem dużo mniejszy 
+      posty odnośnie podstaw Git-a.
+               </p>
+               <p>
+                       Git powinien być już zainstalowany w systemie. Jednak warto się upewnić 
+      wydając polecenie:
+               </p>
+<pre class="code-block">
+$ git --version
+</pre>
+<pre class="code-block">
+git version 2.25.1
+</pre>
+               <p>
+                       Jeśli dostaniemy taki wynik polecenie, oznacza to że Git jest już 
+      zainstalowany w systemie. Instalacja na Ubuntu wymaga jednego polecenia:
+               </p>
+<pre class="code-block">
+$ sudo apt install git
+</pre>
+               <p>
+                       Teraz możemy przejść do konfiguracji, musimy podać nazwę użytkownika oraz
+      adres e-mail, który dokonuje zatwierdzeń, ponieważ Git to monitoruje, 
+      jeśli zapomnimy o tym kroku, Git będzie wymagał podania tych danych przy
+      pierwszym przesłaniu kodu do zdalnego repozytorium na platformie Heroku.
+               </p>
+<pre class="code-block">
+$ git config --global user.name "xf0r3m"
+$ git config --global user.email "morketsmerke@gmail.com"
+</pre>
+               <p>
+                       Po skonfigurowaniu gita możemy utworzyć puste repozytorium w katalogu z 
+      danymi projektu wydając bardzo proste polecenie
+               </p>
+<pre class="code-block">
+python/django3 $ git init
+</pre>
+               <p>
+                       Powinniśmy dostać taki wyniki działania dla tego polecenia:
+               </p>
+<pre class="code-block">
+Initialized empty Git repository in /home/xf0r3m/python/django3/.git/
+</pre>
+               <p>
+                       Teraz dodamy plik, w którym zdefiniujemy wszystkie pliki/katalogi, które
+      mają być ignorowane przez Git podczas dodawania zmian do repozytorium. 
+      Tworzymy plik <em>.gitignore</em>, plik ten będzie ukryty z powodu kropki
+      poprzedzającej nazwę pliku. W tym pliku wpisujemy katalog środowiska 
+      wirtualnego <em>blog_env/</em>, katalog <em>__pycache__/</em> oraz 
+      wszystkie pliki baz danych <em>*.sqlite3</em>. Dlaczego? Otóż monitowanie
+      plików lokalnej bazy danych jest generalnie złą praktyką i może 
+      doprowadzić do niezłych tarapatów, kiedy np. nadpiszemy bazę produkcyjną
+      tą na platformie Heroku, bazą testową z Git-a. Dlatego pomijamy ten plik. 
+      Poniżej znajduje się zawartość pliku <em>.gitignore</em>
+               </p>
+<pre class="code-block">
+       blog_env/
+__pycache__/
+*.sqlite3
+</pre>
+               <p>
+                       Teraz kiedy mamy już zdefiniowany plik <em>.gitignore</em>, możemy 
+      przejść do pierwszego zatwierdzenia. W katalogu projektu wydajemy 
+      polecenie:
+               </p>
+<pre class="code-block">
+$ git add .
+</pre>
+               <p>
+                       To polecenie doda do repozytorium wszystkie pliki projektu poza plikami i
+      katalogami z pliku <em>.gitignore</em>.
+               </p>
+<pre class="code-block">
+$ git commit -am "Projekt gotowy do wdrożenia na platformie Heroku"
+</pre>
+               <p>
+                       Powyższe polecenie powoduje właśnie zatwierdzenie. Opcja 
+      <code class="code-inline">-a</code> powoduje uzwględnienie wszystkich 
+      zmodyfikowanych plików do zatwierdzenia, natomiast opcja 
+      <code class="code-inline">-m</code> powoduje dodanie komunikatu do 
+      zatwierdzenia.
+               </p>
+               <p>
+                       Po wydaniu powyższego polecenia warto wydać polecenie:
+               </p>
+<pre class="code-block">
+$ git status
+</pre>
+               <p>
+                       Aby sprawdzić stan wykonanego zatwierdzania, wynik działania polecenia 
+      powinien wyglądać podobnie jak poniżej.
+               </p>
+<pre class="code-block">
+$ git status
+On branch master
+nothing to commit, working tree clean
+</pre>
+               <p>
+      Po wykonaniu pierwszego zatwierdzenia przyszedł czas na przekazanie 
+      projektu do Heroku. Teraz musimy przypomnieć sobie adres e-mail, na jaki
+      zakładaliśmy konto Heroku oraz jakie było do niego hasło. Jeśli mamy już
+      te dane w pobliżu wydajemy polecenie
+               </p>
+<pre class="code-block">
+python/django3 $ heroku login
+heroku: Press any key to open up the browser to login or q to exit:
+Logging in... done
+Logged in as user@example.com
+</pre>
+               <p>
+                       Po wydaniu powyższego polecenia, zgodnie z instrukcją naciskamy dowolny 
+      klawisz poza literą <code class="code-inline">q</code>, aby otworzyła 
+      nam się przeglądarka. Tam podajemy dane dostępowe do Heroku, po poprawny
+      zalogowaniu, zostanie wyświetlony komunikat o poprawyn zalogowaniu oraz 
+      o tym że możemy już zamknąć okno przeglądarki. W terminalu pod instrukcją
+      wyświetloną przez polecenie, zostaną dopisane pozostałe dwie linie takie
+      jak przedstawione powyżej.
+               </p>
+               <p>
+                       Po zalogowaniu możemy już utworzyć nową aplikację wydając w terminalu 
+      poniższe polecenie.
+               </p>
+<pre class="code-block">
+python/django3 $ heroku create
+Creating app... done, ⬢ dry-atoll-67152
+https://dry-atoll-67152.herokuapp.com/ | https://git.heroku.com/dry-atoll-67152.git
+</pre>
+               <p>
+                       W odpowiedzi na to polecenie otrzymamy nazwę nowo utworzonej aplikacji na
+      Heroku, potem zmienimy ją na bardziej przystępną, oraz dwa adresy. Jeden
+      pod którym aplikacja jest dostępna w internecie, natomiast drugi to adres
+      zdalnego repozytorium Git, na który będziemy <strong>wpychać</strong> 
+      zatwierdzenia kodu naszej aplikacji. Adres Git dla naszej aplikacji 
+      Heroku został już automatycznie zdefiniowany jako adres zdalnego 
+      repozytorium pod nazwą <code class="code-inline">heroku</code>. 
+      Dokonajmy teraz pierwszego wepchnięcia oraz zbudujmy naszą aplikacje na 
+      platformie Heroku. Budowa następuje automatycznie po wepchnięciu.
+               </p>
+<pre class="code-block">
+python/django3 $ git push heroku master
+</pre>
+               <p>
+                       Po wydaniu tego polecenia na ekranie zostanie wyświetlony cały proces 
+      budowania aplikacji w Heroku.
+               </p>
+<pre class="code-block">
+Enumerating objects: 46, done.
+Counting objects: 100% (46/46), done.
+Delta compression using up to 4 threads
+Compressing objects: 100% (39/39), done.
+Writing objects: 100% (46/46), 9.12 KiB | 1.14 MiB/s, done.
+Total 46 (delta 6), reused 0 (delta 0)
+remote: Compressing source files... done.
+remote: Building source:
+remote:
+remote: -----&gt; Python app detected
+remote:  !     Python has released a security update! Please consider upgrading to python-3.8.5
+remote:        Learn More: https://devcenter.heroku.com/articles/python-runtimes
+remote: -----&gt; Installing python-3.8.2
+remote: -----&gt; Installing pip 20.1.1, setuptools 47.1.1 and wheel 0.34.2
+remote: -----&gt; Installing SQLite3
+remote: -----&gt; Installing requirements with pip
+remote:        Collecting asgiref==3.2.10
+remote:          Downloading asgiref-3.2.10-py3-none-any.whl (19 kB)
+remote:        Collecting beautifulsoup4==4.9.1
+remote:          Downloading beautifulsoup4-4.9.1-py3-none-any.whl (115 kB)
+remote:        Collecting dj-database-url==0.5.0
+remote:          Downloading dj_database_url-0.5.0-py2.py3-none-any.whl (5.5 kB)
+remote:        Collecting Django==3.1
+remote:          Downloading Django-3.1-py3-none-any.whl (7.8 MB)
+remote:        Collecting django-bootstrap4==2.2.0
+remote:          Downloading django_bootstrap4-2.2.0-py3-none-any.whl (24 kB)
+remote:        Collecting django-heroku==0.3.1
+remote:          Downloading django_heroku-0.3.1-py2.py3-none-any.whl (6.2 kB)
+remote:        Collecting gunicorn==20.0.4
+remote:          Downloading gunicorn-20.0.4-py2.py3-none-any.whl (77 kB)
+remote:        Collecting psycopg2==2.8.5
+remote:          Downloading psycopg2-2.8.5.tar.gz (380 kB)
+remote:        Collecting pytz==2020.1
+remote:          Downloading pytz-2020.1-py2.py3-none-any.whl (510 kB)
+remote:        Collecting soupsieve==2.0.1
+remote:          Downloading soupsieve-2.0.1-py3-none-any.whl (32 kB)
+remote:        Collecting sqlparse==0.3.1
+remote:          Downloading sqlparse-0.3.1-py2.py3-none-any.whl (40 kB)
+remote:        Collecting whitenoise==5.2.0
+remote:          Downloading whitenoise-5.2.0-py2.py3-none-any.whl (19 kB)
+remote:        Building wheels for collected packages: psycopg2
+remote:          Building wheel for psycopg2 (setup.py): started
+remote:          Building wheel for psycopg2 (setup.py): finished with status 'done'
+remote:          Created wheel for psycopg2: 
+filename=psycopg2-2.8.5-cp38-cp38-linux_x86_64.whl size=483298 
+sha256=7daad67c78674aaee0b224f104bccb4ab6a0dbc40682c37b80f6f6e5572f5f7e
+remote:          Stored in directory: /tmp/pip-ephem-wheel-cache-105idbzs/
+wheels/35/64/21/9c9e2c1bb9cd6bca3c1b97b955615e37fd309f8e8b0b9fdf1a
+remote:        Successfully built psycopg2
+remote:        Installing collected packages: asgiref, soupsieve, beautifulsoup4, 
+dj-database-url, pytz, sqlparse, Django, django-bootstrap4, whitenoise, psycopg2,
+django-heroku, gunicorn
+remote:        Successfully installed Django-3.1 asgiref-3.2.10 
+beautifulsoup4-4.9.1 dj-database-url-0.5.0 django-bootstrap4-2.2.0 
+django-heroku-0.3.1 gunicorn-20.0.4 psycopg2-2.8.5 pytz-2020.1
+soupsieve-2.0.1 sqlparse-0.3.1 whitenoise-5.2.0
+remote: -----&gt; $ python manage.py collectstatic --noinput
+remote:        132 static files copied to '/tmp/build_f49f7b9a/staticfiles', 
+418 post-processed.
+remote:
+remote: -----&gt; Discovering process types
+remote:        Procfile declares types -&gt; web
+remote:
+remote: -----&gt; Compressing...
+remote:        Done: 56.1M
+remote: -----&gt; Launching...
+remote:        Released v5
+remote:        https://dry-atoll-67152.herokuapp.com/ deployed to Heroku
+remote:
+remote: Verifying deploy... done.
+To https://git.heroku.com/dry-atoll-67152.git
+ *[new branch]      master -&gt; master
+</pre>
+               <p>
+                       Jeśli otrzymaliśmy podobny input, to znaczy że cały proces przebiegł 
+      prawidłowo. Teraz jeśli wydamy polecenie:
+               </p>
+<pre class="code-block">
+python/django3 $ heroku open
+</pre>
+               <p>
+                       Zostanie otworzona przeglądarka z nasza aplikacją w Heroku. Jednak, 
+      jeśli klikniemy w odnośnik 'Menu', zostanie nam zrócona strona błedu 
+      <em>ProgrammingError</em>, oznacza to mniej więcej tyle i aż tyle że nie
+      ma bazy danych. Utworzenie bazy danych oraz dodanie superużytkownika, to
+      dwie kolejne czynności, które możemy wykonać dwa różne sposoby. 
+      Przedstawie je poniżej, aby byśmy zwrócili uwagę na to że z aplikacjami 
+      na Heroku można wchodzić w interakcje w dwojaki sposób. Pierwszy z nich 
+      to wydawanie konkretnych poleceń poprzedzając nasze polecenie słowami 
+      <code class="code-inline">heroku run</code>. Uruchamiamy daną czynność 
+      tak samo jak w środowisku wirtualnym na naszym lokalnym komputerze. Tak 
+      też stworzymy bazę danych.
+               </p>
+<pre class="code-block">
+python/django3 $ heroku run python manage.py migrate
+Running python manage.py migrate on ⬢ dry-atoll-67152... up, run.7671 (Free)
+Operations to perform:
+  Apply all migrations: admin, auth, blogs, contenttypes, sessions
+Running migrations:
+  Applying contenttypes.0001_initial... OK
+  Applying auth.0001_initial... OK
+  Applying admin.0001_initial... OK
+  Applying admin.0002_logentry_remove_auto_add... OK
+  Applying admin.0003_logentry_add_action_flag_choices... OK
+  Applying contenttypes.0002_remove_content_type_name... OK
+  Applying auth.0002_alter_permission_name_max_length... OK
+  Applying auth.0003_alter_user_email_max_length... OK
+  Applying auth.0004_alter_user_username_opts... OK
+  Applying auth.0005_alter_user_last_login_null... OK
+  Applying auth.0006_require_contenttypes_0002... OK
+  Applying auth.0007_alter_validators_add_error_messages... OK
+  Applying auth.0008_alter_user_username_max_length... OK
+  Applying auth.0009_alter_user_last_name_max_length... OK
+  Applying auth.0010_alter_group_name_max_length... OK
+  Applying auth.0011_update_proxy_permissions... OK
+  Applying auth.0012_alter_user_first_name_max_length... OK
+  Applying blogs.0001_initial... OK
+  Applying blogs.0002_blogpost_owner... OK
+  Applying sessions.0001_initial... OK
+</pre>
+               <p>
+                       Jak można zauważyć na początku trwa nawiązywanie połączenia z naszym 
+      kontenerem (naszą aplikacją), a następnie wykonywane jest polecenie. 
+      Drugim sposobem jest uruchomienie powłoki w środowisku kontenera Heroku,
+      za pomocą tej metody utworzymy superużytkownika. Aby uruchomić powłokę 
+      należy wydać następujące polecenie.
+               </p>
+<pre class="code-block">
+python/django3 $ heroku run bash
+Running bash on ⬢ dry-atoll-67152... up, run.8503 (Free)
+~ $
+</pre>
+               <p>
+                       Po połączeniu zostanie na zrócony taki charakterystyczny, krótki znak 
+      zachęty. Zaraz zanim wydajemy polecenie, takie jakie wydawaliśmy podczas 
+      tworzenie superużytkownika na naszym komputerze.
+               </p>
+<pre class="code-block">
+~ $ python manage.py createsuperuser
+Użytkownik (leave blank to use 'u17122'): blog_admin
+Adres email:
+Password:
+Password (again):
+Superuser created successfully.
+</pre>
+               <p>
+                       Teraz możemy przjeść do naszej aplikacji oraz móc sprawdzić moduł 
+      logowania oraz zalogować się do witryny administracyjnej aby zdefiniować
+      trochę danych.
+               </p>
+               <p>
+                       Teraz kiedy nasza aplikacja jest gotowa, możemy przjeść do nadania jej 
+      nieco przyjaźniejszej nazwy. Zmianę nazwy realizujemy za pomocą 
+      polecenia:
+               </p>
+<pre class="code-block">
+python/django3 $ heroku apps:rename blogs-morkme-v01
+</pre>
+               <p>
+                 Pamiętać jednak należy o tym że podczas nadawania nazw w Heroku 
+      możemy korzystać jedynie z liter, cyfr oraz myślników.
+               </p>
+               <p>
+                       Teraz przejdziemy do zabepieczenia naszej aplikacji. Zwróćmy uwagę na to,
+      że gdy w plikach naszego projektu na Heroku zabrakło bazy danych, została
+      na zwrócona strona z opisem błędu <em>ProgrammingError</em>, ta strona 
+      została przygotowana przez Debuger.</strong> W środowisku testowym jest 
+      powszechne i często spotykane zjawisko, że w razie błędów zostanie 
+      wyświetlona strona z informacjami o tym gdzie szukać danego błędu, 
+      jednak w środowisku produkcyjnym takim jak Heroku jest to 
+      niedopuszczalne, takie strony zazwyczaj zwracają za dużo newralgicznych 
+      danych i mogą być wykorzystane do ataków przeciwko nam. Na podstawie 
+      zmiennej środowiskowej będziemy regulować wyświetlanie stron debugera.
+      Z racji tego iż w Django zmienna <em>Debug</em> przyjmuje wartość 
+      boolowską, a z kolei zmienne środowiskowe przechowują ciągi tekstowe, 
+      będzie nam potrzebna konstrukcja if, którą zaimplementujemy w pliku 
+      <em>settings.py</em> w głównym katalogu projektu.
+               </p>
+               <p>
+                       Naszą implementacje zaczynamy od zaimportowania obiektu 
+      <code class="code-inline">environ</code> modułu 
+      <code class="code-inline">os</code> na górze pliku. Następnie na samym 
+      dole pliku wprowadzamy poniższy kod.
+               </p>
+<pre class="code-block">
+if environ.get('DEBUG') == 'TRUE':
+    DEBUG = True
+elif environ.get('DEBUG') == 'FALSE':
+    DEBUG = False
+</pre>
+               <p>
+                       Za pomocą metody <code class="code-inline">get</code> obiektu 
+      <em>environ</em>, pobieramy wartość zmiennej środowiskowej, której nazwa 
+      jest pobierana jako ciąg tekstowy w pierwszym argumencie. W zależności od
+      wyniku przyrównania wartości w zmiennej 
+      <code class="code-inline">DEBUG</code> nadawana jest wartość boolowska 
+      <code class="code-inline">True</code> or 
+      <code class="code-inline">False</code>. Z racji tego iż przesłaliśmy plik
+      <em>settings.py</em>, wraz ustawioną opcją <em>DEBUG</em> na 
+      <em>True</em>. To teraz musimy ją zmienić w naszej aplikacji na 
+      platformie Heroku, możemy tego dokonać za pomocą jednego polecenia.
+               </p>
+<pre class="code-block">
+python/django3 $ heroku config:set DEBUG=FALSE
+</pre>
+               <p>
+                       To polecenie spowoduje ustawienie podanej zmiennej środowiskowej na 
+      podaną wartość oraz restart aplikacji. Teraz otworzymy naszą aplikację za
+      pomocą polecenia <code class="code-inline">heroku open</code> i 
+      przejdziemy pod stronę, której nie zaimplementowano w naszej aplikacji. 
+      Powinniśmy otrzymać typowy komunikat <em>Not Found</em>. Ten komunikat 
+      nie pasuje do szaty graficznej naszej aplikacji, my jednak możemy dodać 
+      własne szablony dla typowych błędów. Szablony będą banalne, ale będą 
+      miały jedną ważną cechę. Będą ładować podstawowy wygląd naszej aplikacji.
+      Zaczynamy od utworzenia katalogu <em>templates</em> w głównym katalogu 
+      projektu. W tym katalogu tworzymy dwa pliki: <em>404.html</em> oraz 
+      <em>500.html</em>. Poniżej zamieszczam zawartość każdego szablonu.
+               </p>
+               <p>
+                       <span style="text-decoration: underline;">Plik 404.html</span>
+               </p>
+<pre class="code-block">
+{% extends 'blogs/base.html' %}
+
+{% block page_header %}
+    &lt;h2&lt;Żądana strona nie zostałą odnaleziona (404).&lt;/h2&gt;
+{% endblock page_header %}
+</pre>
+                       <p>
+                               <span style="text-decoration: underline;">Plik 500.html</span>
+                       </p>
+<pre class="code-block">
+{% extends 'blogs/base.html' %}
+
+{% block page_header %}
+    &lt;h2&gt;Wystąpił wewnętrzny błąd serwera (500).&lt;/h2&gt;
+{% endblock page_header %}
+</pre>
+               <p>
+                       Teraz wracamy do naszego pliku <em>settings.py</em> w nim ustawiamy jedną
+      rzecz. Na początku importujemy obiekt <em>path</em> z modułu <em>os</em>.
+      Następnie odszukujemy klucz <em>DIRS</em> w słowniku wenątrz listy 
+      <em>TEMPLATES</em>. Następnie wewnątrz listy DIRS wpisujemy jedną wartość
+      zwracaną przez metodę <em>join</em> obiektu <em>path</em>, która jako 
+      argumenty przyjmuje ścieżkę bazową <em>BASE_DIR</em> oraz ścieżkę dostępu
+      do szablonów względem ścieżki bazowej. Trochę to zagmatwane, ale jak 
+      spojrzymy w górę kodu dostrzerzemy fakt iż <em>BASE_DIR</em> to zmienna,
+      którą możemy sobie odtworzyć w powłoce. Jako<em>__file__</em> podstawimy
+      ścieżke do dostępową do pliku <em>settings.py</em> względem naszego 
+      katalogu głównego z plikami, gdzie znajdują katalog projektu, katalogi 
+      aplikacji oraz katalog ze środowiskiem wirtualnym.
+                       Poniżej zamieściłem listing z konsoli jak możemy sprawdzić naszą ścieżkę.
+               </p>
+<pre class="code-block">
+&gt;&gt;&gt;from pathlib import Path
+&gt;&gt;&gt; base_dir = Path('blog/settings.py').resolve(strict=True).parent.parent
+&gt;&gt;&gt; base_dir
+PosixPath('/home/xf0r3m/python/django3')
+</pre>
+               <p>
+                       Teraz znając już wartość naszej zmiennej <em>BASE_DIR</em> możemy 
+      perfekcyjnie ustalić ścieżke dostępową do naszych szablonów.
+               </p>
+               <p>
+                       Warto pamiętać o tym, że te szablony będą wyświetlane tylko wtedy, gdy 
+      opcja <em>DEBUG</em> jest ustawiona na False. Możemy je przetestować 
+      żądając strony, której nie ma, otrzymamy stronę błędu 404. Natomiast 
+      jeśli spróbujemy edytować zamówienie, którego niema to w ten czas 
+      otrzymamy stronę błędu 500. Skupmy się przez chwilę na tym drugim 
+      przypadku, kiedy chcemy edytować zamowienie, którego nie ma. 
+      Przezkazujemy za pomocą metody <em>GET</em> identyfikator zamówienia, 
+      kiedy widok próbuje wydobyć informacje odnośnie rekordu o takim 
+      identyfikatorze otzymuje wartość <em>None</em> oznacza to tyle, że nie ma
+      takiego rekordu, jeśli więc nie ma takiego rekordu to żądana strona 
+      edycji zamówienia nie może istnieć, więc lepiej użyć strony 404 niż 500.
+                       Można to zrealizować wykorzystując funkcję 
+      <code class="code-inline">get_object_or_404</code> z tego samego modułu 
+      <code class="code-inline">django.shortcuts</code>, z którego 
+      importowaliśmy funkcje <em>render</em> oraz <em>redirect</em>, następnie 
+      możemy jej użyć w każdym widoku wymagającym identyfikatora np. w 
+      zapytaniach do bazy.
+               </p>
+<pre class="code-block">
+# order = Order.objects.get(id=order_id)
+order = get_object_or_404(Order, id=order_id)
+</pre>
+               <p>
+                       Zbliżamy się do końca tego materiału, jednak zanim się rozejdziemy dalej 
+      poznawać świat Pythona, posprzątamy po sobie. Jednak jeśli chcesz możesz
+      w ramach ćwiczenia rozwinąć projekt Pizzeria do stanu użytczeności.
+               </p>
+               <p>
+                       Jednak jeśli ta aplikacja, która była z nami przez dłuższą część nauki 
+      <em>frameworka</em> Django przestała być potrzebna, to możemy ją usunąć z
+      platformy wydajac polecenie:
+               </p>
+<pre class="code-block">
+python/django2 $ heroku apps:destroy pizzeria-morkme-1a
+ ▸    WARNING: This will delete ⬢ pizzeria-morkme-1a including
+ ▸    all add-ons.
+ ▸    To proceed, type pizzeria-morkme-1a or re-run this
+ ▸    command with --confirm pizzeria-morkme-1a
+ &gt;
+</pre>
+               <p>
+                       Heroku zarząda od nas potwierdzenia, w postaci ponownego wprowadzenia 
+      nazwy aplikacji. Po jej podaniu, otrzymamy informacje poprawnym 
+      zniszczeniu (usunięciu) aplikacji na platformie Heroku.
+               </p>
+<pre class="code-block">
+&gt; pizzeria-morkme-1a
+Destroying ⬢ pizzeria-morkme-1a (including all add-ons)... done
+</pre>
+               <p>
+                       Jeśli chodzi o podstawy Pythona oraz Django to wydaje mi się, że mamy je 
+      już za sobą.
+               </p>
+    </div>
+       </div>
+       </body>
+</html>
diff --git a/articles/tnt/automatyczne_montowanie_partycji_przy_starcie_systemu.html b/articles/tnt/automatyczne_montowanie_partycji_przy_starcie_systemu.html
new file mode 100755 (executable)
index 0000000..c618b34
--- /dev/null
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Automatyczne montowanie partycji podczas uruchamiania systemu</h1>
+                 <p>
+                   Dla takiego dysku należy utworzyć wpis w pliku 
+        <strong><em>/etc/fstab</em></strong>. Ten plik jest czytany podczas 
+        ładowania systemu, stąd wiadomo, który dysk należy podmontować jako "/"
+        (<em>root</em> - główny system plików). Bardzo rzadko występuje tam 
+        standardowe nazewnictwo dla dysków, takie jak na przykład 
+        <em>/dev/sda1</em>. Raczej występują tam UUID lub PARTUUID. Klasyczne 
+        oznaczenia bywają zwodniczne, mogą zmieniać się, kiedy podłączymy
+                   kolejny dysk. Dostęp do UUID oraz PARTUUID uzyskujemy za pomocą 
+        polecenia <code class="code-inline">blkid</code>. Wywołanie tego 
+        polecenia, w niektórych distro możemy wymagać uprawnień <em>roota</em>.
+                 </p>
+<pre class="code-block">
+$ sudo blkid
+/dev/sda1: UUID="240040b5-fda6-4540-95f2-ce02cfdc96b9" TYPE="ext4" PARTUUID="802e3498-01"
+...
+</pre>
+                 <p>
+                   Jeśli nie wiemy czy wybrać UUID lub PARTUUID, to spójrzmy na linię, 
+        która montuje glówny system plików. Na podstawie tego możemy zdecydować, 
+        którą z tych informacji należy umieścić. Sam wpis wygląda następująco:
+                 </p>
+<pre class="code-block">
+UUID="..."     /home   ext4    defaults        0       2
+</pre>
+                 <p>
+                   Gdzie:
+      </p>
+                 <ul>
+                         <li><code class="code-inline">UUID="..."</code> - UUID (identyfikator
+          urządzenia) sciągnięty z wyniku polecenia 
+                                 <code class="code-inline">blkid</code>,</li>
+                       <li><code class="code-inline">/home</code> - punkt montowania,</li>
+                       <li><code class="code-inline">ext4</code> - montowany system plików</li>
+                       <li><code class="code-inline">defaults</code> - opcje systemów plików, 
+        każdy system posiada swoje, <em>ext4</em> posiada opcję 
+                               <em>defaults</em> dla domyślnego zestawu,</li>
+                       <li><code class="code_inline">0</code> - oznacza ustawienie kopii 
+        zapasowej programu <em>dump</em>,</li>
+                       <li><code class="code_inline">2</code> - oznacza ustawienie sprawdzania 
+        systemu plików przez program <em>fsck</em>. Wartość <em>2</em>
+                               oznacza ze system będzie sprawdzany po głownym systemie plików.</li> 
+                 </ul>
+      <p>
+        ~xf0r3m
+      </p> 
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/automatyczne_przewinięcie_strony_na_sam_dół_w_JS.html b/articles/tnt/automatyczne_przewinięcie_strony_na_sam_dół_w_JS.html
new file mode 100755 (executable)
index 0000000..6ab80da
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt;(__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_links">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main"> 
+      <h1 class="title"> Automatyczne przewinięcie strony na sam dół w JavaScript</h1>
+                 <p>
+                         <strong>Autoscroll</strong>, czyli automatyczne przewinięcie treści 
+        elementu, musi być wykonane w oparciu o jakieś zdarzenie. W funkcji 
+        zdarzenia dopisujemy poniższą linię.
+                 </p>
+<pre class="code-block">
+&lt;zmienna_z_elementem&gt;.scrollTop = &lt;zmienna_z_elementem&gt;.scrollHeight;
+</pre>
+                 <p>
+                         Kiedy dojdzie do zdarzenia treść elementu zostanie przewinięta na sam 
+        dół.
+                 </p>
+      <p>
+        Źródło: znalezione gdzieś na stackoverflow, nie zapisałem linku, gdyż
+        jest to fragment kodu, jednego z moich projektów. 
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/dowiązania_symboliczne_na_udziale_samba.html b/articles/tnt/dowiązania_symboliczne_na_udziale_samba.html
new file mode 100755 (executable)
index 0000000..c0b3626
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Dowiązania symboliczne na udziale Samba</h1>
+                 <p>
+                         W tym celu w pliku konfiguracyjnym <em>/etc/samba/smb.conf</em>, 
+        wpisujemy sekcji globalnej
+                 </p>
+<pre class="code-block">
+allow insecure wide links = yes
+</pre>
+                 <p>
+                         Następnie przchodzimy do definicji udziału i dodajemy poniższe opcje.
+                 </p>
+<pre class="code-block">
+follow symlinks = yes
+wide links = yes
+</pre>
+                 <p>
+                         Zapisujemy i zamykamy plik, następnie restartujemy usługę.
+                 </p>
+<pre class="code-block">
+$ sudo systemctl restart smbd
+$ sudo systemctl restart nmbd
+</pre>
+                 <p>
+                         W sumie to tyle, jednak jeśli mamy zamiar wykorzystać nasz udział do 
+        tworzenia stron WWW, to warto dodać naszego użytkownika do grupy 
+        <em>www-data</em> i wymusić na udziale za pomocą poniższych opcji 
+        zmianę domyślnego właściciela oraz grupę dla nowo utworzonych plików.
+                 </p>
+<pre class="code-block">
+force user = www-data
+force group = www-data
+</pre>
+                 <p>
+                         Jeśli to ustawimy, to należy ustawić grupę oraz właściciela katalogu 
+        głównego serwera WWW <em>/var/www</em> na 
+        <em>www-data</em>:<em>www-data</em> oraz zmienić maski na udziale na 
+        <code class="code-inline">0775</code>.
+                 </p>
+      <p>
+        Źródła:
+        <ol>
+          <li><a href="https://unix.stackexchange.com/questions/5120/how-do-you-make-samba-follow-symlink-outside-the-shared-path">
+           Odpowiednie opcje oraz ich rozmieszczenie</a></li>
+        </ol>
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/index.html b/articles/tnt/index.html
new file mode 100755 (executable)
index 0000000..54bdd38
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+                       <ul class="special_list">
+                               <li><a href="konfiguracja_programu_pocztowego_mutt.html">Konfiguracja programu pocztowego MUTT</a></li>
+        <li><a href="montowanie_virtualbox_shared_folder_na_Alpine_Linux.html">Montowanie VirtualBox Shared Folder na Alpine Linux</a></li>
+        <li><a href="automatyczne_przewinięcie_strony_na_sam_dół_w_JS.html">Automatyczne przewinięcie strony na sam dół w JavaScript</a></li>
+        <li><a href="dowiązania_symboliczne_na_udziale_samba.html">Dowiązania symboliczne na udziale samba</a></li>
+        <li><a href="ustawienie_protokołu_VNC_dla_maszyn_VirtualBox_uruchamianych_w_trybie_headless.html">Ustawienie protokołu VNC dla maszyn VirtualBox uruchamianych w trybie headless</a></li>
+        <li><a href="zwrot_wartości_logicznej_dla_sparsowanego_zapytania_SQL_w_PHP.html">Zwrot wartości logicznej dla sparsowanego zapytania SQL w PHP</a></li>
+        <li><a href="miejsce_montowania_udziału_samba_przez_GNOME_pliki.html">
+Miejsce montowania udziału samba przez menadżer plików środowiska GNOME</a></li>
+        <li><a href="katalog_hostingu_WWW_poza_var_www.html">Katalog hostingu WWWW poza /var/www</a></li>
+        <li><a href="pobieranie_filmów_z_xvideos.html">Pobieranie filmów z XVIDEOS.com</a></li>
+        <li><a href="przekierowanie_na_HTTPS_w_pliku_hostingu_apache2.html">Przekierowanie HTTP na HTTPS w pliku hostingu Apache2</a></li>
+        <li><a href="tworzenie_szyfrowanych_archiwów_za_pomocą_7-zip.html">Tworzenie szyfrowanych archwiwów za pomocą 7-zip</a></li>
+        <li><a href="tworzenie_maszyn_wirtualnych_VirtualBox_z_poziomu_terminala.html">Tworzenie maszyn wirtualnych VirtualBox z poziomu terminala</a></li>
+        <li><a href="obsługa_uploadu_plików_za_pomocą_obszaru_dropzone_JS.html">Obsługa uploadu plików za pomocą obszaru dropzone w JavaScript</a></li>
+        <li><a href="uruchomienie_ssh_na_raspberry_pi.html">Uruchomienie SSH na Raspberry Pi</a></li>
+        <li><a href="uruchomienie_kodu_JS_w_tle_innego_skryptu_JS.html">Uruchomienie kodu JavaScript w tle innego skryptu</a></li>
+        <li><a href="ustawienie_kodowania_polskich_znaków_w_MySQL.html">Ustawienie kodowania polskich znaków w MySQL</a></li>
+        <li><a href="usunięcie_tablicy_RAID_madm.html">Usunięcie tablicy RAID madm</a></li>
+        <li><a href="użycie_polecenia_rsync_w_PHP.html">Użycie polecenia rsync w PHP</a></li>
+        <li><a href="automatyczne_montowanie_partycji_przy_starcie_systemu.html">Automatyczne montowanie partycji podczas uruchamiania systemu</a></li>
+        <li><a href="zabezpieczenie_dostępu_RDP_do_maszyn_VirtualBox_hasłem.html">Zabezpieczenie dostępu RDP do maszyn VirtualBox hasłem</a></li>
+        <li><a href="przenoszenie_systemu_operacyjnego_z_maszyny_wirtualnej_na_fizyczny_komputer.html">Przenoszenie systemu operacyjnego z maszyny wirtualnej na fizyczny komputer</a></li>
+                       </ul>
+               </div>
+
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/tnt/katalog_hostingu_WWW_poza_var_www.html b/articles/tnt/katalog_hostingu_WWW_poza_var_www.html
new file mode 100755 (executable)
index 0000000..b8a4776
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Katalog hostingu WWW poza
+        /var/www</h1>
+                 <p>
+                         W pliku konfiguracyjnym hostingu dopisujemy poniższą dyrektywę katalogu.
+                 </p>
+<pre class="code-block">
+&lt;Directory docelowy_katalog_witryny&gt;
+       Options Indexes FollowSymLinks Includes ExecCGI
+       AllowOverride All
+       Require all granted
+       Allow from all
+&lt;/Directory&gt;
+</pre>
+               <p>
+                       Po tej deklaracji hosting tej strony będzie znajdował się w katalogu 
+      (ścieżce) podanym w polu 
+      <code class="code-inline">docelowy_katalog_witryny</code>.
+               </p>
+    <p>
+      Źródło: Internet.
+    </p>
+    <p>
+      ~xf0r3m
+    </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
+               
diff --git a/articles/tnt/konfiguracja_programu_pocztowego_mutt.html b/articles/tnt/konfiguracja_programu_pocztowego_mutt.html
new file mode 100644 (file)
index 0000000..59f909e
--- /dev/null
@@ -0,0 +1,152 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Konfiguracja programu pocztowego MUTT</h1>
+      <p>
+                       Klient pocztowy <strong>MUTT</strong>, do proste w obsłudze narzędzie
+        umożliwiające korzystanie z popularnych skrzynek mailowych z poziomu
+        terminala czy konsoli serwera. Sprawdza się on wśród hackerów
+        (like a Stallman not Mitnick) oraz osób chcących odbierać powiadomienia
+        z serwera na swoją skrzynkę, ponieważ wysyłanie maili w skryptach w
+        przypadku MUTT jest bardzo proste. Tutaj pokaże wam jak wygląda
+        integracja z MUTT z GMail-em. Jednak na początku musimy na naszej
+        skrzynce.
+      </p>
+               <ul>
+                       <li>Wyłączyć uwierzytelnianie dwuskładnikowe o ile mamy je włączone,</li>
+                       <li>Włączyć dostęp do skrzynki z mniej bezpiecznych aplikcji.</li>
+               </ul>
+      <p>
+                       Przygotowując plik konfiguracyjny korzystałem z dystrybucji GNU/Linux
+        Debian, zatem instalacje przeprowadzę z poziomu managera pakietów tej
+        dystrybucji. Ten materiał mógł znajdować się w kategorii Linux, jednak
+        opiera się o program, który do zainstalowania jest na wiekszości
+        popularnych platform. Przed instalacją jakiego kolwiek oprogramowania
+        zawsze zalecam zaktualizować system.
+               </p>
+<pre class="code-block">
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt install mutt
+</pre>
+               <p>
+                       Po zainstalowaniu upewnijmy się czy został stworzony ukryty katalog
+        <em>.mutt</em> na katalogu domowym użytkownika, w przeciwym wypadku
+        należy taki katalog stworzyć. Poniżej znajduje się plik konfiguracyjny.
+        Możemy go sobie skopiować do edytora, wpisać wymagane rzeczy ujęte w
+        ostre nawiasy (<strong>&lt; &gt;</strong>) i zapisać w
+        <em>$HOME/.mutt/.muttrc</em>. Pod wstawionym listingiem znajduje się
+        opis poszczególnych opcji.
+               </p>
+<pre class="code-block">
+set ssl_starttls=yes
+set ssl_force_tls=yes
+set imap_user='&lt;nazwa_użytkownika&gt;@gmail.com'
+set imap_pass='&lt;hasło_do_konta&gt;'
+set from='&lt;nazwa_użytkownika&gt;@gmail.com'
+
+set realname='&lt;RN&gt;'
+set folder=imaps://imap.gmail.com/
+set spoolfile=imaps://imap.gmail.com/INBOX
+set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
+
+set header_cache="~/.mutt/cache/headers"
+set message_cachedir="~/.mutt/cache/bodies"
+set certificate_file="~/.mutt/certificates"
+
+set smtp_url="smtps://&lt;nazwa_użytkownika&gt;@gmail.com@smtp.gmail.com"
+set smtp_pass='&lt;hasło_do_konta&gt;'
+set move = no
+set imap_keepalive = 900
+</pre>
+               <p>
+                       Warto zaznaczyć że przed pierszym uruchomieniem MUTT,
+        <code class="code-inline">header_cache, message_cachedir, certificate_file</code>
+        muszą istnieć w systemie.
+               </p>
+               <ul>
+                       <li><code class="code-inline">ssl_starttls</code> - wykorzystanie
+          STARTTLS,</li>
+                       <li><code class="code-inline">ssl_force_tls</code> - wymaganie
+          szyfrowania wszystkich połączeń pomiędzy serwerem a klientem,</li>
+                       <li><code class="code-inline">imap_user</code> - nazwa użytkownika
+          serwera IMAP,</li>
+                       <li><code class="code-inline">imap_pass</code> - hasło użytkownika
+          serwera IMAP,</li>
+                       <li><code class="code-inline">from</code> - domyślny adres email
+          nadawcy, będzie wyświetlał się w polu 'Od:' wiadomości,</li>
+                       <li><code class="code-inline">realname</code> - Nazwa personalna nadawcy,
+                               najczęściej imię i nazwisko, wykorzystywana w celu prezentacji nadawcy,
+          np. w skrzynce odbiorczej,</li>
+                       <li><code class="code-inline">folder</code> - domyślna lokalizacja
+          głównej skrzynki mailowej (jak katalog / [root]), w tym przypadku jest
+          serwer IMAP Gmaila.</li>
+                       <li><code class="code-inline">spoolfile</code> - lokalizacja skrzynki
+          odbiorczej,</li>
+                       <li><code class="code-inline">postponed</code> - lokalizacja skrzynki z
+          kopiami (wersjami) roboczymi,</li>
+                       <li><code class="code-inline">header_cache</code> - plik pamięć
+          podręcznej zawierający nagłówki wiadomości,</li>
+                       <li><code class="code-inline">message_cachedir</code> - katalog na
+          pamięć podręczną zawierającą wiadomości,</li>
+                       <li><code class="code-inline">certificate_file</code> - plik
+          zawierający zaakceptowane przez nas certyfikaty,</li>
+                       <li><code class="code-inline">smtp_url</code> - adres serwera SMTP,
+          w wewnątrz adresu zawarta jest już nazwa użytkownika,</li>
+                       <li><code class="code-inline">smtp_pass</code> - hasło do konta
+          użytkownika na serwerze SMTP.</li>
+                       <li><code class="code-inline">move</code> - przenoszenie przeczytanych
+          wiadomości ze skrzynki odbiorczej do skrzynki na przeczytane,</li>
+                       <li><code class="code-inline">imap_keepalive</code> - ilość czasu
+          (w sekundach) utrzymania połączenia z serwerem IMAP, stosowane aby
+          serwer przedwcześnie nie zamknął połączenia.</li>
+               </ul>
+               <p>
+                       Po skonfigurowaniu naszej skrzynki i pierwszym jej otwarciu w tym
+        programie, MUTT jest gotowy do wysyłania maili z poziomu wiersza poleceń.
+               </p>
+<pre class="code-block">
+$ cat message.txt | mutt -s "To jest temat maila" adresat@example.com
+</pre>
+               <p>
+                       Przekierowując zawartość pliku tekstowego tworzymy treść wiadomości,
+        którą wysyłamy na adres
+        <code class="code-inline">adresat@example.com</code>, opisując całość
+        tematem zawartym po przełączniku <code class="code-inline">-s</code>.
+               </p>
+      <p>
+        Niestety ten artykuł należy uznać za przestarzały, ze względu na użyty
+        przypadek. Od 30 maja 2022 Google wyłączy możliwość logowania się
+        na konto Google aplikacjom innych firm, które używają wyłącznie loginu
+        i hasła. Mimo to sam sposób logowania do innych dostawców, którzy nadal
+        korzystają tradycyjnych metod powinien być jak najbardziej aktualny.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/tnt/miejsce_montowania_udziału_samba_przez_GNOME_pliki.html b/articles/tnt/miejsce_montowania_udziału_samba_przez_GNOME_pliki.html
new file mode 100755 (executable)
index 0000000..17c1cc5
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Miejsce montowania udziału samba przez 
+        menadżer plików środowiska GNOME</h1>
+                 <p>
+                         Udział montowany jest na ścieżce <em>/run/user/&lt;uid&gt;/gvfs/smb-share:&lt;SERWER&gt;,share:&lt;nazwa_udziału&gt;</em>.
+                 </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/montowanie_virtualbox_shared_folder_na_Alpine_Linux.html b/articles/tnt/montowanie_virtualbox_shared_folder_na_Alpine_Linux.html
new file mode 100755 (executable)
index 0000000..3d5e5d5
--- /dev/null
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Montowanie VirtualBox Shared Folder 
+        na Alpine Linux</h1>
+                 <p>
+                         Pierwszą rzeczą jaką należy wykonać jest włączenie repozytoriów 
+        społeczności, w pliku <em>/etc/apk/repositories</em> usuwamy znak 
+        komentarza na początku linii zawierającej taki ciąg znaków 
+        'v3.11/community', gdzie v3.11 to wersja systemu Alpine.
+                 </p>
+<pre class="code-block">
+#/media/cdrom/apks
+http://ftp.icm.edu.pl/pub/Linux/distributions/alpine/v3.11/main
+http://ftp.icm.edu.pl/pub/Linux/distributions/alpine/v3.11/community
+#http://ftp.icm.edu.pl/pub/Linux/distributions/alpine/edge/main
+#http://ftp.icm.edu.pl/pub/Linux/distributions/alpine/edge/community
+#http://ftp.icm.edu.pl/pub/Linux/distributions/alpine/edge/testing
+</pre>
+                 <p>
+                         Zapisujemy zmiany, następnie instalujemy niezbędne oprogramowanie.
+                 </p>
+<pre class="code-block">
+# apk add build-base virtualbox-guest-additions virtualbox-guest-modules-virt
+</pre>
+                 <p>
+                         Po instalacji restartujemy system.
+                 </p>
+<pre class="code-block">
+# reboot
+</pre>
+                 <p>
+                         Kiedy system się załaduje, możemy dodać moduł do jądra.
+                 </p>
+<pre class="code-block">
+# modprobe -a vboxsf
+</pre>
+                 <p>
+                         Jeśli dodanie modułu do jądra nie zwróci żadnych błędów, możemy przejść
+        do montowania folderu współdzielonego VirtualBox.
+                 </p>
+<pre class="code-block">
+# mount -t vboxsf vbox_share /media
+</pre>
+                 <p>
+                         Gdzie <code class="code-inline">vbox_share</code> to nazwa folderu 
+        współdzielonego.
+                 </p>
+      <p>
+        Źródła:
+        <ol>
+          <li><a href="https://wiki.alpinelinux.org/wiki/VirtualBox_shared_folders">
+            Folder współdzielony VirtualBox - Dokumentacja Alpine Linux</a></li>
+        </ol>
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/obsługa_uploadu_plików_za_pomocą_obszaru_dropzone_JS.html b/articles/tnt/obsługa_uploadu_plików_za_pomocą_obszaru_dropzone_JS.html
new file mode 100755 (executable)
index 0000000..51b7948
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Obsługa uploadu plików za pomocą obszaru 
+        dropzone w JavaScript</h1>
+               <p>
+                       Aby tego dokonać możemy użyć poniższego kodu.
+               </p>
+<pre class="code-block">
+&lt;script&gt;
+function uploadFiles(plik) {
+
+       var xhr = new XMLHttpRequest();
+       var fd = new FormData();
+
+       xhr.open("POST", '/service.php', true);
+       xhr.onload = function () {
+               if ( xhr.status === 200 ){
+               alert(xhr.responseText);
+               }
+       }
+       fd.append('pliki', plik);
+       xhr.send(fd);
+}
+
+var dropzone = document.getElementById("dropzone");
+
+dropzone.ondragover = dropzone.ondragenter = function (e) {
+       e.stopPropagation();
+       e.preventDefault();
+}
+
+dropzone.ondrop = function (e) {
+       e.preventDefault();
+       e.stopPropagation();
+       var plikiTab = e.dataTransfer.files;
+
+       for (var a=0; a &lt; plikiTab.length; a++) {
+               uploadFiles(plikiTab[a]);
+       }
+}
+&lt;/script&gt;
+&lt;div id="dropzone"&gt;Przeciągnij i upuść pliki tutaj.&lt;/div&gt;
+</pre>
+               <p>
+                       Jedyne co musimy zrobić to przygotować plik PHP, który obsłuży nam 
+      wysłany plik.
+               </p>
+    <p>
+      Źródło: Kod perfidnie ukradziony z internetu.
+    </p>
+    <p>
+    ~xf0r3m
+    </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/pobieranie_filmów_z_xvideos.html b/articles/tnt/pobieranie_filmów_z_xvideos.html
new file mode 100755 (executable)
index 0000000..8580b23
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Pobranie filmów z XVIDEOS.com</h1>
+                 <p>
+                         Możemy je pobrać za pomocą zwykłego terminala. URL do filmu znajduje 
+        się na stronie, wystarczy go wydobyć.
+                 </p>
+<pre class="code-block">
+$ wget --no-check-certificate &lt;url z filmem&gt;
+$ url=$(cat &lt;plik_strony_z_filmem&gt; | grep "setVideoUrlHigh" | cut -d "'" -f 2);
+$ wget --no-check-certificate $url
+</pre>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/przekierowanie_na_HTTPS_w_pliku_hostingu_apache2.html b/articles/tnt/przekierowanie_na_HTTPS_w_pliku_hostingu_apache2.html
new file mode 100755 (executable)
index 0000000..4ed84d6
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_links">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Przekierowanie HTTP na HTTPS w pliku hostingu Apache2</h1>
+                 <p>
+                         W pliku hostingu HTTP, dopisujemy poniższe opcje.
+                 </p>
+<pre class="code-block">
+RewriteEngine On
+RewriteCond %{HTTPS} !on
+RewriteRule (.*) https://${HTTP_HOST}%{REQUEST_URI}
+</pre>
+                 <p>
+                         Aby te opcje zadziałały, niezbędne jest włączenie modułu <em>rewrite</em>.
+                 </p>
+<pre class="code-block">
+$ sudo a2enmod rewrite
+</pre>
+      <p>
+        Źródło: Internet.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/przenoszenie_systemu_operacyjnego_z_maszyny_wirtualnej_na_fizyczny_komputer.html b/articles/tnt/przenoszenie_systemu_operacyjnego_z_maszyny_wirtualnej_na_fizyczny_komputer.html
new file mode 100755 (executable)
index 0000000..1033988
--- /dev/null
@@ -0,0 +1,402 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Przenoszenie systemu operacyjnego z
+        maszyny wirtualnej na fizyczny komputer</h1>
+      <p>
+        W zeszłym tygodniu na mój warsztat trafiły dwa laptopy. Jeden zupełnie
+        nowy, zakupiony na potrzeby programu diagnostycznego dla ciężarówek.
+        Drugi zaś nieco już zużyty. Wymieniony program diagnostyczny jest 
+        rozpowadzany na zasadzie
+        gotowego środowiska znajdującego się na maszynie wirtualnej VMware.
+        Mój zleceniodawca poprosił mnie abym oczyścił ten stary laptop i
+        generalnie przystosował go do tego aby działa na nim tylko ten program,
+        nic więcej. Starszy laptop to <em>Dell Inspiron 3542</em> z i3 czwartej
+        generacji, 4GB ramu oraz tradycjnym dyskiem talerzowym o pojemności
+        500GB. Szału nie ma, na VMware ten laptop jest za słaby. Sprawdziłem,
+        że sama maszyna ma przydzielone 3 GB pamięci operacyjnej, najwyraźniej 
+        tyle wymaga.
+      </p>
+      <p>
+        Do głowy przyszedł mi pomysł: a co jeśli by wyciągnąć obraz dysku z
+        maszyny. Na początku straciłem trochę czasu, na szukanie sprawdzonego
+        narzędzia, które musiało zginąć pod czas uszkodzenia przez mnie
+        LVM-u na serwerze plików w warsztacie. No cóż stwierdziłem, że jak
+        nie mam obrazu, to go zrobie. Niestety po odszukaniu na gryzoniu
+        programu w odpowiedniej wersji, nie byłem wstanie utworzyć obrazu płyty
+        gdyż ADK dla Windows 8.1, nie jest już dostępne. Microsoft radzi użycie
+        ADK dla Windows 10, ten program nie chce jednak tego przyjąć. 
+        Utworzone
+        na dysku usb oparte na Linuksie środowisko, nie miało w ogóle funkcji
+        utworzenia kopii zapasowej dysku. Więc zacząłem szukać jakiejś
+        alternatywy, najlepiej <em>open source</em> i do głowy wpadła mi
+        <strong>Clonezilla</strong> - to dystrybucja GNU/Linux oparta na
+        Debianie służąca tworzeniu kopii zapasowych partycji jak i całych 
+        dysków.
+      </p>
+      <p>
+        Obrazy przeznaczone dla i386 oraz amd64 znajdziemy na stronie projektu.
+        Tu warto zaznaczyć, że najlepiej jest wybrać jako mirror <em>OSDN</em>.
+        Dla celów testowych przedstawie przypadek, przeniesienia Windows 7 
+        Starter 32 bit na netbooka Acer Aspire One. Aby przenieść system z
+        maszyny wirtualnej dobrze jest operować udziałem <em>Samba</em>,
+        ponieważ łatwiej jest utworzyć obraz dysku maszyny wirtualnej na
+        udziale, a <em>Clonezilla</em> jest wstanie 
+        utworzyć backup dysku na udziale sieciowym. Tak wygląda maszyna
+        wirtualna, z której będziemy przenosić nasz system:
+      </p>
+      <p>
+        <img src="https://i.ibb.co/j5qWW3X/01-clonezilla-okno-z-maszyn.jpg" alt="01-clonezilla-okno-z-maszyn" border="0" style="width: 70%;">
+      </p>
+      <h2>Tworzenie obrazu</h2>
+      <p>
+        Pracę rozpoczynamy od załadowania do napędu maszyny wirtualnej obrazu 
+        płyty z <em>Clonezillą</em>, następnie uruchomiamy ją z niego. Z menu 
+        programu rozruchowego wybieramy pierwszą, domyślną opcję.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/5xK73fJ/02-clonezilla-uruchomienie-clonezilla.jpg" alt="02-clonezilla-uruchomienie-clonezilla" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po uruchomieniu zostaniemy zapytani o ustawienia lokalizacyjne takiej
+        jak język (<em>Clonezilla</em> jest po polsku).
+      </p>
+      <p>
+        <img src="https://i.ibb.co/ThRn3FB/03-clonezilla-wybor-jezyka.jpg" alt="03-clonezilla-wybor-jezyka" border="0" style="width: 70%;">
+      </p>
+      <p>
+        oraz układ klawiatury (pozostawiamy go domyślnie).
+      </p>
+      <p>
+        <img src="https://i.ibb.co/HpFd5Wy/04-clonezilla-uklad-klawiatury.jpg" alt="04-clonezilla-uklad-klawiatury" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Nastepnie uruchamiamy już właściwy proces wybierając opcje 
+        <em>Start_Clonezilla</em>.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/tZwphZx/05-clonezilla-uruchomienie-clonezilla.jpg" alt="05-clonezilla-uruchomienie-clonezilla" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Program może pracować w wielu trybach, jednak nas będzie interesować
+        wyłącznie praca z obrazami dlatego w następnym oknie wybieramy opcje
+        <em>device-image</em>.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/zQD7hsk/06-clonezilla-praca-z-obrazami.jpg" alt="06-clonezilla-praca-z-obrazami" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Tak jak już wspomniałem na wstępnie, jako miejsca docelowego na obraz
+        wykorzystamy udział <em>Samba</em>. Tworząc obrazy na fizycznych maszynach
+        możemy użyć pendrive-a lub dysku zewnetrznego, jednak w naszym
+        przypadku potrzeba by nieco więcej zachodu aby przekazać maszynie dysk
+        zewnętrzny, a wydajność mogłaby być niezbyt zadowalająca. Dlatego też
+        teraz wybieramy opcje <em>samba_server</em>. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/d4Gjb4M/07-clonezilla-wybranie-miejsca-docelowego-dla-obrazow.jpg" alt="07-clonezilla-wybranie-miejsca-docelowego-dla-obrazow" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Przechodząc przez kolejne okna będziemy musieli podać wszystkie
+        parametry potrzebne do połączenia z udziałem. Jednak najpierw musimy
+        dokonać konfiguracji sieci środowiska <em>Clonezilla</em>. Możemy
+        pobrać ją z serwera DHCP, więc pozostawiamy domyślną opcję.
+        Po tej konfiguracji przyszła pora na podanie parametrów
+        do połączenia się z udziałem.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/gV1M288/08-clonezilla-konfiguracja-karty-sieciowej.jpg" alt="08-clonezilla-konfiguracja-karty-sieciowej" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Podajemy adres ip serwera <em>Samba</em>.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/KNnGdJ2/09-clonezilla-wskazujemy-nazwe-lub-ip-serwera-samba.jpg" alt="09-clonezilla-wskazujemy-nazwe-lub-ip-serwera-samba" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Następnie domenę (jeśli domena nie jest ustawiona na serwerze, 
+        wybieramy przycisk "Anuluj").
+      <p>
+        <img src="https://i.ibb.co/R9K6K4Q/10-clonezilla-domena-na-serwerze-samba.jpg" alt="10-clonezilla-domena-na-serwerze-samba" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Teraz podajemy nazwę użytkownika mającego uprawnienia do zapisu na 
+        docelowym udziale.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/Yyq2yQ0/11-clonezilla-uzytkownik-udzialu-na-serwerze.jpg" alt="11-clonezilla-uzytkownik-udzialu-na-serwerze" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Nazwę udziału (uwaga), podajemy po <em>slashu</em> - jak by to był 
+        folder, ale to nazwa udziału.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/6gZjZ9j/12-clonezilla-wskazanie-nazwy-udzialu.jpg" alt="12-clonezilla-wskazanie-nazwy-udzialu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po podaniu ostatniej informacji, zostaniemy poproszeni o wybór wersji
+        protokołu SMB. Mój serwer to <em>Samba</em> postawiona na Debian 10, 
+        więc pozostawiam tę wartość domyślnie.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/BNggDmq/13-clonezilla-wybranie-wersji-protokolu.jpg" alt="13-clonezilla-wybranie-wersji-protokolu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Kolejną jest "tryb bezpieczestwa", jeśli udział nie stoi na jakimś 
+        archaiczym Windowsie pozostawiamy <em>auto</em>.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/0fpRTKk/14-clonezilla-wybor-trybu-bezpieczenstwa.jpg" alt="14-clonezilla-wybor-trybu-bezpieczenstwa" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po zatwierdzeniu tej opcji, zostanie nam wyświetlony monit o potrzebie 
+        podania hasła do udziału. Polecenie pokazane w oknie jest tylko 
+        poglądowe i nie ma nic wspólnego z właściwym poleceniem montującym 
+        udział.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/MVRPh8h/15-clonezilla-monit-o-podaniu-hasla.jpg" alt="15-clonezilla-monit-o-podaniu-hasla" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po wybraniu "OK" zostanie zwrócony znak zachęty proszący o hasło aby 
+        podmontować udział. Każdy kto kiedyś montował udział SMB za pomocą 
+        wiersza poleceń będzie znać ten symbol.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/VH2yG42/16-clonezilla-wpisywanie-hasla-do-udzialu.jpg" alt="16-clonezilla-wpisywanie-hasla-do-udzialu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po prawidłowym podłączeniu udziału, <em>Clonezilla</em> zwróci nam
+        tabelę z informacjami na temat udziału (dostępna przestrzeń dysku,
+        punkt montowania).
+      </p>
+      <p>
+        <img src="https://i.ibb.co/g4KqMTL/17-clonezilla-informacja-zwrotna-o-zamontowanym-udziale.jpg" alt="17-clonezilla-informacja-zwrotna-o-zamontowanym-udziale" border="0" style="width: 70%;"> 
+      </p>
+      <p>
+        Po zamontowaniu miejsca docelowego
+        w <em>/home/partimag</em>, pora wybrać tryb pracy programu
+        <em>Clonezilla</em>. Do wyboru będziemy mieli tryb <em>Beginner</em> -
+        początkujący lub <em>Expert</em>. Jako iż jest to moja druga w ogóle
+        styczność z tym narzędziem, sam wybrałem tryb dla początkujących. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/K5DvrWm/18-clonezilla-tryb-beginner.jpg" alt="18-clonezilla-tryb-beginner" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po uruchomieniu programu w trybie dla początkujących, musimy określić 
+        sposób
+        tworzenia kopii. <em>Clonezilla</em> może tworzyć kopie całych dysków 
+        lub
+        poszczególnych partycji. Dla rozpatrywanego przypadku najlepszym
+        rozwiązaniem jest zapisanie całego dysku. Instalacja najnowszych
+        systemów Windows jest zazwyczaj rozbijana na kilka partycji. Zatem
+        wybieramy opcje <em>savedisk</em>.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/0cFDrzh/19-clonezilla-zapisujemy-lokalny-dysk-jako-obraz.jpg" alt="19-clonezilla-zapisujemy-lokalny-dysk-jako-obraz" border="0" style="width: 70%;">
+      </p>
+      <p>
+        W następnym oknie zostaniemy poproszeni o podanie nazwy dla katalogu,
+        w którym przechowywany będzie obraz. To dobry i jedyny moment, aby go
+        opisać.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/9ZWCF2Q/20-clonezilla-nazwa-dla-katalogu-obrazu.jpg" alt="20-clonezilla-nazwa-dla-katalogu-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po utworzeniu odpowiedniego katalogu, pora na wybór dysku źródłowego.
+        Zaznaczamy dysk z listy, przechodzimy na przycisk "OK" i klikamy Enter.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/BVrCsnX/21-clonezilla-wybieramy-zrodlo-dla-naszego-obrazu.jpg" alt="21-clonezilla-wybieramy-zrodlo-dla-naszego-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        W kolejnym pytaniu program za sugeruje man sprawdzenie i ewenualną
+        naprawę systemu plików. Jednak dla systemów takich jak NTFS jest to 
+        nie możliwe, więc wybieramy opcje <em>-sfsck</em> (pominięcie
+        sprawdzenia systemu plików).
+      </p>
+      <p>
+        <img src="https://i.ibb.co/MMPfNYn/22-clonezilla-sprawdzenie-systemow-plikow-przed-stworzenien-obrazu-dla-ntfs-mozna-pominac.jpg" alt="22-clonezilla-sprawdzenie-systemow-plikow-przed-stworzenien-obrazu-dla-ntfs-mozna-pominac" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Domyślnie <em>Clonezilla</em> chce sprawdzić
+        poprawność zapisanego obrazu. W tym przypadku zostawiam pełną
+        dowolność. Ja, aby nie przedłużać tworzenia obrazu, czy zakończenia
+        procesu pominąłem sprawdzanie obrazu. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/bLXd6fT/23-clonezilla-czy-sprawdzic-zapisany-obraz.jpg" alt="23-clonezilla-czy-sprawdzic-zapisany-obraz" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Kolejne okno zawiera pytanie o
+        szyforwanie obrazu, tutaj również pozostawiam dowolność, jednak jeśli
+        tworzymy obraz zaszyfrowanego dysku, to sam obraz również dobrze jest
+        zaszyfrować.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/fq7qS8p/24-clonezilla-pytanie-o-szyfrowanie-obrazu.jpg" alt="24-clonezilla-pytanie-o-szyfrowanie-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Przed wykonaniem obrazu należy zdefiniować jeszcze
+        czynność wykonywaną po ukończeniu tego procesu. Co ma zrobić 
+        <em>Clonezilla</em>. Może przejść do wiersza poleceń, wyłączyć lub
+        zrestartować komputer. Może również przjeść do menu, z którego 
+        wybierzemy inną czynność. Jest to przydatne kiedy chcemy utworzyć obrazy 
+        większej ilości dysków, ponieważ będziem mogli uruchomić program od 
+        pewnego momentu, pomijąjąc część konfiguracji. Tutaj też możemy wybrać 
+        dowolnie. Ja wybrałem opcję <em>-choose</em> uruchamiającą owe menu.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/LtxbYMF/25-clonezilla-akcja-do-wykonania-po-stworzeniu-obrazu.jpg" alt="25-clonezilla-akcja-do-wykonania-po-stworzeniu-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Teraz kiedy wszystkie ustawienia zostały przyjęte. <em>Clonezilla</em>
+        wyświetli polecenie, którego możemy użyć korzystając z wiersza poleceń,
+        aby utworzyć obraz ponownie bez przechodzenia przez te wszystkie okna. 
+        Klikamy "Enter" w celu kontynuowania działania programu.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/2nxbM9Z/26-clonezilla-informacja-o-zapisaniu-uzytego-polecenia.jpg" alt="26-clonezilla-informacja-o-zapisaniu-uzytego-polecenia" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po przetworzeniu kilku informacji o dysku źródłowym, program wyświetli
+        informacje o tym, że zostanie utworzony obraz źródłowego dysku oraz
+        pytanie czy chcemy kontynuować. Potwierdzamy odpowiadając na pytanie
+        <em>y</em> i klikając "Enter".
+      </p>
+      <p>
+        <img src="https://i.ibb.co/vdt3ByS/27-clonezilla-consent-o-utworzenie-obrazu.jpg" alt="27-clonezilla-consent-o-utworzenie-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        W tym momencie rozpoczyna pracę już właściwy program <strong>Partclone</strong>
+        znany między innymi z projektu FOG (Free Open-source Ghost - ma podobne
+        zastosowanie co <em>Clonezilla</em>, jednak jest bardziej ukierunkowny
+        na wykorzystanie sieciowe oraz masowe. Przydaje się przy reinstalacji
+        systemów operacyjnych w szkolnych salach komputerowych).
+      </p>
+      <p>
+        <img src="https://i.ibb.co/3RX1pMC/28-clonezilla-tworzenie-obrazu.jpg" alt="28-clonezilla-tworzenie-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        O zakończonym procesie tworzenia obrazu zostaniemy poinformowani.
+        Pozostało nam tak naprawdę tylko kliknąć klawisz "Enter". Po tym
+        nastąpi akcja, którą wcześniej wybraliśmy.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/dM1RT1C/29-clonezilla-informacja-zwrotna-po-utworzeniu-obrazu.jpg" alt="29-clonezilla-informacja-zwrotna-po-utworzeniu-obrazu" border="0" style="width: 70%;">
+      </p>
+      <h2>Przywracanie obrazu</h2>
+      <p>
+        Początkowe fazy przywracania obrazu, są identyczne jak przy jego
+        tworzeniu. Po zamontowaniu miejsca, w którym składowane są obrazy,
+        podczas wybierania trybu wybieramy <em>restoredisk</em>, przywracając
+        tym samym stan zapisany w obrazie na dysk. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/9gmfp17/01-clonezilla2-przywracanie-dysku.jpg" alt="01-clonezilla2-przywracanie-dysku" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Program przeszuka teraz magazyn w poszukiwaniu obrazów i zostaną one
+        wyświetlone w menu do wyboru. Naszym zadanie jest wybrać obraz jaki
+        ma zostać przywrócony na tym komputerze.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/brNj40B/02-clonezilla2-wybor-pliku-obrazu.jpg" alt="02-clonezilla2-wybor-pliku-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Dla wybranego obrazu musimy teraz wskazać docelowy dysk. Środowisko
+        <em>Clonezilli</em> przeszuka komputer pod względem dysków i zostaną one
+        wyświetlone w menu do wyboru. 
+      </p>
+      <p>
+        <img src="https://i.ibb.co/JQc1t15/03-clonezilla2-wybor-dysku-docelowego-dla-obrazu.jpg" alt="03-clonezilla2-wybor-dysku-docelowego-dla-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Teraz program zapyta o to czy sprawdzić obraz przed przywróceniem.
+        Jeśli jest to dla nas ważne, możemy go sprawdzić. Jednak jeśli
+        testujemy <em>Clonezillę</em>. Możemy sobie darować, stracimy tylko
+        czas.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/k22S8Rk/04-clonezilla2-pominiecie-sprawdzania-obrazu.jpg" alt="04-clonezilla2-pominiecie-sprawdzania-obrazu" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Tak jak i w przypadku tworzenia obrazu, należy wskazać czynność jaka
+        zostanie wykonana po przywróceniu.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/k4kK2LH/05-clonezilla2-akcja-po-zakonczeniu-przywracania-obrazu.jpg" alt="05-clonezilla2-akcja-po-zakonczeniu-przywracania-obrazu" border="0" style="width: 70%";>
+      </p>
+      <p>
+        Następnie zostanie nam zwrócone
+        polecenie użyte do przywrócenia, mamy szanse je zapisać, aby
+        zaoszczędzić te kilka chwil spędzonych na pytaniach programu
+        przywracając ten obraz ponownie w tych samych okolicznościach.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/HnkNTxm/06-clonezilla2-zapisanie-polecenia-przywracania.jpg" alt="06-clonezilla2-zapisanie-polecenia-przywracania" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po naciśnięciu klawisza "Enter", narzędzie zapyta nas dwukrotnie, czy
+        chcemy kontynuować przywracanie obrazu, ponieważ ta czynność nadpisze
+        wszelkie dane znajdujące się na dysku.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/5kDqLJY/08-clonezilla2-drugi-z-dwoch-consentow-o-nadpisanie-danych-na-dysku.jpg" alt="08-clonezilla2-drugi-z-dwoch-consentow-o-nadpisanie-danych-na-dysku" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Po potwierdzeniu, rozpoczyna się już właściwa procedura przywracania
+        realizowana przez program <em>Partclone</em>. Po jej zakończniu zostanie
+        wykonana czynność wybrana przed przywracaniem.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/hH1GLHq/11-clonezilla2-przywracanie-obrazu-na-fizycznym-komputerze.jpg" alt="11-clonezilla2-przywracanie-obrazu-na-fizycznym-komputerze" border="0" style="width: 70%;">
+      </p>
+      <p>
+        Poniżej znajduje się zdjęcie przedstawiające pulpit laptopa, na którego
+        system został przeniesiony z maszyny wirtualnej. Powyższe zdjęcie
+        również pochodzi z procedury przywracania systemu na tym sprzęcie.
+        Jak widać system się uruchomił, pozostało tylko zainstalować
+        sterowniki i można działać. Przenoszenie powiodło się zarówno w moim
+        jak i testowym przypadku. Póki co czekam na <em>feedback</em> czy
+        program działa.
+      </p>
+      <p>
+        <img src="https://i.ibb.co/JsvTFPY/12-clonezilla2-gotowy-pulpit-na-fizycznym-komputerze.jpg" alt="12-clonezilla2-gotowy-pulpit-na-fizycznym-komputerze" border="0" style="width: 70%">
+      </p> 
+      <p>
+        Część rysunków w podczas przywracania to zrzuty ekranu z maszyny
+        wirtualnej, dlatego iż były prostsze do zarejestrowania niż robienie
+        zdjęć błyszczącej matrycy.
+      </p>
+      <p>
+       ~xf0r3m
+      </p> 
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+
+               </body>
+       </html>
diff --git a/articles/tnt/tworzenie_maszyn_wirtualnych_VirtualBox_z_poziomu_terminala.html b/articles/tnt/tworzenie_maszyn_wirtualnych_VirtualBox_z_poziomu_terminala.html
new file mode 100755 (executable)
index 0000000..3bb2f25
--- /dev/null
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       </style>
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Tworzenie maszyn wirtualnych VirtualBox z poziomu terminala</h1>
+                 <p>
+                         Wykonujemy poniższą sekwencje poleceń, aby utworzyć maszynę VirtualBox
+        poziomu terminala.
+                 </p>
+                 <p>
+                         Rozpoczniemy od utworzenia samej maszny, a następnie będziemy ją 
+        konfigurować.
+                 </p>
+<pre class="code-block">
+$ vboxmanage --createvm --name &lt;nazwa_maszyny&gt; --ostype &lt;goszczony_system_operacyjny&gt; --register
+</pre>
+                 <p>
+                         W katalogu maszyny <em>$HOME/VirtualBox VMs/&lt;nazwa_maszyny&gt;</em>, 
+        utworzymy dysk.
+                 </p>
+<pre class="code-block">
+$ vboxmanage createhd --filename &lt;nazwa_dysku&gt; --size &lt;rozmiar_dysku_w_MB&gt; --format VDI --variant Standard
+</pre>
+                 <p>
+                         Po utworzeniu dysku możemy przejść do utworzenia kontrolera dysków na 
+        maszynie.
+                 </p>
+<pre class="code-block">
+$ vboxmanage storagectl &lt;nazwa_maszyny&gt; --name SATA0 --add sata
+</pre>
+                 <p>
+                         Kiedy mamy już dodany kontroler, możemy załadować dysk oraz obraz płyty,
+        z którego będziemy instalować system.
+                 </p>
+<pre class="code-block">
+#DYSK:
+$ vboxmanage storageattach &lt;nazwa_maszyny&gt; --storagectl SATA0 --port 0 --type hdd --medium &lt;nazwa_pliku/scieżka dysku&gt;
+
+#OBRAZ PŁYTY
+$ vboxmanage storageattach &lt;nazwa_maszyny&gt; --storagectl SATA0 --port 1 --type dvddrive --medium &lt;ścieżka_do_iso&gt;
+</pre>
+                 <p>
+                         Teraz możemy ustawić ilość pamięci (pamięć jest wyrażana w megabajtach)
+        oraz interfejs sieciowy.
+                 </p>
+<pre class="code-block">
+#Pamięć RAM:
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --memory 2048
+
+#Sieć NAT (jest ustawiana domyślnie podczas tworzeznia maszyny):
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --nic1 nat
+
+#Sieć Bridged:
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --nic1 bridged
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --bridgedadapter1 &lt;interfejs_sieciowy_komputera&gt;
+</pre>
+                 <p>
+                         Jeśli uruchamiamy maszynę gdzieś na serwerze i nie mamy dostępu do 
+        środowiska graficznego, wtedy możemy skorzystać z RDP. Jednak wymaga 
+        ono zainstalowania <strong>Oracle VM VirtualBox Extension Pack</strong>.
+                 </p>
+<pre class="code-block">
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --vrde on
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --vrdeport &lt;port_dla_vrde&gt;
+</pre>
+                 <p>
+                         Teraz możemy wystartować maszynę, jeśli korzystamy z serwera to należy 
+        ją uruchomić w headless.
+                 </p>
+<pre class="code-block">
+#Serwer zdalny bez GUI:
+$ vboxmanage startvm &lt;nazwa_maszyny&gt; --type headless
+#Normalna stacja robocza:
+$ vboxmanage startvm &lt;nazwa_maszyny&gt;
+</pre>
+           <p>
+                   Jeśli nie podamy goszczonego systemu podczas rejestracji (tworzenia
+        maszyny), to:
+      </p>
+                 <ul>
+                         <li>Dla systemu <strong>Windows</strong> należy ustawić te dwie rzeczy:
+<pre class="code-block">
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --chipset ich9
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --ioapic on
+</pre>
+                         </li>
+                           <li>Dla systemów <strong>BSD</strong> należy ustwić poniższą opcję:
+<pre class="code-block">
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --hwvirtex on
+</pre>
+                             Jednakże przy wirtualizcji sprzętowej należy pamiętać że, jeśli 
+            chcemy jej użyć musi być ona wspierana przez procesor oraz włączona
+            w BIOS.
+                     </li>
+                 </ul>
+      <p>
+      ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/tworzenie_szyfrowanych_archiwów_za_pomocą_7-zip.html b/articles/tnt/tworzenie_szyfrowanych_archiwów_za_pomocą_7-zip.html
new file mode 100755 (executable)
index 0000000..d3f6f1f
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Tworzenie szyfrowanych archiwów za pomocą 7-zip</h1>
+<pre class="code-block">
+$ 7z a -t7z -mhe=on -p&lt;hasło&gt; &lt;nazwa_archiwum&gt; &lt;plik/pliki/katalog&gt;
+</pre>
+                       <ul>
+                               <li><code class="code-inline">a</code> - utworzenie archiwum,</li>
+                               <li><code class="code-inline">-t7z</code> - ustawienie formatu archiwum jako 7-zip,</li>
+                               <li><code class="code-inline">-mhe=on</code> - szyfrowanie nagłówków, dzięki temu hasło będzie wymagane nawet do otwarcia archiwum,</li>
+                               <li><code class="code-inline">-p&lt;haslo&gt;</code> - hasło archiwum, używane do jego zaszyfrowania.</li>
+                       </ul>
+      <p>
+                         Reszta jest raczej czytelna i nie wymaga komentarza.
+                 </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/uruchomienie_kodu_JS_w_tle_innego_skryptu_JS.html b/articles/tnt/uruchomienie_kodu_JS_w_tle_innego_skryptu_JS.html
new file mode 100755 (executable)
index 0000000..26a394c
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Uruchomienie kodu JavaScript w tle innego
+        skryptu</h1>
+                 <p>
+                         Możemy użyć techiki tzw. <em>Workerów</em>. Poniżej znajduje się kod, 
+        ustawiono w nim interwał, który uruchamia tą funkcję co jakiś czas w 
+        tym przypadku jest 0,5 sekundy.
+                 </p>
+<pre class="code-block">
+//plik główny .js:
+var w = new Worker('&lt;plik_z_funkcją_działającą_w_tle&gt;');
+
+w.onmessage = function(e) {
+       //po uzyskaniu wyniku pracy funkcji w tle, zrób coś...
+}
+
+//plik z funkcją działającą w tle:
+
+function getMsgFromServer () {
+       //zrób cos ...
+       postMessage(wiadomosc_zwrotna);
+
+       //Uruchom funkcje po odczekaniu timeout-u 0,5 sek.
+       setTimeout("getMsgFromServer()", 500);
+}
+getMsgFromServer();
+</pre>
+    <p>
+      ~xf0r3m
+    </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/uruchomienie_ssh_na_raspberry_pi.html b/articles/tnt/uruchomienie_ssh_na_raspberry_pi.html
new file mode 100755 (executable)
index 0000000..3bff942
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Uruchomienie SSH na Raspberry Pi</h1>
+                 <p>
+                         Opcje są dwie. Kiedy urządzenie już działa możemy uruchomić SSH za 
+        pomocą polecenia <code class="code-inline">$ sudo raspi-config</code> 
+        -&gt; <code class="code-inline">5. Interfaceing Options</code> -&gt;
+        <code class="code-inline">P2 SSH</code> -&gt; 
+        <code class="code-inline">yes</code>.
+                 </p>
+                 <p>
+                         Drugim rozwiązaniem jest utworznie pustego plik o nazwie <em>ssh</em> 
+        na partycji <em>boot</em> karty pamięci.
+                 </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/ustawienie_kodowania_polskich_znaków_w_MySQL.html b/articles/tnt/ustawienie_kodowania_polskich_znaków_w_MySQL.html
new file mode 100755 (executable)
index 0000000..4fa41e0
--- /dev/null
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+                       </style>
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Ustawienie kodowanie polskich znaków w MySQL</h1>
+                 <p>
+                         Kodowanie polskich znaków możemy ustawić poprzez dopisanie kilku opcji 
+        w pliku konfiguracyjnym MySQL. Plik znajduje się na ścieżce 
+        <em>/etc/mysql/conf.d/mysql.conf</em>, oczywiście tam gdzie serwer baz 
+        danych to MySQL a nie MariaDB. W pliku dopisujemy następujące opcje.
+                 </p>
+<pre class="code-block">
+[mysql]
+default-character-set = utf8
+[mysqld]
+collation-server = utf8_polish_ci
+init-connect = 'SET NAMES utf8'
+character-ser-server = utf8
+</pre>
+                 <p>
+                         Restartujemy serwer.
+                 </p>
+<pre code="code-block">
+$ sudo systemctl restart mysql
+</pre>
+                 <p>
+                         Po zrestartowaniu serwera możemy sprawdzić ustawienia za pomocą dwóch 
+        poleceń.
+                 </p>
+<pre class="code-block">
+mysql&gt; SHOW VARIABLES LIKE 'char%'
+</pre>
+           <p>
+                   Powinniśmy zobaczyć, że każda zmienna jest ustawiona na 
+        <code class="code-inline">utf8</code>, poza jedną - ustawioną na 
+        <code class="code-inline">binary</code>.
+           </p>
+<pre class="code-block">
+mysql&gt; SHOW VARIABLES LIKE 'colla%'
+</pre>
+           <p>
+                   Pierwsza zmienna powinna mieć wartość 
+        <code class="code-inline">utf8_general_ci</code>, natomiast pozostałe 
+        <code class="code-inline">utf8_polish_ci</code>. Te zmiany spowodują 
+        wyświetlanie polskich znaków w konsoli MySQL. Także pozwolną na użycie 
+        modyfikatorów <code class="code-inline">ORDER BY</code> z polskimi 
+        znakami w operandach.
+      </p>
+      <p>
+        Źródło: Internet.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/ustawienie_protokołu_VNC_dla_maszyn_VirtualBox_uruchamianych_w_trybie_headless.html b/articles/tnt/ustawienie_protokołu_VNC_dla_maszyn_VirtualBox_uruchamianych_w_trybie_headless.html
new file mode 100755 (executable)
index 0000000..001ac7d
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Ustawienie protokołu VNC dla maszyn VirtualBox uruchamianych w trybie headless</h1>
+                 <p>
+                         W przypadku zdalnych ekranów maszyn <em>VirtualBox</em> najważniejsze 
+        to posiadać zainstalowany <strong>VNC Extension Pack</strong> na 
+        komputerze, który tą maszynę uruchomił. W przeciwym wypadku maszynę 
+        należy wyłączyć a następnie zainstalować paczkę rozszerzeń 
+        <strong>Oracle VM VirtualBox Extension Pack</strong> i użyć protoku 
+        RDP, który wymaga do konfiguracji jedynie dwóch pierwszych poleceń 
+        czyli włączenia samego zdalnego dostępu oraz wybrania portu, 
+        oczywiście istnieje możliwość zabezpieczenia dostępu hasłem, w 
+        przeciwnym wypadku uwierzytelnienie działa na zasadzie kto pierwszy 
+        ten lepszy.
+                 </p>
+<pre class="code-block">
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --vrde on
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --vrdeport &lt;port_rdp/vnc&gt;
+$ vboxmanage modifyvm &lt;nazwa_maszyny&gt; --vrdeproperty VNCPassword=&lt;hasło_dla_połaczenia&gt;
+</pre>
+                 <p>
+                         Po wykonaniu tych poleceń możemy uruchomić maszynę wirtualną. Do 
+        połączenia możemy wykorzystać np. program <em>Remmina</em>, który jest 
+        standardowym pakietem, odpowiedzialnym za połączenia RDP oraz VNC w 
+        systemach GNU/Linux. Wybieramy protokół, przez który będziemy się 
+        łączyć z maszyną. Następnie w adresie serwera podajemy adres IP, 
+        komputera który uruchomił maszynę lub localhost, po dwukropku 
+        (<strong>:</strong>) port. Podczas zestawiania połączenia zostaniemy 
+        zapytani o zdefiniowane w ostatnim poleceniu hasło, o ile użyliśmy VNC.
+                 </p>
+      <p>
+        Źródło: Internet
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/usunięcie_tablicy_RAID_madm.html b/articles/tnt/usunięcie_tablicy_RAID_madm.html
new file mode 100755 (executable)
index 0000000..696018b
--- /dev/null
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Usunięcie tablicy RAID madm</h1>
+                 <p>
+                         Żeby usunąć tablicę RAID musimy na początku 
+        <strong>zatrzymać urządzenie RAID</strong> za pomocą poniższego 
+        polecenia.
+                 </p>
+<pre class="code-block">
+$ sudo mdadm --stop &lt;urządzenie_RAID&gt;
+</pre>
+                 <p>
+                         Teraz możemy zainicjować dysk za pomocą polecenia 
+        <code class="code-inline">fdisk</code>, sformatować partycję i zacząć 
+        z niej korzystać.
+                 </p>
+<pre class="code-block">
+$ sudo fdisk /dev/sdb
+&gt; o
+&gt; n
+&gt; p
+&gt; [ENTER]
+&gt; [ENTER]
+&gt; [ENTER]
+&gt;  w
+&gt; quit
+
+$ sudo mkfs.ext4 /dev/sdb1
+
+$ sudo mount /dev/sdb1 /mnt
+</pre>
+      <p>
+        Źródło: Internet
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/użycie_polecenia_rsync_w_PHP.html b/articles/tnt/użycie_polecenia_rsync_w_PHP.html
new file mode 100755 (executable)
index 0000000..e4a25dd
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Użycie polecenia rsync w PHP</h1>
+                 <p>
+                         Użyć polecenia rsync możemy za pomocą instrukcji 
+        <code class="code-inline">exec()</code>, wartością zwracaną przez tą 
+        instrukcje są dane wyjściowe polecenia.
+                 </p>
+                 <p>
+                         W celu uruchomienia polecenia <code class="code-inline">rsync</code>, 
+        należy pamiętać o wymianie kluczy między stronami oraz o tym aby 
+        użytkownik <em>www-data</em> posiadał w swoim katalogu domowym 
+        (zazwyczaj <em>/var/www</em>) katalog <em>.ssh</em> z kluczami. Katalog
+        ten powinien mieć ustawionego właściciela na <em>www-data</em> oraz 
+        odpowienie uprawnienia (<em>644</em>, dla katalogu, <em>600</em> dla 
+        klucza prywatnego [plik bez rozszerzenia .pub]). Warto również użyć 
+        kilku opcji SSH (przez SSH <code class="code-inline">rsync</code> 
+        łączy się z serwerem) takich jak 'StrictHostKeyChecking' ustawione na 
+        'no' (<code class="code-inline">StrictHostKeyChecking=no</code>) oraz 
+        'UserKnowHostFile' ustawione na <em>/dev/null</em> 
+        (<code class="code-inline">UserKnownHostsFile=/dev/null</code>)
+                         Aby w ogóle użyć opcji SSH w <code class="code-inline">rsync</code>, 
+        należy użyć przełącznika <code class="code-inline">-e</code> jako 
+        wartość tej opcji w podwójnych apostrofach podaje się polecenie 
+        <code class="code-inline">ssh</code> gdzie, każdą z opcji podaje się 
+        po przełączniku <code class="code-inline">-o</code>.
+                 </p>
+<pre class="code-block">
+exec('rsync -re \"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" &lt;katalog_lokalny&gt; &lt;użytkownik_zdalny&gt;@&lt;adres_ip_serwera&gt;:&lt;katalog_zdalny&gt;');
+</pre>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/zabezpieczenie_dostępu_RDP_do_maszyn_VirtualBox_hasłem.html b/articles/tnt/zabezpieczenie_dostępu_RDP_do_maszyn_VirtualBox_hasłem.html
new file mode 100755 (executable)
index 0000000..a3b4c2d
--- /dev/null
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+
+               <div class="main">
+      <h1 class="title">Zabezpieczenie dostępu RDP do maszyny VirtualBox hasłem</h1>
+                 <p>
+                   Na wyłączonej maszynie musimy ustawić poniższe opcje:
+                 </p>
+<pre class="code-block">
+vboxmanage setproperty vrdeauthlibrary "VBoxAuthSimple"
+vboxmanage modifyvm "&lt;nazwa_vm&gt;" --vrdeauthtype external
+vboxmanage internalcommands passwordhash &lt;hasło&gt;
+vboxmanage setextradata "&lt;nazwa_vm&gt;" "VBoxAuthSimple/users/&lt;nazwa_użytkownika&gt;" &lt;hash&gt;
+</pre>
+                 <p>
+                   Gdzie:
+      </p>
+                 <ul>
+                         <li><code class="code-inline">nazwa_użytkownika</code> - Możemy podać 
+          dowolny ciąg znaków. Ta wartość będzie sprawdzana z polem
+                                 "nazwa użytkownika" programu, z którego bedziemy się łączyć z maszyną.</li>
+                         <li><code class="code-inline">hash</code> - hash wygenerowany przez 
+          polecenie 
+                                 <code class="code-inline">vboxmanage internalcommands passwordhash
+          &lt;hasło&gt;</code></li>
+                 </ul>
+      <p>
+                   Jeśli wcześniej nie uruchamialiśmy maszyn z <em>VRDE</em> to upewnijmy 
+        się najpierw, że mamy zainstalowany <em>Extension Pack</em>. Po wydaniu
+        tych poleceń możemy uruchamiać maszynę. Więcej informacji odnośniku
+        źródłowym.
+                 </p>
+                 <p>
+                   Programy, przez które będzimy się łączyć z maszyną mogą nie zwrócić 
+        monitu o dane uwierzytelniające. Wyświetlą jedynie informacje o tym,
+                   że nie udało się połączyć z danym serwerem. Wtedy należy utworzyć 
+        profil połączenia, i z tego poziomu powinno się już połączyć 
+        (przynajmniej tak jest na <em>Remminie</em> na GNU/Linux Debian).
+                 </p>
+      <p>
+        Źródło:
+        <ol>
+          <li><a href="https://www.virtualbox.org/manual/ch07.html#vbox-auth">
+        Podręcznik VirtualBox (dokumentacja)</a></li>
+        </ol>
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/articles/tnt/zwrot_wartości_logicznej_dla_sparsowanego_zapytania_SQL_w_PHP.html b/articles/tnt/zwrot_wartości_logicznej_dla_sparsowanego_zapytania_SQL_w_PHP.html
new file mode 100755 (executable)
index 0000000..af1bccb
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+       <html>
+               <head>
+                       <meta charset="utf-8" />
+                       <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+                       <link rel="stylesheet" type="text/css" href="/style.css">
+               </head>
+               <body>
+<pre>
+  _______            ___   ______     _      __
+ /_  __(_)___  _____( _ ) /_  __/____(_)____/ /_______
+  / / / / __ \/ ___/ __ \/|/ / / ___/ / ___/ //_/ ___/
+ / / / / /_/ (__  ) /_/  &lt;/ / / /  / / /__/ ,&lt; (__  )
+/_/ /_/ .___/____/\____/\/_/ /_/  /_/\___/_/|_/____/
+     /_/
+</pre>
+
+               <p class="header_link">
+                       &#9760;&nbsp;<a href="https://morketsmerke.github.io/">morketsmerke</a>&nbsp;&#9760;
+               </p>
+               <div class="main">
+      <h1 class="title">Zwrot wartości logicznej dla sparsowanego zapytania SQL w PHP</h1>
+                 <p>
+                         Instrukcja <code class="code-inline">sprintf</code> zwraca 
+        <em>FALSE</em>, w razie błedu podczas parsowania. Najczęstszą przyczyną
+        jest za mało lub za dużo o jeden format 
+        (<code class="code-inline">%s</code>) albo argument 
+        (<code class="code-inline">mysqli_real_escape_string($connection, ...)</code>).
+                 </p>
+      <p>
+        Źródło: Internet.
+      </p>
+      <p>
+        ~xf0r3m
+      </p>
+               </div>
+               <p class="footer">
+                       2022; COPYLEFT; ALL RIGHTS REVERSED;
+               </p>
+               </body>
+       </html>
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..0434438
--- /dev/null
@@ -0,0 +1,227 @@
+<!DOCTYPE html>
+<html>
+       <head>
+               <meta charset="utf-8" />
+               <link rel="icon" type="image/png" href="https://i.ibb.co/khy45hh/mm.png">
+               <link rel="stylesheet" type="text/css" href="style.css">
+       </head>
+       <body>
+<pre>
+                        __        __                           __
+   ____ ___  ____  _____/ /_____  / /__________ ___  ___  _____/ /_____
+  / __ `__ \/ __ \/ ___/ //_/ _ \/ __/ ___/ __ `__ \/ _ \/ ___/ //_/ _ \
+ / / / / / / /_/ / /  / ,< /  __/ /_(__  ) / / / / /  __/ /  / ,< /  __/
+/_/ /_/ /_/\____/_/  /_/|_|\___/\__/____/_/ /_/ /_/\___/_/  /_/|_|\___/
+
+</pre>
+               <div class="main">
+                       <p class="links">
+                               <a href="articles/linux/index.html">linux</a>
+                               <a href="articles/bsd/index.html">bsd</a>
+                               <a href="articles/raspberrypi/index.html">raspberry pi</a>
+                               <a href="articles/terminallog/index.html">terminallog</a>
+                               <a href="articles/tnt/index.html">tips&amp;ticks</a>
+        <a href="articles/immudex/index.html">immudex - docs</a>
+        <a href="https://github.com/xf0r3m">git</a>
+        <a href="articles/immudex/immudex.html">immudex</a>
+                       </p>
+      <p>&nbsp;</p>
+      <p>
+        <strong>Changelog</strong>:
+      </p>
+                       <ul class="reduced-list">
+        <li> 14.04.2023 - Utworzenie kategorii dla dokumentacji Immudex</li>
+        <li> 23.12.2022 - Dodanie "Instalacja własnościowego sterownika graficznego Nvidii na Debian 11"</li>
+        <li> 10.12.2022 - Zmiana layoutu dużych materiałów na terminallog</li>
+        <li> 10.12.2022 - Odświerzenie artykułu 'Ściąga z PYTHONga'</li>
+        <li> 10.09.2022 - Dodanie "Python. Ćwiczenia." na terminallog</li>
+             <li> 01.09.2022 - Wydanie immudex w wersji 0.0.0</li>
+        <li> 01.09.2022 - Dodanie "Red Hat Enterprise Linux 9 - RHCSA" na terminallog</li>
+        <li> 24.07.2022 - Dodanie "Uruchomienie skryptu podczas ładowania systemu - jednostka systemd"</li>
+        <li> 20.05.2022 - Dodanie "Przenoszenie systemu operacyjnego z maszyny wirtualnej na fizyczny komputer"</li>
+        <li> 15.05.2022 - Zmiana FAQ na Tips&amp;Tricks</li>
+        <li> 13.05.2022 - Dodanie "Podłączanie 7-calowego ekranu dotykowego (1024x600) do Raspberry Pi"</li>
+        <li> 07.05.2022 - Przeniesienie strony na adres https://morketsmerke.github.io</li>
+        <li> 06.05.2022 - Wydanie greenOS 1.4</li>
+        <li> 05.05.2022 - Zmiany w greenOS. Wydanie wersji greenOS 1.3 (btw i use Arch)</li>
+        <li> 27.04.2022 - Wydanie OTP w wersji 1.0.5</li>
+        <li> 17.04.2022 - Wydanie OTP w wersji 1.0.4</li>
+        <li> 16.04.2022 - Wydanie OTP w wersji 1.0.3</li>
+        <li> 31.03.2022 - Przeniesienie strony na inny serwer. Powrót do domeny morketsmerke.net. Home Sweet Home.</li>
+        <li> 29.03.2022 - Test GitHub CLI</li>
+        <li> 27.03.2022 - Wydanie greenOS greenServer</li>
+        <li> 27.03.2022 - Wydanie wersji greenOS 1.2</li>
+        <li> 27.02.2022 - Usunięcie dotychczasowej serii "Jak działa Linux". Wymaga ona przeredagowania.</li>
+        <li> 13.02.2022 - Wydanie OTP w wersji 1.0.2</li>
+        <li> 13.02.2022 - Wydanie greenOSTe 9.0.1</li>
+        <li> 11.02.2022 - Upublicznienie archiwum z greenOSAE</li>
+        <li> 11.02.2022 - Przeniesienie danych z ftp.morketsmerke.net na serwis sourceforge.net oraz aktualizacja adresów odnośników na stronie greenOS</li>
+        <li> 30.01.2022 - Wydanie greenOS Ratpoison</li>
+        <li> 30.01.2022 - Wydanie greenOS 1.1</li>
+        <li> 22.01.2022 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+        <li> 07.01.2022 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+        <li> 04.01.2022 - Dodanie "linux/Szyfrowany rootfs na greenOSTe"</li>
+        <li> 30.12.2021 - Wydanie pierwszej wersji greenOS Trisquel edition (Torwards the sun)</li>
+        <li> 23.12.2021 - Dodanie "Szyfrowany rootfs na greenOS"</li>
+        <li> 22.12.2021 - Wydanie OTP w wersji 1.0.1</li>
+        <li> 19.12.2021 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+       <li> 12.12.2021 - Wydanie pierwszej wersji OTP o nazwie kodowej "Wise choice".</li>
+        <li> 06.12.2021 - Rozpoczęcie prac nad OTP.</li>
+        <li> 05.12.2021 - Reaktywacja projektu greenOS (Wydanie wersji 1 [Torwards the sun])</li>
+        <li> 18.11.2021 - Dodanie kolejnego rodziału do serii "Jak działa Linux?"</li>
+        <li> 14.11.2021 - Update materiału "Parabola GNU/Linux-libre"</li>
+        <li> 12.11.2021 - Dodanie "Parabola GNU/Linux-libre"</li>
+        <li> 28.10.2021 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+        <li> 15.10.2021 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+       <li> 03.10.2021 - Dodanie kolejnego rozdziału do serii "Jak działa Linux?"</li>
+       <li> 26.09.2021 - Przeniesie morketsmerke.net na morketsmerke.github.io</li>
+        <li> 24.09.2021 - Zwieszenie wsparcia dla greenOS</li>
+        <li> 19.09.2021 - Dodanie "greenOSAE"</li>
+        <li> 05.09.2021 - Dodanie "Raspberry Pi jako przekaźnik bluetooth"</li>
+        <li> 03.09.2021 - Dodanie "Instalacja systemu z własnego obrazu LiveCD z Debianem"</li>
+        <li> 02.09.2021 - Dodanie "Własne LiveCD z Debianem"</li>
+        <li> 21.08.2021 - Wydanie pierwszej oficjalnej wersji greenOS</li>
+        <li> 30.07.2021 - Dodanie "GNU mailutils jako program mailowy"</li>
+        <li> 29.07.2021 - Dodanie "Raspberry Pi jako serwer poczty"</li>
+       <li> 30.06/01.07.2021 - Uruchomienie mirroru Debiana dla stable, oldstable dla architektur amd64 oraz i386</li>
+       <li> 12-13.06.2021 - Rozpoczęcie prac nad greenOS</li>
+        <li> 08.06.2021 - Rozpoczęcie serii materiałów "Jak działa Linux?"</li>
+        <li> 15.05.2021 - Uaktualnienie "Laboratorium sieci VPN".</li>
+        <li> 15.05.2021 - Dodanie "Sieci VPN" na terminallog.</li>
+       <li> 07.05.2021 - Dodanie "Konfiguracja HAProxy dla HTTP oraz HTTPS" na terminallog.</li>
+       <li> 05.05.2021 - Aktualizacja FAQ.</li>
+       <li> 03.05.2021 - Zmiany w "lost+found".</li>
+       <li> 02.05.2021 - Dodanie "20 letni Sun Netra T1 jako serwer mailowy z wykorzystaniem NetBSD".</li>
+       <li> 30.04.2021 - Dodanie "Instalacja NetBSD".</li>
+       <li> 11.04.2021 - Dodanie "Dziennika OpenBSD".</li>
+       <li> 04.04.2021 - Zakończenie prac nad obecną formą strony.</li>
+       <li> 26.03.2021 - Zakończenie przenoszenia treści na nową wersję strony.</li>
+       <li> 01.11.2020 - Przenosiny zakończone, utworzenie frontpage-a morketsmerke.net.</li>
+       <li> 28.10.2020 - Rozpoczęcie przenosin na inny sprzęt.</li>
+       <li> 19.10.2020 - Rozpoczęcie redagowania artykułu Bash Bushido dla terminallog.</li>
+       <li> 16.10.2020 - Rozpoczęcie przenoszenia treści na nową wersję strony.</li>
+       <li> 15.10.2020 - Utworznie statycznych podstron dla katalogów.</li>
+       <li> 14.10.2020 - Rozpoczęcie tworzenia nowej odsłony strony morketsmerke.net.</li>
+                       </ul>
+      <p><strong>Ostatnie zmiany w projektach</strong>: <a href="https://github.com/xf0r3m">https://github.com/xf0r3m</a></p>
+      <ul id="chprojects" class="reduced-list" style="height: 100px;">
+        <li>immudex-testing - 9096680 - <a href="https://github.com/xf0r3m/immudex-testing/commit/90966802fd753b0da1f4934ed658affc191060a0">Publikacja immudex-testing w wersji 1.0.5</a></li>
+        <li>immudex - 50d2aeb - <a href="https://github.com/xf0r3m/immudex/commit/50d2aeb69f6a46a53a0ab3291ef571725ceaeb31">Publikacja immudex w wersji 1.0.1</a></li>
+        <li>bugtrack - 877c5e1 - <a href="https://github.com/xf0r3m/bugtrack/commit/877c5e12b0508b69d8c29a1057a888a6a56267da">Minimalna wielkość pola zmiany statusu - BT #82</a></li>
+        <li>morketsmerke-dev - f0ce6fc - <a href="https://github.com/morketsmerke/morketsmerke-dev/commit/f0ce6fc07ed22cfa91f3fdde5359f0f84fdecc82">Zakończenie tworzenia 9 rozdziału. Przekazanie do przeredagowania</a></li>
+      </ul> 
+      <p><strong>Ostatnie zgłoszenia w serwisie BugTrack</strong>: <a href="https://bugtrack.morketsmerke.org">https://bugtrack.morketsmerke.org</a></p>
+      <ul id="chbugtrack" class="reduced-list" style="height: 100px;">
+        <li><a href="https://bugtrack.morketsmerke.org/?p=comments&bid=87">#87</a> - immudex-lhe - problem - immudex_hostname</li>
+        <li><a href="https://bugtrack.morketsmerke.org/?p=comments&bid=86">#86</a> - immudex-lhe - problem - immudex_crypt - nie można okeślić systemu plików.</li>
+        <li><a href="https://bugtrack.morketsmerke.org/?p=comments&bid=85">#85</a> - immudex-lhe - problem - pl - spacja przy linku</li>
+        <li><a href="https://bugtrack.morketsmerke.org/?p=comments&bid=83">#83</a> - immudex-testing - ulepszenie - create_media - nuke</li>
+      </ul>
+      <p>&nbsp;</p>
+      <p>
+        <strong>O mnie</strong></li>
+      </p>
+               <div>
+               <img src="https://i.ibb.co/D9CYmS5/mm-lb.png" style="display: block; float: left;" />
+               <p> 
+           Cześć, mam imię Jakub i jestem entuzajstą systemów uniksopodobnych,
+        serwerów (zarówno fizycznych maszyn jak i demonów) oraz różnych 
+        dziwnych
+        rozwiązań komputerowych jak np. cienkie klienty. Żaden ze mnie
+        <em>sysadmin</em>. Ta strona jest przedłużeniem mojej pamięci i
+        powstała w jednym celu - zapisać wszystko z czym miałem styczność
+        podczas moich zabaw z komputerami (if u know what i mean ;)). Często
+        korzystałem z różnych źródeł próbując coś sobie skonfigurować na
+        Linuksie czy innym Uniksie i zawarte tam informacje nie zawsze były 
+        trafne, akurat w moim przypadku. (Oczywiście!) Dlatego też zamiast
+        15 minut, spędzałem nad nią kilka godzin.
+        Kiedy już osiągnąłem cel, doszedłem do wniosku że tyle pracy nie może
+        przecież pójść na marne i zacząłem te swoje rozwiązania spisywać
+        do plików .txt. Później wpadłem na pomysł, że przecież mogę utworzyć
+        bloga i tam wszystko umieszczać. Ta strona miała kilka wersji,
+        charakteryzujących się różnorakim <em>designem</em>, <em>layoutem</em>. 
+       czy rozwiązaniem. Ta jest wersją 6. Czy ostateczną? Tego niewiadomo.
+        Sądząc po tym jak szybko się nudze i jak bardzo nie służy mi stagnacja
+        z dużym prawdopodobieństwem chyba nie.
+      <!--
+                Po chyba pięciu wersjach jest... Najbardziej hakerska wersja tej strony. 
+                Wygląda jakby autorowi ewidentnie się nie chciało. Chociaż dzisiaj w 
+                czasach ogólnej, ekscytującej brzydoty design ukradziony z pierwszych 
+                stron sieci World Wide Web, gdzie dzieciaki przenosiły to co widziały 
+                na BBS, pójdzie to nawet na tosterze na ziemiaki. Szczerze żałuje, że 
+                nie urodziłem się wcześniej. Żałuje że, nie dorastałem w raz rodzącymi 
+                się w bólach globalnymi sieciami, chociaż czy wtedy dorastając w takim 
+                samym środowisku potrafiłbym myśleć w podobny sposób jak dzisiaj? Może
+                kierowałbym się innymi wartościami? To jest tylko wypełniacz. Oryginalne
+                Lorem Ipsum. Tutaj wpisz przykładowy tekst.</li>
+                 </li>
+                ~xf0r3m
+      -->
+                       </p>
+               </div>
+      <p>
+        Materiały tutaj zamieszczone, tworzę wyłącznie z myślą o sobie samym.
+        Materiały są pełne literówek, błędów językowych, gramatycznych czy 
+        ortograficznych (spędzając wiecej czasu w książkach o Linuksie czy
+        jezykach oprogramowania nabawiłem się chyba jakiejś dysleksji, może te
+        akapity uda się napisać poprawnie).
+        Te można sobie darować, jednak pracuje nad tym aby każdy materiał był
+        jak najbardziej merytoryczny i zawierał jak najmniej tego typu błędów.
+        Jednym słowem grafomania. Materiały zawarte na tej stronie są publikowne
+        w oparciu o <em>copyleft</em>. (Nie chce mi się przytaczać pełnej nazwy
+        tej licencji. Nawet jej nie znam. W kwestajach licencyjnych jestem
+        straszym ignoratem, liczą się tylko te najbardziej liberalne jak
+        <em>GPL</em> [zaraz i tak się dowiem, że GPL nie jest, aż tak mocno
+        liberalna], zatem moją licencje mogę określić mianem JCh - "Bierzcie i
+        korzystajcie z tego wszyscy, to jest moja praca wydana na wieki 
+        wieków", wszystkie inne licencje ograniczające użytkownika to ściek.)
+        Dlatego też śmiało można korzystać ze wszystkich materiałów tutaj
+        umieszczonych. Nie obiecuje, że ta strona będzie komukolwiek przydatna,
+        ale jak już jesteście to siadajcie. Brawo dotarłeś do końca internetu.
+      </p>
+      <p>
+       Jakby ktoś potrzebował kontaktu ze mną, to znajdzie go pod tym
+       adresem mailowm: <a href="mailto:xf0r3m@gmail.com">itaktegonieodczytam@gmail.com</a>.
+      </p>
+                       <p>&nbsp;</p>
+                       <p>
+                               <strong>Oznaczenia tekstu stosowane w materiałach:</strong><br />
+        <em>(autor zastrzega sobie możliwość niestosowania się do poniższych
+        reguł)</em>
+                       </p>
+                       <ul>
+                               <li>
+<pre class="code-block">
+# rcctl enable dnsmasq
+</pre>
+                                       (<strong>&lt;pre class=".code-block"&gt;&lt;/pre&gt;</strong>) - bloki kodu; 
+                    zawartość plików konfiguracyjnych powyżej jednej linii; informacje zwracane 
+                    przez programy,
+                               </li>
+                               <li>
+                                       <code class="code-inline">rcctl enable dhcpd</code>
+                                       (<strong>&lt;code class="code-inline"&gt;&lt;/code&gt;</strong>) - fragmenty 
+                    bloków oznaczonych klasą <em>.code-block</em>; pojedyńcze linie poleceń lub 
+                    linie plików konfiguracyjnych oraz ewentualne ich fragmenty użyte w innych 
+                    elementach niż te opisane powyższą klasą; informacje zwracane przez programy 
+                    wykorzystane w akapitach,
+                </li>
+                               <li><strong>&lt;em&gt;&lt;/em&gt;</strong> - wyrazy obce; nazwy programów; scieżki; 
+                    nazwy plików,
+                </li>
+                               <li><strong>&lt;strong&gt;&lt;/strong&gt;</strong> - przedstawienia znaków; 
+                    szczególny nacisk na fragmenty tekstu; pierwsze wystąpienie frazy w 
+                    przeznaczonym dla niej fragmencie tekstu.
+                </li>
+        <li><strong>&lt;u&gt;&lt;/u&gt;</strong> - nałożenie nacisku na termin
+                    mniej istotny niż znacznik <em>strong</em>
+                </li>
+                       </ul>
+                       </div>
+                       <p>&nbsp;</p>
+                       <p class="footer">
+                               2023; COPYLEFT; ALL RIGHTS REVERSED;
+                       </p>
+
+               </body>
+       </html>
diff --git a/style.css b/style.css
new file mode 100644 (file)
index 0000000..a6238ec
--- /dev/null
+++ b/style.css
@@ -0,0 +1,137 @@
+body {
+       background-color: #282828;
+       color: #c7cbd0;
+       font-family: monospace;
+       font-size: 13pt;
+}
+
+.code-block {
+       display: block;
+       background-color: #353535;
+       font-family: monospace;
+       font-weight: bolder;
+}
+
+.code-inline {
+       background-color: #353535;
+       font-family: monospace;
+       font-weight: bolder;
+}
+
+p {
+       text-align: justify;
+}
+
+.main {
+       margin-left: auto;
+       margin-right: auto;
+       width: 80%;
+}
+
+.links {
+       margin: 0;
+       padding: 0;
+       outline: 0;
+       font-size: 14pt;
+}
+
+.header_link {
+       margin: 15px;
+       padding: 0;
+       outline: 0;
+       font-size: 18pt;
+}
+
+.special_list {
+       list-style-type: none;
+       font-size: 14pt;
+}
+
+.title {
+       text-align: center;
+}
+
+td { 
+       border-bottom: 1px solid #c7cbd0;
+}
+
+th {
+       border-top: 1px solid #c7cbd0;
+       border-bottom: 1px solid #c7cbd0;
+}
+
+a:link {
+       color: #5555ff;
+}
+
+.footer {
+       margin: 15px;
+       padding: 0;
+       outline: 0;
+}
+
+.toc {
+  list-style-type: none;
+}
+
+.mainToc {
+  padding-left: 0;
+}
+
+#tableOfContent {
+  width: 38%;
+  height: 100vh;
+  float: left;
+  overflow: scroll;
+  padding-right: 1%;
+  margin-left: 1%;
+}
+
+#content {
+  width: 56%;
+  height: 100vh;
+  float: left;
+  overflow: scroll;
+  margin-left: 2%;
+  padding-right: 1%;
+}
+
+#contentHeader {
+  width: 100%;
+  float: left;
+}
+
+#contentHeaderLink {
+  float: left;
+  padding-left: 5%;
+  padding-top: 5%;
+}
+
+#divisionBaner {
+  font-size: 9pt;
+  float: left;
+}
+
+.warn-sign {
+  font-weight: bold;
+}
+
+.notice { color: black; }
+.warning { color: red; }
+
+.reduced-list {
+  overflow-y: scroll;
+  height: 150px;
+}
+
+.centered-text {
+  text-align: center;
+}
+
+.lefted-text {
+  text-align: left;
+}
+
+.no-border {
+  border: hidden;
+}