Cvičení: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14.

Toto a následující cvičení se zaměřuje na správcovské úlohy. Obsahuje absolutní minimum potřebné pro správu vašeho Linuxového stroje. Ale obsahuje i pár bonusů, které se mohou hodit do shellových skriptů.

Většina věcí zde popsaných vyžaduje vlastní Linuxovou instalaci, protože potřebují práva superuživatele. Nebudou fungovat na sdílených strojích v IMPAKTu.

Nezapomeňte, že Čtení před cvičením je povinné a je z něj kvíz, který musíte vyplnit před cvičením.

Čtení před cvičením

Uživatelé a root

Tohoto tématu jsme se už párkrát dotkli, ale radši jej ještě jednou shrneme.

Mezi uživatelskými účty na Linuxu má jeden z nich výsadní postavení. Tento uživatel se jmenuje root (často též superuser nebo superuživatel), má číselný kód 0 a má v podstatě neomezená oprávnění nad běžícím strojem. Například, přístupová práva jsou ve skutečnosti ignorována pro uživatele root (tj. proces běžící pod rootem ignoruje libovolné z rw oprávnění a může číst/zapisovat libovolný soubor).

Na rozdíl od jiných systémů, Linux je navržen tak aby uživatelské programy mohly vždy běžet pod normálním (obyčejným) uživatelem a nevyžadovaly rootovská oprávnění. Dokonce, některé programy (často se to týkalo třeba IRC klientů) se pod rootem odmítaly spustit.

Účet root je vyžadován pro změny v systému jako celku. To zahrnuje aktualizaci systému, formátování pevného disku nebo třeba modifikaci systémové konfigurace.

Velmi striktní oddělené běžných (pracovních) účtů a superuživatele vychází z faktu, že Linux byl navržen jako víceuživatelský systém. Tato filozofie je více jak 50 let stará a sahá do doby, kdy počítač byl sdílen mnoha uživateli a jen jeden z nich – root – byl administrátorem. Dnes, kdy typická notebooková instalace je právě pro jednoho uživatele, je toto rozdělení spíš umělé, ale pořád existuje.

Pravdou je, že dnešní uživatel je více ohrožen napadenou webovou stránku spíše než neoprávněnou aktualizací systému a účet superuživatele byl navržen spíše s ohledem na to druhé. Nicméně, idea oddělených účtů dává stále smysl a obezřetný uživatel může používat různé účty pro různé aktivity (např. prohlížení sociálních sítí a práce s on-line bankovnictvím).

sudo

Některé programy vyžadují zvýšení svých oprávnění (privilege escalation), tj. běžet s většími pravomocemi než ostatní programy. Některé to vyžadují svojí podstatou a už jsme zmiňovali set-uid bity na spustitelných souborech, které jsou použity u aplikací, které vždy vyžadují vyšší práva (bez ohledu na to, kdo je jak spustil). Ale set-uid bit se nehodí, pokud chceme jen někomu umožnit pustit daný program s vyšším oprávněním. Navíc, některé programy vyžadují vyšší oprávnění jen občas. A pak nedává smysl zbytečně zvyšovat možnost napadení tím, že ho budou mít vždy.

Pro tyto situace je jedním z možných řešení sudo (domovská stránka). Jak jméno napovídá, provádí jeden příkaz (superuser do) s oprávněními superuživatele. Výhodou sudo je, že administrátor může určit který příkaz poběží s vyšším oprávněním. Takže nedává vybraným uživatelům kompletní kontrolu nad počítačem, ale pouze jim umožňuje pracovat s vybranou množinou příkazů. Například je možné jednomu uživateli dát možnost restartovat určitou službu (např. chceme testerovi umožnit restartovat webový server) ale větší kontrolu nad strojem mu svěřit nechceme.

Všimněte si, že granularita sudo je na úrovni programů. Neomezuje, jak se program chová uvnitř. Například, je možné omezit, že uživatelka alice může spustit nebezpecny_prikaz pouze s přepínačem --neskodny-prepinac. Ale, pokud nebezpecny_prikaz také čte konfiguraci ze souboru ~/.nebezpecnyrc, alice může skrz něj přidat volbu --nebezpecna-volba. A sudo tomu nemá jak zabránit. Jinými slovy: jakmile jsou počáteční kontroly (před spuštěním) dokončeny, program se chová jako by ho spustit uživatel root.

Tohle je velmi důležité pro sdílené stroje, kde administrátor chce typicky omezit ostatní uživatele jak nejvíce to jde. Na druhou stranu, na desktopových (notebookových) instalacích, obvyklé nastavení je, že první vytvořený uživatel (typicky vytvořený ještě během instalace) může spustit libovolný program se sudo. Zdůvodnění je takové, že existuje stejně pouze jeden (fyzický) uživatel, který stejně rootovské heslo zná. To je také důvod, proč většina návodů na webu obvykle uvádí příkazy pro správu systému včetně sudo na začátku každého příkazu.

Měli byste ale vždy vědět, proč sudo pouštíte. Nechyťte se do pasti zvyku, že když to nefunguje, zkusím to pustit se sudo. Mimochodem, možností jak získat rootovský shell je více (např. sudo bash).

sudo není jediným bezpečnostním mechanismem. Ostatními se nebudeme do detailů zabývat, ale uvedeme alespoň odkazy na SELinux nebo AppArmor. Shrnutí mechanismů je k dispozici též na Wikipedie.

Správa balíčků

Software v Linuxu je obvykle instalován prostřednictvím správce balíčků (package manager). Správce balíčků je speciální program, které se postará o instalaci, upgrade i odstranění balíčků. Balíček může být cokoliv, co lze nainstalovat; to zahrnuje:

  • programy (například, balíček ranger nainstaluje program ranger),
  • datové soubory a nastavení (např. libreoffice-langpack-cs pro podporu češtiny v LibreOffice),
  • knihovna (třeba gmp nebo gmp-devel poskytují GNU knihovnu pro libovolně přesné výpočty),
  • nebo tzv. meta balíček (např. xfce zahrnuje xfce4-terminal, xfwm4-themes atd.).

V tomto směru je Linux velmi podobný tomu, co znáte ze správy softwaru styl obchoďák na vašich chytrých telefonech. Je velmi neobvyklé instalovat software na Linuxu prostřednictvím grafického instalátoru.

Výhodou centrální správy balíčků je možnost upgradovat celý systém, aniž by bylo nutné kontrolovat samostatně jednotlivé aplikace.

Jednotlivé balíčky mají často závislosti (dependencies) – instalace jednoho balíčku způsobí tranzitivní instalaci ostatních balíčků, na kterých závisí (na příklad, webový prohlížeč bude vyžadovat základní podporu GUI apod.). To trochu komplikuje proces aktualizací (pro správce balíčků, naštěstí nikoliv pro uživatele). Ale ušetří to trochu místa na disku. Asi nejdůležitější výhodou je, že různé aplikace mohou sdílet stejné knihovny (na Linux mají příponu .so a jsou podobné souborům DLL na Windows). Takže je možné upgradovat knihovnu i dále nevyvíjené aplikaci. Což se velmi hodí, pokud knihovna obsahuje bezpečnostní záplatu.

Je pochopitelně možné instalovat software i ručně. Z pohledu souborového systému je to jedno – správce balíčků v podstatě jen kopíruje soubory do správných adresářů. Ale ručně nainstalovaný software musí být i ručně aktualizován a věci spíš komplikuje. Takže se tomu pokud možno vyhýbejte.

Typický správce balíčků pracuje s několika repozitáři softwaru (software repository). Můžete o nich uvažovat jako by váš telefon měl několik obchodních center, kde si aplikace vybíráte. Obvykle najdete následující typy repozitářů. Je na uživateli (správci), jak se rozhodne, které repozitáře bude využívat.

  • Stable a testing, kde ten druhý nabízí novější verze softwaru ale s drobnou možností výskytu chyb (obvykle existuje ještě třetí repozitář, obvykle nazvaný unstable, který je pro poslední, často vývojové, verze).
  • Free a non-free kde ten první obsahuje jen software bez libovolných právnických překvapení. Non-free software může být zatížen patenty nebo vlastnickými právy (obvykle podle práva USA) nebo licencemi, které omezují jeho šíření.

Můžete si vytvořit i vlastní repozitář, což se může hodit když potřebujete instalovat software na více strojů (třeba jde o proprietární software, který máte zabalíčkovaný, ale nemůžete ho poslat do veřejných repozitářů).

Velká většina distribucí také nabízí nějaký druh uživatelských repozitářů, kde v podstatě kdokoliv může zveřejnit svůj software. Pro Fedoru existuje Copr.

Ani oficiální ani neoficiální repozitáře neposkytují žádnou záruku v právním slova smyslu. Nicméně, používání oficiálních (výchozích) repozitářů se považuje za bezpečné, množství útoků na tyto repozitáře je nízké a – na rozdíl od mnoha komerčních institucí – správci těchto repozitářů jsou velmi otevření v informovanosti o podobných incidentech. Je mnohem snazší narazit na podvodnou aplikaci v “obchodu” pro váš chytrý telefon než na ní narazit v oficiálních repozitářích vaší distribuce.

Náhrady klasických správců balíčků

Přítomnost různých správců balíčků má i nevýhody – pokud používáte více distribucí, musíte umět používat více programů. Navíc, různé distribuce musí vytvářet svoje vlastní balíčky (kompatibilní se svými správci balíčků) což je opět více práce.

Takže existuje i snaha správce balíčků sjednotit. Snap byl vytvořen proto, aby bylo možné jednotným způsobem instalovat balíčky napříč distribucemi. Zatímco pro některé uživatele je to snadný způsob jak rychle software nainstalovat, pro jiné je proprietární podstata Snapu a nutnost mít uživatelský účet překážka, potenciální riziko a odklon od otevřenosti.

Jako problematický příklad se můžeme podívat na instalaci PyCharmu. PyCharm je IDE pro Python, které (bohužel) cílí na uživatele Windows a také nabízí placenou profesionální verzi. Balíček PyCharmu pro Fedoru neexistuje.

Což je ale spíše výjimka – tento problém u většiny open-source programů nenajdete. Dokonce i společnosti zaměřené na jiné operační systémy dnes nabízí repozitáře pro DNF obsahující jejich software. Všimněte si, že v tomto případě je nabídka kompletního repozitáře ideální volbou. Uživatelé si mohou vybrat, jestli takový repozitář chtějí nebo ne, správci distribuce to nemusí dále řešit a komerční společnost má stále plnou kontrolu na vlastní distribucí.

Jsou tedy dvě možnosti jak nainstalovat PyCharm:

  1. Použít Snap
  2. Použít ad-hoc instalační skript. Je stažen spolu s instalací PyCharmu.

Druhá možnost není příliš oblíbená. Vyžaduje, aby uživatel spustil skript, který si stáhl, což je potenciálně nebezpečné – vždy byste měli podobné skripty kontrolovat. (Samozřejmě, i správce balíčků stahuje a spouští skripty, ale možnosti útoku jsou trochu menší.)

Dalším problémem je, že libovolná aplikace nainstalovaná tímto způsobem nemůže být automaticky aktualizovaná.

Co použít

Snap není jediná alternativa ke klasickým správcům balíčků.

Existuje také Flatpak nebo AppImage. Mohou existovat vedle sebe a je na uživateli, který si vybere.

Rozhodnutí, který používat, je ovlivněno mnoha faktory. Obecně je nejlepší preferovat instalaci přes obvyklé nástroje vaší distribuce.

Jako poslední poznámku: pokud software který potřebujete není jako balíček dostupný, můžete si vždy takový balíček sami vytvořit. Postup je mimo záběr předmětu, ale není to tak složité.

Správa procesů a signály

Když spustíte program (tj. spustitelný soubor), stane se procesem. Spustitelný soubor a běžící proces sdílí kód - ten je stejný v obou. Ale proces také obsahuje zásobník (stack) (např. pro lokální proměnné), haldu (heap), seznam otevřených soubor atd. apod. – tomu všemu se obvykle říká kontext procesu. Obvykle jsou slovní spojení běžící program a proces zaměňována.

Abyste zobrazili seznam běžící procesů na vašem stroji, můžete spustit ps -e (nebo ps -axufw pro více detailů). Pro interaktivní prohlížení je ale mnohem hezčí volbou htop.

htop lze použít pro zobrazení základních vlastností procesů. Pro ilustraci je zde příklad výstupu ps (s volbou --forest, která zobrazí, jak byly procesy navzájem spouštěny).

UID          PID    PPID  C STIME TTY          TIME CMD
root           2       0  0 Feb22 ?        00:00:00 [kthreadd]
root           3       2  0 Feb22 ?        00:00:00  \_ [rcu_gp]
root           4       2  0 Feb22 ?        00:00:00  \_ [rcu_par_gp]
root           6       2  0 Feb22 ?        00:00:00  \_ [kworker/0:0H-events_highpri]
root           8       2  0 Feb22 ?        00:00:00  \_ [mm_percpu_wq]
root          10       2  0 Feb22 ?        00:00:00  \_ [rcu_tasks_kthre]
root          11       2  0 Feb22 ?        00:00:00  \_ [rcu_tasks_rude_]
root           1       0  0 Feb22 ?        00:00:09 /sbin/init
root         275       1  0 Feb22 ?        00:00:16 /usr/lib/systemd/systemd-journald
root         289       1  0 Feb22 ?        00:00:02 /usr/lib/systemd/systemd-udevd
root         558       1  0 Feb22 ?        00:00:00 /usr/bin/xdm -nodaemon -config /etc/X11/...
root         561     558 10 Feb22 tty2     22:42:35  \_ /usr/lib/Xorg :0 -nolisten tcp -auth /var/lib/xdm/...
root         597     558  0 Feb22 ?        00:00:00  \_ -:0
intro        621     597  0 Feb22 ?        00:00:40      \_ xfce4-session
intro        830     621  0 Feb22 ?        00:05:54          \_ xfce4-panel --display :0.0 --sm-client-id ...
intro       1870     830  4 Feb22 ?        09:32:37              \_ /usr/lib/firefox/firefox
intro       1966    1870  0 Feb22 ?        00:00:01              |   \_ /usr/lib/firefox/firefox -contentproc ...
intro       4432     830  0 Feb22 ?        01:14:50              \_ xfce4-terminal
intro       4458    4432  0 Feb22 pts/0    00:00:11                  \_ bash
intro     648552    4458  0 09:54 pts/0    00:00:00                  |   \_ ps -ef --forest
intro      15655    4432  0 Feb22 pts/4    00:00:00                  \_ bash
intro     639421  549293  0 Mar02 pts/8    00:02:00                      \_ man ps
...

Především má každý proces svoje ID, často označované jen PID (neplést s tímto). PID je číslo přiřazené jádrem operačního systému a je používáno nástroji pro správu procesů. PID 1 je určeno pro první proces spuštěný v systému (0 je vyhrazená pro speciální účely – mrkněte na fork(2) pokud vás zajímají detaily). Když tento proces skončí, systém se vypne. Ostatní procesy dostávají (v jednoduchosti) postupně se zvyšující PIDy, časem jsou PIDy recyklovány.

Vzpomeňte si, že tyto informace jsou obsažené též v adresáři /proc/PID.

Signály

Linuxové systémy používají signály pro asynchronní komunikaci mezi běžícími programy (procesy). Slovo asynchronní znamená, že signál může být odeslán (a doručen) bez ohledu na stav procesu. Porovnejme se standardní vstup, kde program (explicitně) řídí, kdy z něj bude číst.

Signály ale nenabízejí příliš bohatou možnost komunikace: jediná informace (kromě toho, že byl vůbec poslán) je jejich číslo. Ve skutečnosti kernel definuje, které signály existují (jejich čísla) a některé dokonce sám řeší (většinou to znamená, že je proces násilně ukončen). Některé signály může aplikace zachytit a reagovat na ně. Pokud na ně ale aplikace nezareaguje, kernel ji ukončí (v výjimkou některých signálů, které jsou ve výchozím nastavení ignorovány).

Tohle je také vyjádřeno tím, že prográmek, kterým se signály posílají se jmenuje kill (protože obvykle proces zabije – ukončí).

Bez dalších parametrů kill posílá signál 15 (nazvaný TERM) který aplikaci říká, že má skončit. Aplikace se může rozhodnout, že signál tzv. odchytí, např. zavře otevřené soubory a teprve pak skončí. Ale může udělat v podstatě cokoliv, dokonce i signál ignorovat. Kromě TERMu můžeme též poslat signál KILL (číslo 9), který je vždy odchycen kernelem a okamžitě (a násilně) program ukončí). Signál 9 je tzv. nemaskovatelný a nemůže být aplikací nikdy odchycen.

Většina signálů je poslána procesu v reakci na specifickou událost. Například, signál PIPE je poslán, pokud proces zkouší zapsat do roury, jejíž čtecí konec byl uzavřen. (Vzpomeňte si na problém z labu 04.) Ukončení programu pomocí Ctrl-C v terminálu ve skutečnosti pošle signál INT (interrupt). Pokud vás zajímají i ostatní signály, mrkněte na signal(7).

Na příklad, pokud se systém vypíná, pošle TERM všem procesům. To jim dá možnost rozumně skončit,. Procesy, které po nějaké době stále běží jsou násilně ukončeny signálem KILL.

Jak na signály reagovat uvidíme na cvičení.

sudo

To try sudo, you can try running fdisk -l. Generally, fdisk is a tool for partitioning disks. With -l, it reads information about all disks on your system and displays information about partitions on them.

Without sudo, it will likely show only the following message:

fdisk: cannot open /dev/sda: Permission denied

Running it with sudo displays the actual information.

sudo fdisk -l
Disk /dev/sda: 480 GiB, 515396075520 bytes, 1006632960 sectors
Disk model: QEMU HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xdc505942

Device     Boot    Start        End   Sectors   Size Id Type
/dev/sda1  *        2048    2099199   2097152     1G 83 Linux
/dev/sda2        2099200   18620415  16521216   7.9G 82 Linux swap / Solaris
/dev/sda3       18620416 1006632959 988012544 471.1G 83 Linux

Note that sudo typically asks for a password (though that can be configured). It is the password of the current user, not root’s. (If you want to authenticate using the root’s password, you can use su instead.)

dnf (tj. správce balíčků pro Fedoru)

Note: Fedora used to have yum as the package manager and it can be found in many tutorials on the Internet (even in quite recent ones). It is considered obsolete and you should better avoid it. If you are used to yum from older versions of Fedora or from other RPM-based distributions, you will find dnf very similar and in many situations faster than yum.

The package manager for Fedora is called DNF.

Note: if you decided to use a different distribution, you will need to update the commands to match your system. Generally, the operations would be rather similar but we cannot provide a tutorial for every package manager here.

You can use the search command to get a list of packages which match the given name. Note that searching is not a privileged operation, hence it does not require sudo.

dnf search arduino
dnf search atool

Note that searching for a very generic term can yield hundreds of results.

The output is in the following format:

atool.noarch : A perl script for managing file archives of various types
ratools.x86_64

The .noarch and .x86_64 strings describe the nature of the package. noarch usually refers to a data package or package using interpreted languages, while .x86_64 denotes a package with binaries for the x86-64 architecture (e.g., written in C or Rust and then compiled to machine code).

To install a software package, run dnf with the install subcommand, giving it the name of the package to install. Here, sudo is needed as we are modifying the system.

sudo dnf install atool

Some applications are not a part of any software repository, but you can still download them in a format understandable by your package manager. That is a better situation than installing the files manually, because your package manager knows about the files (although it cannot upgrade it automatically). One such example is the Zoom client which has to be installed like this:

sudo dnf install "https://zoom.us/client/latest/zoom_x86_64.rpm"

To upgrade the whole system, simply run sudo dnf upgrade. DNF will ask for confirmation and then upgrade all available packages.

Note that unlike on other systems, you can always choose when to upgrade. The system will never reboot the machine for you or display a message about needed restart, unless you explicitly ask for it.

If you want to install a whole group of packages, you can use dnf grouplist to view their list and sudo dnf install @GROUP_NAME to install it.

The commands above contain the basics for maintaining your Fedora installation with respect to package management. The following links provide more information. The official Wiki page is a good source of information if you already know the system a bit.

For beginners, this guide about DNF and this tutorial are probably a better starting point.

Práce s procesy

Execute ps -ef --forest to view all process on your machine. Because of your graphical interface, the list will be probably quite long.

Practically, a small server offering web pages, calendar and SSH access can have about 80 processes, for a desktop running Xfce with browser and few other applications, the number will rise to almost 300 (this really depends a lot on the configuration but it is a ballpark estimate). About 50–60 of these are actually internal kernel threads. In other words, a web/calendar server needs about 20 “real” processes, a desktop about 200 of them :-).

You can view the same information with htop. You can also easily configure it to display information about your system like amount of free memory or CPU usage.

It can look like this (this one from a 32G/24CPU machine):

  Date & Time: 2022-03-03 10:07:26                                   Uptime: 50 days, 20:55:31
    1[||                     4.5%]    7[|||                    5.0%]  13[||||                    8.9%]  19[|                       3.2%]
    2[|                      1.3%]    8[|                      1.9%]  14[||                      3.8%]  20[||                      4.5%]
    3[||                     5.1%]    9[|                      0.6%]  15[||||||                 17.8%]  21[|||                     5.7%]
    4[                       0.0%]   10[                       0.0%]  16[||                      4.4%]  22[||                      4.5%]
    5[||                     4.5%]   11[||                     5.1%]  17[||                      4.5%]  23[|||                     4.5%]
    6[                       0.0%]   12[||                     5.1%]  18[||                      4.5%]  24[||                      4.5%]
  Mem[|||||||||||||||||||||||||||||||                   11.2G/31.3G] Tasks: 252, 1803 thr, 341 kthr; 1 running
  Swp[||||||||||||||||||||||||||||||||||||||||||||||||  3.06G/4.00G] Load average: 0.59 1.19 1.13

    PID USER       PRI  NI  VIRT   RES   SHR S CPU%+MEM%   TIME+  Command
    966 vojta       20   0  448M  9692  5824 S  0.0  0.0  0:01.01 |           |  |  `-
   3130 vojta       20   0 85856  3360  3356 S  0.0  0.0  0:00.03 |           |  `- /usr/lib/eclipse/eclipse -data /home/vojta/mff/eclips
   3174 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  2h57:34 |           |  |  `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.requi
   3175 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  1h12:37 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3176 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  2:44.29 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3177 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:00.04 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3178 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:00.96 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3179 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:00.23 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3180 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  8:46.39 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3181 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  3:53.24 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3182 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:01.85 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3183 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:01.62 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3184 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:00.00 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3185 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:00.00 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3186 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  1:55.30 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3187 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:20.61 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3188 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:01.52 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3189 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0  0:01.68 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
   3193 vojta       20   0 20.8G 1274M 28068 S  0.0  4.0 17:29.22 |           |  |     `- /usr/lib/jvm/java-11-openjdk/bin/java -Dosgi.re
F1 Help  F2 Setup F3 Search F4 Filter F5 List  F6 SortBy F7 Nice - F8 Nice + F9 Kill  F10 Quit

Similar to MidnightCommander, function keys perform the most important actions and the help is visible in the bottom bar.

Signály

Open two terminals now.

Run the following command in the first one.

sleep 999

In the second terminal, find the PID of this process. Hint.

From the second terminal, we will now kill the program.

kill THE_PID

Looking back at the first terminal, you should see the following message.

Terminated (SIGTERM).

Start the sleep command again, but send KILL this time.

kill -9 THE_PID

The message probably changed to Killed and the process was terminated as well.

Reakce na signály v Pythonu

Your program would typically react to TERM (the default “soft” termination), INT (Ctrl-C from the keyboard) and perhaps to USR1 or USR2 (the only user-defined signals). System daemons (non-interactive programs handling system services) often react to HUP by reloading their configuration.

The following Python program reacts to Ctrl-C by terminating (imports omitted):

# Actual signal callback
def on_signal(signal_number, frame_info):
    print("")
    print("Caught signal {} ({})".format(signal_number, frame_info))
    sys.exit()

def main():
    # Setting signal callback
    signal.signal(signal.SIGINT, on_signal)
    while True:
        time.sleep(0.5)
        print("Hit Ctrl-C...")

if __name__ == '__main__':
    main()

Exercise: write a program that tries to print all prime numbers. When terminating, it stores the highest number found so far and on the next invocation, it continues from there. Solution.

Reacting to a signal in a shell script is also possible using the trap command. Note that a typical action for a signal handler in a shell script is clean-up of temporary files.

#!/bin/bash

set -ueo pipefail

on_interrupt() {
    echo "Interrupted, terminating ..." >&2
    exit 17
}

on_exit() {
    echo "Cleaning up..." >&2
    rm -f "$MY_TEMP"
}

MY_TEMP="$( mktemp )"

trap on_interrupt INT TERM
trap on_exit EXIT

echo "Running as $$"

counter=1
while [ "$counter" -lt 10 ]; do
    date "+%Y-%m-%d %H:%M:%S | Waiting for Ctrl-C (loop $counter) ..."
    echo "$counter" >"$MY_TEMP"
    sleep 1
    counter=$(( counter + 1 ))
done

The command trap receives as the first argument the command to execute on the signal. Other arguments list the signals to react to. Note that a special signal EXIT means normal script termination. Hence, we do not need to call on_exit after the loop terminates.

Using - instead of the handler causes the respective handler to be set to default. Without this reset in on_exit, the handler would be called twice after the user would hit Ctrl-C (first for INT caused by Ctrl-C itself and then by the explicit call to exit).

From now on, your shell scripts shall always include a signal handler for clean-up of temporary files.

Note the use of $$ which prints the current PID. Alternatively, you can use pgrep <program_name> to find a PIDs for running programs. Similarly, you can use killall to kill processes by name (but be careful as with great power comes great responsibility). Consult the manual pages for more details.

Run the above script, note its PID and run the following in a new terminal.

kill THE_PID_PRINTED_BY_THE_ABOVE_SCRIPT

The script was terminated and the clean-up routine was called. Compare with situation when you comment-out the trap command.

Run the script again but pass -9 to kill to specify that you want to send signal nine (i.e., KILL).

What happened? Answer.

While signals are a rudimentary mechanism, which passes binary events with no additional data, they are the primary way of process control in Linux. (If you need a richer communication channel, you can use D-Bus instead.) Reasonable reaction to basic signals is a must for server-style applications (e.g., a web server should react to TERM by completing outstanding requests without accepting new connections, and terminating afterwards). It shell scripts, it is considered good manners to always clean up temporary files.

Správa uživatelských účtů

So far, we used /etc/passwd for getting information about accounts directly. In practice, things can be more complicated as the information may come from different sources. For example, in IMPAKT labs, the information is somehow fetched from the CAS.

Generally, there can be multiple sources of user accounts. Thus, it is better to use getent to query them all instead of relying on /etc/passwd only:

getent passwd YOUR_GITLAB_LOGIN

You can specify group instead of passwd to query groups, too.

Note that the output is actually in the same format as /etc/passwd. This is on purpose.

Without the login parameter, the command will (usually) list all accounts.

How many student accounts are on the machine u-pl17.ms.mff.cuni.cz? Hint. Solution.

Vytváření nových účtů

Creating a new account in Linux is rather straightforward. The utility useradd creates a new user by adding the appropriate entry into /etc/passwd and by creating a home directory.

Technically, nothing more needs to be done: the entry in /etc/passwd means that user id (numerical) is assigned to a human-readable name, creation of the home directory ensures that the user has a writable directory to start with.

Practically, one can create a new user by editing /etc/passwd manually, but it is not recommended.

Hodnocené úlohy (deadline: 24. dubna)

09/passwd.txt (20 bodů)

Na stroji linux.ms.mff.cuni.cz získejte informace o vašem účtu.

Vložte odpovídající řádek o vašem účtu z passwd databáze do souboru 09/passwd.txt.

Automatické testy nekontrolují skutečnou správnost, ale jen formát odpovědi.

Hint.

09/signals.txt (25 bodů)

Spusťte příkaz nswi177-signals na linux.ms.mff.cuni.cz.

Budete mu muset ve správném pořadí poslat různé signály, abyste splnili tuto úlohu.

Program vás během provede: vždy vytiskne, jaký signál máte poslat.

Zkopírujte poslední řádek výstupu (budou to dvě čísla) z tohoto programu do 09/signals.txt.

Tato úloha je pouze částečně testovaná automatickými testy.

09/countdown.sh (35 bodů)

Napište skript, který obdrží jeden parametr: počet sekund (nezáporné číslo) k odpočtu a každou vteřinu vypíše, kolik času zbývá.

Můžete předpokládat, že program bude vždy korektně spuštěn.

Pokud uživatel stiskne Ctrl-C za běhu (nebo pošle TERM signál), skript se ukončí se slovem Aborted a s exit kódem 17.

Příklady:

$ ./countdown.sh 10
10
9
8
7
6
5
4
3
2
1

Každá řádka se objeví o vteřinu později než předchozí. Využijte sleep 1 na čekání mezi tisky a před ukončením. První číslo se tiskne ihned, zatímco po poslední řádce s 1 má program ještě vteřinku počkat, než skončí.

Prosím, uvědomte si, že skript bude o něco pomalejší, protože i spuštění sleepu něco trvá, ale to nám nevadí.

Ukázkové spuštění, kde uživatel stiskne Ctrl-C (^C označuje místo stisku Ctrl-C a nejde o výstup z program). Zpráva FAILED je vytištěna mimo program a jen zdůrazňuje nenulový návratový kód programu.

$ ./countdown.sh 5 || echo "FAILED"
5
4
^C
Aborted
FAILED

09/dnf.txt (20 bodů)

Jaká verze balíčku (nikoliv verze programu!) msim-git je nainstalovaná na linux.ms.mff.cuni.cz?

Tato úloha je pouze částečně testovaná automatickými testy.

Použijte příkaz dnf help, abyste zjistili seznam podpříkazů a našli ten správný pro vyřešení úlohy (budete potřebovat jeden z hlavních příkazů: main commands).

Je v pořádku napsat jen verzi nebo verzi včetně vydání (version, release).

Učební výstupy

Znalosti konceptů

Znalost konceptů znamená, že rozumíte významu a kontextu daného tématu a jste schopni témata zasadit do většího rámce. Takže, jste schopni …

  • vysvětlit jaké druhy účtů existují na Linuxu a čím se liší

  • vysvětlit, proč jsou potřeba mechanismy jako je sudo a proč jsou lepší než přímá práce pod superuživatelem (root)

  • vysvětlit co je to balíček (package) a jak se na Linuxu používá

  • vysvětlit, co je to signál (u procesů)

Praktické dovednosti

Praktické dovednosti se obvykle týkají použití daných programů pro vyřešení různých úloh. Takže, dokážete …

  • použít getent na získání informací o existujících účtech

  • použít useradd pro vytvoření nového uživatelského účtu

  • použít správce balíčků (package manager) pro instalaci a odinstalaci balíčků a upgrade celého systému

  • použít ps a pgrep

  • použít htop

  • poslat signál běžícímu procesu