diff --git a/CHANGES b/CHANGES
index 1bdb681f0970caf5f72080a7352a22ba40e9260d..c91e99299135464af66aa6459c79994231907fe7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,18 +7,27 @@ contributors are listed. Note that Calamares does not have a historical
 changelog -- this log starts with version 3.2.0. The release notes on the
 website will have to do for older versions.
 
-# 3.2.44 (unreleased) #
+# 3.2.44 (2021-09-24) #
 
 This release contains contributions from (alphabetically by first name):
+ - Anke Boersma
+ - Shrinivas Vishnu Kumbhar (new contributor, welcome!)
  - whorfin (new contributor, welcome!)
 
 ## Core ##
- - No core changes yet
+ - "Log spam" has been reduced a little in the partitioning module.
 
 ## Modules ##
+ - *initcpiocfg* has had a number of internal code-fixes, and now adds
+   the `consolefont` hook by default as well. (Thanks Shrinivas)
+ - Both *locale* and *keyboard* have received some tweaks for configurations
+   in India; unless the user selects otherwise, English is preferred.
  - The *luksbootkeyfile* module was reported to be too quick to declare
    a timeout when applying the keyfile. The timeout has been increased
    to one minute. (Thanks whorfin)
+ - *networkcfg* tries harder to find the live-user login for re-working
+   networking settings. This fixes a regression on FerenOS, where the
+   installer was crashing because it could not find the live-user login.
 
 
 # 3.2.43 (2021-09-17) #
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 807cdfabf82cb84e6c9f9da6ac2750da14c69717..b391cfeb2b5fcee8daa4cb1047171314b6d8b9f1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,7 @@ project( CALAMARES
     LANGUAGES C CXX
 )
 
-set( CALAMARES_VERSION_RC 1 )  # Set to 0 during release cycle, 1 during development
+set( CALAMARES_VERSION_RC 0 )  # Set to 0 during release cycle, 1 during development
 
 ### OPTIONS
 #
diff --git a/lang/calamares_cs_CZ.ts b/lang/calamares_cs_CZ.ts
index 1c2ed17556bca94929dc12576fe3955109e00e78..5714c4e31bdc2bb8cf28dbaf725885c671a4e9b2 100644
--- a/lang/calamares_cs_CZ.ts
+++ b/lang/calamares_cs_CZ.ts
@@ -134,7 +134,7 @@
     <message>
       <location filename="../src/calamares/DebugWindow.ui" line="131"/>
       <source>Widget Tree</source>
-      <translation>Strom widgetu</translation>
+      <translation>Strom ovládacích prvků</translation>
     </message>
     <message>
       <location filename="../src/calamares/DebugWindow.cpp" line="221"/>
@@ -217,7 +217,7 @@
     <message>
       <location filename="../src/libcalamares/PythonJob.cpp" line="224"/>
       <source>Working directory %1 for python job %2 is not readable.</source>
-      <translation>Pracovní složku %1 pro Python skript %2 se nedaří otevřít pro čtení.</translation>
+      <translation>Pracovní složka %1 pro Python skript %2 není přístupná pro čtení.</translation>
     </message>
     <message>
       <location filename="../src/libcalamares/PythonJob.cpp" line="230"/>
@@ -227,7 +227,7 @@
     <message>
       <location filename="../src/libcalamares/PythonJob.cpp" line="231"/>
       <source>Main script file %1 for python job %2 is not readable.</source>
-      <translation>Hlavní soubor s python skriptem %1 pro úlohu %2 se nedaří otevřít pro čtení..</translation>
+      <translation>Hlavní soubor Python skriptu %1 pro úlohu %2 není přístupný pro čtení.</translation>
     </message>
     <message>
       <location filename="../src/libcalamares/PythonJob.cpp" line="304"/>
@@ -504,7 +504,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/calamares/CalamaresWindow.cpp" line="371"/>
       <source>%1 Installer</source>
-      <translation>%1 instalátor</translation>
+      <translation>Instalátor %1</translation>
     </message>
   </context>
   <context>
@@ -660,7 +660,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1514"/>
       <source>This storage device is a part of an &lt;strong&gt;inactive RAID&lt;/strong&gt; device.</source>
-      <translation>Toto úložné zařízení je součástí &lt;strong&gt;Neaktivního RAID&lt;/strong&gt; zařízení.</translation>
+      <translation>Toto úložné zařízení je součástí &lt;strong&gt;neaktivního RAID&lt;/strong&gt; zařízení.</translation>
     </message>
     <message>
       <location filename="../src/modules/partition/gui/ChoicePage.cpp" line="1641"/>
@@ -758,7 +758,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/keyboard/Config.cpp" line="361"/>
       <source>Set keyboard layout to %1/%2.</source>
-      <translation>Nastavit rozložení klávesnice na %1/%2.</translation>
+      <translation>Nastavit rozvržení klávesnice na %1/%2.</translation>
     </message>
     <message>
       <location filename="../src/modules/locale/Config.cpp" line="342"/>
@@ -808,7 +808,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/welcome/Config.cpp" line="55"/>
       <source>This computer does not satisfy the minimum requirements for setting up %1.&lt;br/&gt;Setup cannot continue. &lt;a href="#details"&gt;Details...&lt;/a&gt;</source>
-      <translation>Počítač nesplňuje minimální požadavky pro instalaci %1.&lt;br/&gt;Instalace nemůže pokračovat &lt;a href="#details"&gt;Podrobnosti…&lt;/a&gt;</translation>
+      <translation>Počítač nesplňuje minimální požadavky pro instalaci %1.&lt;br/&gt;Nastavování nemůže pokračovat &lt;a href="#details"&gt;Podrobnosti…&lt;/a&gt;</translation>
     </message>
     <message>
       <location filename="../src/modules/welcome/Config.cpp" line="59"/>
@@ -953,7 +953,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/packagechooser/Config.cpp" line="177"/>
       <source>Install option: &lt;strong&gt;%1&lt;/strong&gt;</source>
-      <translation>Možnost instalace: &lt;strong&gt;%1&lt;/strong&gt;</translation>
+      <translation>Volba instalace: &lt;strong&gt;%1&lt;/strong&gt;</translation>
     </message>
     <message>
       <location filename="../src/modules/packagechooser/Config.cpp" line="177"/>
@@ -1182,7 +1182,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/users/CreateUserJob.cpp" line="126"/>
       <source>Preserving home directory</source>
-      <translation>Zachování domovské složky</translation>
+      <translation>Zachovává se domovská složka</translation>
     </message>
     <message>
       <location filename="../src/modules/users/CreateUserJob.cpp" line="50"/>
@@ -1198,7 +1198,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/users/CreateUserJob.cpp" line="159"/>
       <source>Setting file permissions</source>
-      <translation>Nastavení oprávnění souboru</translation>
+      <translation>Nastavují se přístupová práva k souboru</translation>
     </message>
   </context>
   <context>
@@ -1755,7 +1755,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/locale/LCLocaleDialog.cpp" line="23"/>
       <source>System locale setting</source>
-      <translation>Místní a jazykové nastavení systému</translation>
+      <translation>Místní a jazyková nastavení systému</translation>
     </message>
     <message>
       <location filename="../src/modules/locale/LCLocaleDialog.cpp" line="30"/>
@@ -1986,7 +1986,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/localeq/Map.qml" line="243"/>
       <source>Timezone: %1</source>
-      <translation>Časová zóna: %1</translation>
+      <translation>Časové pásmo: %1</translation>
     </message>
     <message>
       <location filename="../src/modules/localeq/Map.qml" line="264"/>
@@ -2152,12 +2152,12 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/localeq/Offline.qml" line="115"/>
       <source>Select your preferred Zone within your Region.</source>
-      <translation>Vyberte preferovanou zónu ve vašem regionu.</translation>
+      <translation>Vyberte upřednostňované pásmo ve svém regionu.</translation>
     </message>
     <message>
       <location filename="../src/modules/localeq/Offline.qml" line="186"/>
       <source>Zones</source>
-      <translation>Zóny</translation>
+      <translation>Pásma</translation>
     </message>
     <message>
       <location filename="../src/modules/localeq/Offline.qml" line="233"/>
@@ -2283,7 +2283,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
       <translation>
         <numerusform>Heslo obsahuje méně než %1 číslici</numerusform>
         <numerusform>Heslo obsahuje méně než %1 číslice</numerusform>
-        <numerusform>Heslo obsahuje méně než %1 číslice</numerusform>
+        <numerusform>Heslo obsahuje méně než %1 číslic</numerusform>
         <numerusform>Heslo obsahuje méně než %1 číslice</numerusform>
       </translation>
     </message>
@@ -2463,7 +2463,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/packagechooser/page_package.ui" line="24"/>
       <source>Form</source>
-      <translation>Form</translation>
+      <translation>Formulář</translation>
     </message>
     <message>
       <location filename="../src/modules/packagechooser/page_package.ui" line="44"/>
@@ -2724,7 +2724,7 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
     <message>
       <location filename="../src/modules/partition/gui/PartitionPage.ui" line="18"/>
       <source>Form</source>
-      <translation>Form</translation>
+      <translation>Formulář</translation>
     </message>
     <message>
       <location filename="../src/modules/partition/gui/PartitionPage.ui" line="26"/>
@@ -3609,7 +3609,7 @@ Výstup:
     <message>
       <location filename="../src/modules/users/MiscJobs.cpp" line="184"/>
       <source>These groups are missing in the target system: %1</source>
-      <translation>Tyto skupiny chybí v cílovém systému chybí: %1</translation>
+      <translation>Tyto skupiny v cílovém systému chybí: %1</translation>
     </message>
   </context>
   <context>
@@ -3703,7 +3703,7 @@ Výstup:
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="187"/>
       <source>KDE user feedback</source>
-      <translation>Zpětná vazba uživatele KDE</translation>
+      <translation>Zpětná vazba od uživatele pro KDE</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="193"/>
@@ -3719,12 +3719,12 @@ Výstup:
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="216"/>
       <source>Could not configure KDE user feedback correctly, script error %1.</source>
-      <translation>Nepodařilo se správně nastavit zpětnou vazbu KDE uživatele, chyba ve skriptu %1.</translation>
+      <translation>Nepodařilo se správně nastavit zpětnou vazbu od uživatele pro KDE, chyba ve skriptu %1.</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="222"/>
       <source>Could not configure KDE user feedback correctly, Calamares error %1.</source>
-      <translation>Nepodařilo se správně nastavit zpětnou vazbu KDE uživatele, chyba Calamares %1.</translation>
+      <translation>Nepodařilo se správně nastavit zpětnou vazbu od uživatel pro KDE, chyba Calamares %1.</translation>
     </message>
   </context>
   <context>
@@ -3732,28 +3732,28 @@ Výstup:
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="136"/>
       <source>Machine feedback</source>
-      <translation>Zpětná vazba stroje</translation>
+      <translation>Zpětná vazba ze stroje</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="142"/>
       <source>Configuring machine feedback.</source>
-      <translation>Nastavování zpětné vazby stroje</translation>
+      <translation>Nastavování zpětné vazby ze stroje</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="165"/>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="171"/>
       <source>Error in machine feedback configuration.</source>
-      <translation>Chyba v nastavení zpětné vazby stroje.</translation>
+      <translation>Chyba v nastavení zpětné vazby ze stroje.</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="166"/>
       <source>Could not configure machine feedback correctly, script error %1.</source>
-      <translation>Nepodařilo se správně nastavit zpětnou vazbu stroje, chyba skriptu %1.</translation>
+      <translation>Nepodařilo se správně nastavit zpětnou vazbu ze stroje, chyba skriptu %1.</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingJobs.cpp" line="172"/>
       <source>Could not configure machine feedback correctly, Calamares error %1.</source>
-      <translation>Nepodařilo se správně nastavit zpětnou vazbu stroje, chyba Calamares %1.</translation>
+      <translation>Nepodařilo se správně nastavit zpětnou vazbu ze stroje, chyba Calamares %1.</translation>
     </message>
   </context>
   <context>
@@ -3786,7 +3786,7 @@ Výstup:
     <message>
       <location filename="../src/modules/tracking/TrackingPage.cpp" line="91"/>
       <source>By selecting this you will send information about your installation and hardware. This information will only be sent &lt;b&gt;once&lt;/b&gt; after the installation finishes.</source>
-      <translation>Výběrem tohoto pošlete informace o své instalaci a hardware. Tyto údaje budou poslány &lt;b&gt;pouze jednorázově&lt;/b&gt; po dokončení instalace.</translation>
+      <translation>Výběrem tohoto pošlete informace o své instalaci a hardware. Tyto údaje budou odeslány &lt;b&gt;pouze jednorázově&lt;/b&gt; po dokončení instalace.</translation>
     </message>
     <message>
       <location filename="../src/modules/tracking/TrackingPage.cpp" line="94"/>
@@ -3975,7 +3975,7 @@ Výstup:
     <message>
       <location filename="../src/modules/welcome/WelcomePage.cpp" line="222"/>
       <source>&lt;h1&gt;Welcome to the Calamares installer for %1.&lt;/h1&gt;</source>
-      <translation>&lt;h1&gt;Vítejte v Calamares,  instalačním programu (nejen) pro %1.&lt;/h1&gt;</translation>
+      <translation>&lt;h1&gt;Vítejte v Calamares, instalačním programu (nejen) pro %1.&lt;/h1&gt;</translation>
     </message>
     <message>
       <location filename="../src/modules/welcome/WelcomePage.cpp" line="223"/>
@@ -4121,7 +4121,7 @@ Výstup:
     <message>
       <location filename="../src/modules/keyboardq/keyboardq.qml" line="60"/>
       <source>To activate keyboard preview, select a layout.</source>
-      <translation type="unfinished"/>
+      <translation>Pokud chcete aktivovat náhled klávesnice, vyberte rozvržení.</translation>
     </message>
     <message>
       <location filename="../src/modules/keyboardq/keyboardq.qml" line="86"/>
@@ -4131,7 +4131,7 @@ Výstup:
     <message>
       <location filename="../src/modules/keyboardq/keyboardq.qml" line="254"/>
       <source>Layouts</source>
-      <translation>Rovzržení</translation>
+      <translation>Rozvržení</translation>
     </message>
     <message>
       <location filename="../src/modules/keyboardq/keyboardq.qml" line="263"/>
@@ -4179,7 +4179,7 @@ Výstup:
     <message>
       <location filename="../src/modules/packagechooserq/packagechooserq.qml" line="108"/>
       <source>If you don't want to install an office suite, just select No Office Suite. You can always add one (or more) later on your installed system as the need arrives.</source>
-      <translation>Pokud nechcete nainstalovat žádnou sadu kancelářských aplikací, stačí jen zvolit Žádná sada kancelářských aplikací. V případě potřeby je možné kdykoli nějakou přidat na už nainstalovaný systém.</translation>
+      <translation>Pokud nechcete nainstalovat žádnou sadu kancelářských aplikací, stačí jen zvolit Žádná sada kancelářských aplikací. V případě potřeby je možné kdykoli nějakou přidat do už nainstalovaného systému.</translation>
     </message>
     <message>
       <location filename="../src/modules/packagechooserq/packagechooserq.qml" line="121"/>
@@ -4310,7 +4310,7 @@ Výstup:
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="178"/>
       <source>This name will be used if you make the computer visible to others on a network.</source>
-      <translation>Tento název se použije, pokud počítač zviditelníte ostatním v síti.</translation>
+      <translation>Pod tímto názvem se bude počítač případně zobrazovat ostatním počítačům v síti.</translation>
     </message>
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="198"/>
@@ -4335,7 +4335,7 @@ Výstup:
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="261"/>
       <source>Enter the same password twice, so that it can be checked for typing errors. A good password will contain a mixture of letters, numbers and punctuation, should be at least eight characters long, and should be changed at regular intervals.</source>
-      <translation>Zadejte dvakrát stejné heslo, aby bylo možné zkontrolovat chyby při psaní. Dobré heslo by mělo obsahovat směs písmen, čísel a interpunkce a mělo by mít alespoň osm znaků. Zvažte také jeho pravidelnou změnu.</translation>
+      <translation>Zadání hesla zopakujte i do kontrolní kolonky, abyste měli jistotu, že jste napsali, co zamýšleli (že nedošlo k překlepu). Dobré heslo se bude skládat z písmen, číslic a interpunkce a mělo by být alespoň osm znaků dlouhé. Heslo byste také měli pravidelně měnit (prevence škod z jeho případného prozrazení).</translation>
     </message>
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="406"/>
@@ -4350,7 +4350,7 @@ Výstup:
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="398"/>
       <source>Log in automatically without asking for the password</source>
-      <translation>Přihlaste se automaticky bez zadávání hesla</translation>
+      <translation>Přihlašovat se automaticky bez zadávání hesla</translation>
     </message>
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="190"/>
@@ -4360,7 +4360,7 @@ Výstup:
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="293"/>
       <source>Reuse user password as root password</source>
-      <translation>Použijte uživatelské heslo zároveň jako heslo root</translation>
+      <translation>Použijte heslo uživatele i pro účet správce (root)</translation>
     </message>
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="301"/>
@@ -4380,12 +4380,12 @@ Výstup:
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="342"/>
       <source>Repeat Root Password</source>
-      <translation>Opakujte root heslo</translation>
+      <translation>Zopakujte zadání hesla pro správce systému (root)</translation>
     </message>
     <message>
       <location filename="../src/modules/usersq/usersq.qml" line="368"/>
       <source>Enter the same password twice, so that it can be checked for typing errors.</source>
-      <translation>Zadejte dvakrát stejné heslo, aby bylo možné zkontrolovat chyby při psaní.</translation>
+      <translation>Zadání hesla zopakujte i do kontrolní kolonky, abyste měli jistotu, že jste napsali, co zamýšleli (že nedošlo k překlepu).</translation>
     </message>
   </context>
   <context>
diff --git a/lang/python/az/LC_MESSAGES/python.po b/lang/python/az/LC_MESSAGES/python.po
index f4c40e5ab24e719f88c96b66c9e1d8c5150c63fa..8ac8172d8fd0cc8a703b13c6b795664664aa9a9e 100644
--- a/lang/python/az/LC_MESSAGES/python.po
+++ b/lang/python/az/LC_MESSAGES/python.po
@@ -4,7 +4,7 @@
 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 # 
 # Translators:
-# xxmn77 <xxmn77@gmail.com>, 2021
+# Xəyyam Qocayev <xxmn77@gmail.com>, 2021
 # 
 #, fuzzy
 msgid ""
@@ -13,7 +13,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-09-08 13:31+0200\n"
 "PO-Revision-Date: 2017-08-09 10:34+0000\n"
-"Last-Translator: xxmn77 <xxmn77@gmail.com>, 2021\n"
+"Last-Translator: Xəyyam Qocayev <xxmn77@gmail.com>, 2021\n"
 "Language-Team: Azerbaijani (https://www.transifex.com/calamares/teams/20061/az/)\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
diff --git a/lang/python/az_AZ/LC_MESSAGES/python.po b/lang/python/az_AZ/LC_MESSAGES/python.po
index 2d57f0d4ba6c184cf98611f193eaec260b83d1f1..0df66e71111f8b221a4714bd5548043cf9b5899e 100644
--- a/lang/python/az_AZ/LC_MESSAGES/python.po
+++ b/lang/python/az_AZ/LC_MESSAGES/python.po
@@ -4,7 +4,7 @@
 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 # 
 # Translators:
-# xxmn77 <xxmn77@gmail.com>, 2021
+# Xəyyam Qocayev <xxmn77@gmail.com>, 2021
 # 
 #, fuzzy
 msgid ""
@@ -13,7 +13,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-09-08 13:31+0200\n"
 "PO-Revision-Date: 2017-08-09 10:34+0000\n"
-"Last-Translator: xxmn77 <xxmn77@gmail.com>, 2021\n"
+"Last-Translator: Xəyyam Qocayev <xxmn77@gmail.com>, 2021\n"
 "Language-Team: Azerbaijani (Azerbaijan) (https://www.transifex.com/calamares/teams/20061/az_AZ/)\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
diff --git a/lang/python/cs_CZ/LC_MESSAGES/python.po b/lang/python/cs_CZ/LC_MESSAGES/python.po
index 6305ba7fb3e7296a5f666c4c028df16f065db4c3..993ed0b3f39f43d26892f765fe0f55a4552927d7 100644
--- a/lang/python/cs_CZ/LC_MESSAGES/python.po
+++ b/lang/python/cs_CZ/LC_MESSAGES/python.po
@@ -206,8 +206,8 @@ msgid ""
 "The displaymanagers list is empty or undefined in both globalstorage and "
 "displaymanager.conf."
 msgstr ""
-"Seznam správců displejů je prázdný nebo není definován v jak "
-"bothglobalstorage, tak v displaymanager.conf."
+"Seznam správců displejů je prázdný nebo není definován v jak globalstorage, "
+"tak v displaymanager.conf."
 
 #: src/modules/displaymanager/main.py:989
 msgid "Display manager configuration was incomplete"
@@ -343,7 +343,7 @@ msgid ""
 "The package manager could not make changes to the installed system. The "
 "command <pre>{!s}</pre> returned error code {!s}."
 msgstr ""
-"Nástroji pro správu balíčků se nepodařilo udělat změny v nainstalovaném "
+"Nástroji pro správu balíčků se nepodařilo udělat změny v instalovaném "
 "systému. Příkaz <pre>{!s}</pre> vrátil chybový kód {!s}."
 
 #: src/modules/bootloader/main.py:43
diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp
index 00b30f3187b32333a4f18a246d0d29271a05f6c0..039a28e2646d046e79071dd97d01c2d5f4c271d0 100644
--- a/src/libcalamares/JobQueue.cpp
+++ b/src/libcalamares/JobQueue.cpp
@@ -112,17 +112,19 @@ public:
         QString message;  ///< Filled in with errors
         QString details;
 
+        Logger::Once o;
         m_jobIndex = 0;
         for ( const auto& jobitem : *m_runningJobs )
         {
             if ( failureEncountered && !jobitem.job->isEmergency() )
             {
-                cDebug() << "Skipping non-emergency job" << jobitem.job->prettyName();
+                cDebug() << o << "Skipping non-emergency job" << jobitem.job->prettyName();
             }
             else
             {
-                cDebug() << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
+                cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
                          << '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')';
+                o.refresh();  // So next time it shows the function header again
                 emitProgress( 0.0 );  // 0% for *this job*
                 connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );
                 auto result = jobitem.job->exec();
diff --git a/src/libcalamares/PythonJobApi.cpp b/src/libcalamares/PythonJobApi.cpp
index d61cfc223b12ba9ac934442df73bef0452c6b9f1..480a115ae7d6dacec72892cf22d57e1dbafc4608 100644
--- a/src/libcalamares/PythonJobApi.cpp
+++ b/src/libcalamares/PythonJobApi.cpp
@@ -16,6 +16,7 @@
 #include "partition/Mount.h"
 #include "utils/CalamaresUtilsSystem.h"
 #include "utils/Logger.h"
+#include "utils/RAII.h"
 #include "utils/String.h"
 
 #include <QCoreApplication>
@@ -147,7 +148,7 @@ debug( const std::string& s )
 void
 warning( const std::string& s )
 {
-    Logger::CDebug( Logger::LOGWARNING )  << output_prefix << QString::fromStdString( s );
+    Logger::CDebug( Logger::LOGWARNING ) << output_prefix << QString::fromStdString( s );
 }
 
 PythonJobInterface::PythonJobInterface( Calamares::PythonJob* parent )
@@ -241,6 +242,10 @@ _add_localedirs( QStringList& pathList, const QString& candidate )
 bp::object
 gettext_path()
 {
+    // Going to log informatively just once
+    static bool first_time = true;
+    cScopedAssignment( &first_time, false );
+
     // TODO: distinguish between -d runs and normal runs
     // TODO: can we detect DESTDIR-installs?
     QStringList candidatePaths
@@ -257,21 +262,26 @@ gettext_path()
     }
     _add_localedirs( candidatePaths, QDir().canonicalPath() );  // .
 
-    cDebug() << "Determining gettext path from" << candidatePaths;
+    if ( first_time )
+    {
+        cDebug() << "Determining gettext path from" << candidatePaths;
+    }
 
     QStringList candidateLanguages = _gettext_languages();
-
     for ( const auto& lang : candidateLanguages )
+    {
         for ( auto localedir : candidatePaths )
         {
             QDir ldir( localedir );
             if ( ldir.cd( lang ) )
             {
-                cDebug() << Logger::SubEntry << "Found" << lang << "in" << ldir.canonicalPath();
+                Logger::CDebug( Logger::LOGDEBUG )
+                    << output_prefix << "Found gettext" << lang << "in" << ldir.canonicalPath();
                 return bp::object( localedir.toStdString() );
             }
         }
-    cDebug() << Logger::SubEntry << "No translation found for languages" << candidateLanguages;
+    }
+    cWarning() << "No translation found for languages" << candidateLanguages;
     return bp::object();  // None
 }
 
diff --git a/src/libcalamares/modulesystem/Module.cpp b/src/libcalamares/modulesystem/Module.cpp
index ff0b20f7837dba3dbc1ecb50e11347bcd98cf469..8fbb0530045a3aad114a68d668cb532d6ee09b7f 100644
--- a/src/libcalamares/modulesystem/Module.cpp
+++ b/src/libcalamares/modulesystem/Module.cpp
@@ -101,7 +101,7 @@ Module::loadConfigurationFile( const QString& configFileName )  //throws YAML::E
             YAML::Node doc = YAML::Load( ba.constData() );
             if ( doc.IsNull() )
             {
-                cDebug() << "Found empty module configuration" << path;
+                cWarning() << "Found empty module configuration" << path;
                 // Special case: empty config files are valid,
                 // but aren't a map.
                 return;
@@ -112,14 +112,13 @@ Module::loadConfigurationFile( const QString& configFileName )  //throws YAML::E
                 return;
             }
 
-            cDebug() << "Loaded module configuration" << path;
             m_configurationMap = CalamaresUtils::yamlMapToVariant( doc );
             m_emergency = m_maybe_emergency && m_configurationMap.contains( EMERGENCY )
                 && m_configurationMap[ EMERGENCY ].toBool();
             return;
         }
     }
-    cDebug() << "No config file for" << name() << "found anywhere at" << Logger::DebugList( configCandidates );
+    cWarning() << "No config file for" << name() << "found anywhere at" << Logger::DebugList( configCandidates );
 }
 
 
diff --git a/src/libcalamares/partition/KPMManager.cpp b/src/libcalamares/partition/KPMManager.cpp
index 5f6b87589367552cbc02fa207fe47c9d4bac4f39..ff7701703cf341d4d5d0daff825ee71f6aff0e70 100644
--- a/src/libcalamares/partition/KPMManager.cpp
+++ b/src/libcalamares/partition/KPMManager.cpp
@@ -100,12 +100,10 @@ getInternal()
 KPMManager::KPMManager()
     : m_d( getInternal() )
 {
-    cDebug() << "KPMManager" << s_backend.use_count() << "created.";
 }
 
 KPMManager::~KPMManager()
 {
-    cDebug() << "KPMManager" << s_backend.use_count() << "being destroyed.";
 }
 
 KPMManager::operator bool() const
diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp
index df578a862216d6dd66c91e2ecc318ec995cd1797..d2c0a6cf113d1ec0f005d5e71630d00d7e1fd7f5 100644
--- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp
+++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp
@@ -169,7 +169,7 @@ System::runCommand( System::RunLocation location,
         }
     }
 
-    cDebug() << "Running" << program << RedactedList( arguments );
+    cDebug() << Logger::SubEntry << "Running" << program << RedactedList( arguments );
     process.start();
     if ( !process.waitForStarted() )
     {
@@ -208,10 +208,6 @@ System::runCommand( System::RunLocation location,
         {
             cDebug() << Logger::SubEntry << "Finished. Exit code:" << r << "output:\n" << Logger::NoQuote << output;
         }
-        else
-        {
-            cDebug() << Logger::SubEntry << "Finished. Exit code:" << r;
-        }
     }
     else  // if ( r != 0 )
     {
diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h
index 871cc6fb3a62ba400b5b78e2ca5be9055f43b46e..1fd534d04d6bac6bc0e4b3d6a7e9751d8119c8c0 100644
--- a/src/libcalamares/utils/Logger.h
+++ b/src/libcalamares/utils/Logger.h
@@ -310,6 +310,14 @@ public:
     }
     friend CDebug& operator<<( CDebug&&, const Once& );
 
+    /** @brief Restore the object to "fresh" state
+     *
+     * It may be necessary to allow the Once object to stream the
+     * function header again -- for instance, after logging an error,
+     * any following debug log might want to re-introduce the header.
+     */
+    void refresh() { m = true; }
+
 private:
     mutable bool m = false;
 };
diff --git a/src/libcalamares/utils/RAII.h b/src/libcalamares/utils/RAII.h
index 00e276ec6f60a5f3ac2119559c46e6e1e930f4d9..957e4fe42e6c02e5a8bd39453cdb44ac35cdf283 100644
--- a/src/libcalamares/utils/RAII.h
+++ b/src/libcalamares/utils/RAII.h
@@ -42,30 +42,17 @@ struct cqDeleter
     }
 };
 
-/// @brief Sets a bool to @p value and resets to !value on destruction
-template < bool value >
-struct cBoolSetter
-{
-    bool& m_b;
-
-    cBoolSetter( bool& b )
-        : m_b( b )
-    {
-        m_b = value;
-    }
-    ~cBoolSetter() { m_b = !value; }
-};
-
 /// @brief Blocks signals on a QObject until destruction
 using cSignalBlocker = QSignalBlocker;
 
 /** @brief Writes a value on destruction to a pointed-to location.
  *
  * If the pointer is non-null, write the last-given-value if there
- * is one to the pointed-to object.
+ * is one to the pointed-to object. This is called the "then-value".
+ *
  */
 template < typename T >
-struct cPointerSetter
+struct cScopedAssignment
 {
     std::optional< T > m_value;
     T* m_pointer;
@@ -76,22 +63,36 @@ struct cPointerSetter
      * will do nothing on destruction, leaving the pointed-to
      * value unchanged.
      */
-    cPointerSetter( T* p )
+    cScopedAssignment( T* p )
         : m_pointer( p )
     {
     }
-    /** @brief Create a setter with a value already set
+    /** @brief Create a setter with a then-value already set
      *
      * This ensures that on destruction, the value @p v will be written;
      * it is equivalent to assigning @p v immediately. The pointed-to
      * value is **not** changed (until destruction).
      */
-    cPointerSetter( T* p, T v )
-        : m_value( v )
+    cScopedAssignment( T* p, T then )
+        : m_value( then )
         , m_pointer( p )
     {
     }
-    ~cPointerSetter()
+    /** @brief Create a setter with a then-value and assign a new value now
+     *
+     * As above, but also assign @p now to the thing pointed-to.
+     */
+    cScopedAssignment( T* p, T now, T then )
+        : m_value( then )
+        , m_pointer( p )
+    {
+        if ( p )
+        {
+            *p = now;
+        }
+    }
+
+    ~cScopedAssignment()
     {
         if ( m_pointer && m_value.has_value() )
         {
@@ -99,13 +100,13 @@ struct cPointerSetter
         }
     }
 
-    const T& operator=( const T& v )
+    const T& operator=( const T& then )
     {
-        m_value = v;
-        return v;
+        m_value = then;
+        return then;
     }
 };
 
 template < typename T >
-cPointerSetter( T p )->cPointerSetter< decltype( *p ) >;
+cScopedAssignment( T p )->cScopedAssignment< decltype( *p ) >;
 #endif
diff --git a/src/libcalamares/utils/Tests.cpp b/src/libcalamares/utils/Tests.cpp
index a689505e9b32ff48f829eb28b0438ec91491d6b8..c652571b4bd838bd9966bd2527fed0d38fef22bd 100644
--- a/src/libcalamares/utils/Tests.cpp
+++ b/src/libcalamares/utils/Tests.cpp
@@ -55,7 +55,6 @@ private Q_SLOTS:
     void testOddSizedPrintable();
 
     /** @section Tests the RAII bits. */
-    void testBoolSetter();
     void testPointerSetter();
 
     /** @section Tests the Traits bits. */
@@ -340,28 +339,6 @@ LibCalamaresTests::testOddSizedPrintable()
     }
 }
 
-void
-LibCalamaresTests::testBoolSetter()
-{
-    bool b = false;
-
-    QVERIFY( !b );
-    {
-        QVERIFY( !b );
-        cBoolSetter< true > x( b );
-        QVERIFY( b );
-    }
-    QVERIFY( !b );
-
-    QVERIFY( !b );
-    {
-        QVERIFY( !b );
-        cBoolSetter< false > x( b );
-        QVERIFY( !b );  // Still!
-    }
-    QVERIFY( b );
-}
-
 void
 LibCalamaresTests::testPointerSetter()
 {
@@ -369,35 +346,35 @@ LibCalamaresTests::testPointerSetter()
 
     QCOMPARE( special, 17 );
     {
-        cPointerSetter p( &special );
+        cScopedAssignment p( &special );
     }
     QCOMPARE( special, 17 );
     {
-        cPointerSetter p( &special );
+        cScopedAssignment p( &special );
         p = 18;
     }
     QCOMPARE( special, 18 );
     {
-        cPointerSetter p( &special );
+        cScopedAssignment p( &special );
         p = 20;
         p = 3;
     }
     QCOMPARE( special, 3 );
     {
-        cPointerSetter<int> p( nullptr );
+        cScopedAssignment< int > p( nullptr );
     }
     QCOMPARE( special, 3 );
     {
         // "don't do this" .. order of destructors is important
-        cPointerSetter p( &special );
-        cPointerSetter q( &special );
+        cScopedAssignment p( &special );
+        cScopedAssignment q( &special );
         p = 17;
     }
     QCOMPARE( special, 17 );
     {
         // "don't do this" .. order of destructors is important
-        cPointerSetter p( &special );
-        cPointerSetter q( &special );
+        cScopedAssignment p( &special );
+        cScopedAssignment q( &special );
         p = 34;
         q = 2;
         // q destroyed first, then p
@@ -490,8 +467,7 @@ LibCalamaresTests::testVariantStringListCode()
                   QStringList { "astring" } );  // A single string **can** be considered a stringlist!
         m.insert( key, QString( "more strings" ) );
         QCOMPARE( getStringList( m, key ).count(), 1 );
-        QCOMPARE( getStringList( m, key ),
-                  QStringList { "more strings" } );
+        QCOMPARE( getStringList( m, key ), QStringList { "more strings" } );
         m.insert( key, QString() );
         QCOMPARE( getStringList( m, key ).count(), 1 );
         QCOMPARE( getStringList( m, key ), QStringList { QString() } );
diff --git a/src/modules/fstab/fstab.conf b/src/modules/fstab/fstab.conf
index a14165e1568cc39ee0a9e57416f74c23be6bce2b..33fb2c937e72562ea8098bd7a335610c1c1628d7 100644
--- a/src/modules/fstab/fstab.conf
+++ b/src/modules/fstab/fstab.conf
@@ -13,7 +13,7 @@
 # options from this mapping.
 mountOptions:
     default: defaults,noatime
-    btrfs: defaults,noatime,space_cache
+    btrfs: defaults,noatime,space_cache,autodefrag,compress=zstd
 
 # Mount options to use for the EFI System Partition. If not defined, the
 # *mountOptions* for *vfat* are used, or if that is not set either,
@@ -38,10 +38,10 @@ efiMountOptions: umask=0077
 #     swap: discard
 #     btrfs: discard,compress=lzo
 #
-# The standard configuration applies only lzo compression to btrfs
+# The standard configuration applies asynchronous discard support and ssd optimizations to btrfs
 # and does nothing for other filesystems.
 ssdExtraMountOptions:
-    btrfs: ssd,compress=zstd,commit=120
+    btrfs: discard=async,ssd,compress=zstd,commit=120
 
 # Additional options added to each line in /etc/crypttab
 crypttabOptions: luks
diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py
index 3aa6287a1ca5119bfad39227330107df1730435c..b89d0b0b9f1051c99e8053e8d5cefc111e577fee 100644
--- a/src/modules/initcpiocfg/main.py
+++ b/src/modules/initcpiocfg/main.py
@@ -28,45 +28,74 @@ def pretty_name():
     return _("Configuring mkinitcpio.")
 
 
-def cpuinfo():
+def detect_plymouth():
+    """
+    Checks existence (runnability) of plymouth in the target system.
+
+    @return True if plymouth exists in the target, False otherwise
     """
-    Return the information in /proc/cpuinfo as a dictionary in the following
-    format:
+    # Used to only check existence of path /usr/bin/plymouth in target
+    return target_env_call(["sh", "-c", "which plymouth"]) == 0
+
 
-    cpu_info['proc0']={...}
-    cpu_info['proc1']={...}
+class cpuinfo(object):
     """
-    cpu_info = OrderedDict()
-    procinfo = OrderedDict()
-
-    nprocs = 0
-
-    with open('/proc/cpuinfo') as cpuinfo_file:
-        for line in cpuinfo_file:
-            if not line.strip():
-                # end of one processor
-                cpu_info["proc{!s}".format(nprocs)] = procinfo
-                nprocs += 1
-                # Reset
-                procinfo = OrderedDict()
-            else:
-                if len(line.split(':')) == 2:
-                    splitted_line = line.split(':')[1].strip()
-                    procinfo[line.split(':')[0].strip()] = splitted_line
+    Object describing the current CPU's characteristics. It may be
+    be considered a named tuple, there's no behavior here.
+
+    Fields in the object:
+        - is_intel (if it's definitely an Intel CPU)
+        - is_amd (if it's definitely an AMD CPU)
+        - number_of_cores
+    It is possible for both is_* fields to be False.
+    """
+    def __init__(self):
+        self.is_intel = False
+        self.is_amd = False
+        self.number_of_cores = 0
+
+        cpu = self._cpuinfo()
+        self.is_intel = cpu['proc0']['vendor_id'].lower() == "genuineintel"
+        self.is_amd = cpu['proc0']['vendor_id'].lower() == "authenticamd"
+        self.number_of_cores = len(cpu)
+
+    @staticmethod
+    def _cpuinfo():
+        """
+        Return the information in /proc/cpuinfo as a dictionary in the following
+        format:
+
+        cpu_info['proc0']={...}
+        cpu_info['proc1']={...}
+        """
+        cpu_info = OrderedDict()
+        procinfo = OrderedDict()
+
+        nprocs = 0
+
+        with open('/proc/cpuinfo') as cpuinfo_file:
+            for line in cpuinfo_file:
+                if not line.strip():
+                    # end of one processor
+                    cpu_info["proc{!s}".format(nprocs)] = procinfo
+                    nprocs += 1
+                    # Reset
+                    procinfo = OrderedDict()
                 else:
-                    procinfo[line.split(':')[0].strip()] = ''
+                    if len(line.split(':')) == 2:
+                        splitted_line = line.split(':')[1].strip()
+                        procinfo[line.split(':')[0].strip()] = splitted_line
+                    else:
+                        procinfo[line.split(':')[0].strip()] = ''
 
-    return cpu_info
+        return cpu_info
 
 
-def write_mkinitcpio_lines(hooks, modules, files, root_mount_point):
+def get_host_initcpio():
     """
-    Set up mkinitcpio.conf.
-
-    :param hooks:
-    :param modules:
-    :param files:
-    :param root_mount_point:
+    Reads the host system mkinitcpio.conf and returns all
+    the lines from that file, or an empty list if it does
+    not exist.
     """
     hostfile = "/etc/mkinitcpio.conf"
     try:
@@ -76,48 +105,52 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point):
         libcalamares.utils.debug("Could not open host file '%s'" % hostfile)
         mklins = []
 
-    for i in range(len(mklins)):
-        if mklins[i].startswith("HOOKS"):
-            joined_hooks = ' '.join(hooks)
-            mklins[i] = "HOOKS=\"{!s}\"".format(joined_hooks)
-        elif mklins[i].startswith("MODULES"):
-            joined_modules = ' '.join(modules)
-            mklins[i] = "MODULES=\"{!s}\"".format(joined_modules)
-        elif mklins[i].startswith("FILES"):
-            joined_files = ' '.join(files)
-            mklins[i] = "FILES=\"{!s}\"".format(joined_files)
-
-    path = os.path.join(root_mount_point, "etc/mkinitcpio.conf")
+    return mklins
 
-    with open(path, "w") as mkinitcpio_file:
-        mkinitcpio_file.write("\n".join(mklins) + "\n")
 
-
-def detect_plymouth():
+def write_mkinitcpio_lines(hooks, modules, files, root_mount_point):
     """
-    Checks existence (runnability) of plymouth in the target system.
+    Set up mkinitcpio.conf.
 
-    @return True if plymouth exists in the target, False otherwise
+    :param hooks:
+    :param modules:
+    :param files:
+    :param root_mount_point:
     """
-    # Used to only check existence of path /usr/bin/plymouth in target
-    return target_env_call(["sh", "-c", "which plymouth"]) == 0
-
-
-def modify_mkinitcpio_conf(partitions, root_mount_point):
+    mklins = get_host_initcpio()
+
+    target_path = os.path.join(root_mount_point, "etc/mkinitcpio.conf")
+    with open(target_path, "w") as mkinitcpio_file:
+        for line in mklins:
+            # Replace HOOKS, MODULES and FILES lines with what we
+            # have found via find_initcpio_features()
+            if line.startswith("HOOKS"):
+                line = "HOOKS=\"{!s}\"".format(' '.join(hooks))
+            elif line.startswith("MODULES"):
+                line = "MODULES=\"{!s}\"".format(' '.join(modules))
+            elif line.startswith("FILES"):
+                line = "FILES=\"{!s}\"".format(' '.join(files))
+            mkinitcpio_file.write(line + "\n")
+
+
+def find_initcpio_features(partitions, root_mount_point):
     """
-    Modifies mkinitcpio.conf
+    Returns a tuple (hooks, modules, files) needed to support
+    the given @p partitions (filesystems types, encryption, etc)
+    in the target.
 
-    :param partitions:
-    :param root_mount_point:
+    :param partitions: (from GS)
+    :param root_mount_point: (from GS)
+
+    :return 3-tuple of lists
     """
-    cpu = cpuinfo()
-    swap_uuid = ""
-    btrfs = ""
-    lvm2 = ""
-    hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard",
-             "keymap"]
+    hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap", "consolefont"]
     modules = []
     files = []
+
+    swap_uuid = ""
+    uses_btrfs = False
+    uses_lvm2 = False
     encrypt_hook = False
     openswap_hook = False
     unencrypted_separate_boot = False
@@ -144,10 +177,10 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
                 openswap_hook = True
 
         if partition["fs"] == "btrfs":
-            btrfs = "yes"
+            uses_btrfs = True
 
         if "lvm2" in partition["fs"]:
-            lvm2 = "yes"
+            uses_lvm2 = True
 
         if partition["mountPoint"] == "/" and "luksMapperName" in partition:
             encrypt_hook = True
@@ -169,7 +202,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
                ):
             files.append("/crypto_keyfile.bin")
 
-    if lvm2:
+    if uses_lvm2:
         hooks.append("lvm2")
 
     if swap_uuid != "":
@@ -179,15 +212,12 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
     else:
         hooks.extend(["filesystems"])
 
-    if btrfs == "yes" and cpu['proc0']['vendor_id'].lower() != "genuineintel":
-        modules.append("crc32c")
-    elif (btrfs == "yes"
-          and cpu['proc0']['vendor_id'].lower() == "genuineintel"):
-        modules.append("crc32c-intel")
+    if uses_btrfs:
+        modules.append("crc32c-intel" if cpuinfo().is_intel else "crc32c")
     else:
         hooks.append("fsck")
 
-    write_mkinitcpio_lines(hooks, modules, files, root_mount_point)
+    return (hooks, modules, files)
 
 
 def run():
@@ -208,6 +238,7 @@ def run():
         return (_("Configuration Error"),
                 _("No root mount point is given for <pre>{!s}</pre> to use." ).format("initcpiocfg"))
 
-    modify_mkinitcpio_conf(partitions, root_mount_point)
+    hooks, modules, files = find_initcpio_features(partitions, root_mount_point)
+    write_mkinitcpio_lines(hooks, modules, files, root_mount_point)
 
     return None
diff --git a/src/modules/initcpiocfg/module.desc b/src/modules/initcpiocfg/module.desc
index a4476121bedb74bd6e1c734dd48f7f26a758b2ba..a64fdf173a4a8a499e4f490db1264459ee292391 100644
--- a/src/modules/initcpiocfg/module.desc
+++ b/src/modules/initcpiocfg/module.desc
@@ -1,7 +1,13 @@
 # SPDX-FileCopyrightText: no
 # SPDX-License-Identifier: CC0-1.0
+#
+# Writes a mkinitcpio.conf into the target system. It copies
+# the host system's /etc/mkinitcpio.conf, and replaces any
+# HOOKS, MODULES, and FILES lines with calculated values
+# based on what the installation (seems to) need.
 ---
 type:       "job"
 name:       "initcpiocfg"
 interface:  "python"
 script:     "main.py"
+noconfig:   true
diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp
index 7140bd79059c6fa517f97a51cbb8fe91b32fb0cc..720588810aa1b4791d32dd62573dd8411c8fc387 100644
--- a/src/modules/keyboard/Config.cpp
+++ b/src/modules/keyboard/Config.cpp
@@ -275,7 +275,7 @@ Config::detectCurrentKeyboardLayout()
     {
         return;
     }
-    cPointerSetter returnToIntial( &m_state, State::Initial );
+    cScopedAssignment returnToIntial( &m_state, State::Initial );
     m_state = State::Guessing;
 
     //### Detect current keyboard layout and variant
@@ -427,7 +427,7 @@ Config::guessLocaleKeyboardLayout()
     {
         return;
     }
-    cPointerSetter returnToIntial( &m_state, State::Initial );
+    cScopedAssignment returnToIntial( &m_state, State::Initial );
     m_state = State::Guessing;
 
     /* Guessing a keyboard layout based on the locale means
@@ -472,7 +472,7 @@ Config::guessLocaleKeyboardLayout()
         { "el_GR", "gr" }, /* Greek in Greece */
         { "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */
         { "ha_NG", "hausa_NG" }, /* Hausa */
-        { "en_IN", "eng_in" }, /* India, English with Rupee */
+        { "en_IN", "us" }, /* India, US English keyboards are common in India */
     } );
 
     // Try to preselect a layout, depending on language and locale
diff --git a/src/modules/locale/LocaleConfiguration.cpp b/src/modules/locale/LocaleConfiguration.cpp
index c208dc02d6b5bb102bb0a228cac4a88756c085e1..b7b895290e3f19b9dd0973ae853143d88a382fc6 100644
--- a/src/modules/locale/LocaleConfiguration.cpp
+++ b/src/modules/locale/LocaleConfiguration.cpp
@@ -201,6 +201,10 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
                 // but nearly all its native speakers also speak English,
                 // and migrants are likely to use English.
                 { "IE", "en" },
+                // India has many languages even though Hindi is known as
+                // national language but English is used in all computer
+                // and mobile devices.
+                { "IN", "en" },
                 { "IT", "it" },
                 { "MA", "ar" },
                 { "MK", "mk" },
diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp
index f63aed10d53e6b117b52ff0502286a25af6191bb..236f63ec3399dde47d203bd7747d0930c7cee346 100644
--- a/src/modules/locale/LocalePage.cpp
+++ b/src/modules/locale/LocalePage.cpp
@@ -174,7 +174,7 @@ LocalePage::locationChanged( const CalamaresUtils::Locale::TimeZoneData* locatio
     {
         return;
     }
-    cBoolSetter< true > b( m_blockTzWidgetSet );
+    cScopedAssignment b( &m_blockTzWidgetSet, true, false );
 
     // Set region index
     int index = m_regionCombo->findData( location->region() );
diff --git a/src/modules/networkcfg/main.py b/src/modules/networkcfg/main.py
index 35bf67d63ebd317f4b01a17e0552801296297d08..4dc6cbbf7fd09c2340677df5390bbaf948efd250 100644
--- a/src/modules/networkcfg/main.py
+++ b/src/modules/networkcfg/main.py
@@ -29,23 +29,83 @@ def pretty_name():
     return _("Saving network configuration.")
 
 
+def get_live_user():
+    """
+    Gets the "live user" login. This might be "live", or "nitrux",
+    or something similar: it is the login name used *right now*,
+    and network configurations saved for that user, should be applied
+    also for the installed user (which probably has a different name).
+    """
+    # getlogin() is a thin-wrapper, and depends on getlogin(3),
+    # which reads utmp -- and utmp isn't always set up right.
+    try:
+        return os.getlogin()
+    except OSError:
+        pass
+    # getpass will return the **current** user, which is generally root.
+    # That isn't very useful, because the network settings have been
+    # made outside of Calamares-running-as-root, as a different user.
+    #
+    # If Calamares is running as non-root, though, this is fine.
+    import getpass
+    name = getpass.getuser()
+    if name != "root":
+        return name
+
+    # TODO: other mechanisms, e.g. guessing that "live" is the name
+    # TODO: support a what-is-the-live-user setting
+    return None
+
+
+def replace_username(nm_config_filename, live_user, target_user):
+    """
+    If @p live_user isn't None, then go through the given
+    file and replace @p live_user by the @p target_user.
+
+    Reads the file, then (re-)writes it with new permissions lives.
+    """
+    # FIXME: Perhaps if live_user is None, we should just replace **all**
+    #        permissions lines? After all, this is supposed to be a live
+    #        system so **whatever** NM networks are configured, should be
+    #        available to the new user.
+    if live_user is None:
+        return
+    if not os.path.exists(nm_config_filename):
+        return
+
+    with open(target_network, "r") as network_conf:
+        text = network_conf.readlines()
+
+    live_permissions = 'permissions=user:{}:;'.format(live_user)
+    target_permissions = 'permissions=user:{}:;\n'.format(user)
+    with open(target_network, "w") as network_conf:
+        for line in text:
+            if live_permissions in line:
+                line = target_permissions
+            network_conf.write(line)
+
+
+def path_pair(root_mount_point, relative_path):
+    """
+    Returns /relative_path and the relative path in the target system.
+    """
+    return ("/" + relative_path, os.path.join(root_mount_point, relative_path))
+
+
 def run():
     """
     Setup network configuration
     """
     root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
     user = libcalamares.globalstorage.value("username")
-    live_user = os.getlogin()
+    live_user = get_live_user()
 
     if root_mount_point is None:
         libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
         return (_("Configuration Error"),
                 _("No root mount point is given for <pre>{!s}</pre> to use." ).format("networkcfg"))
 
-    source_nm = "/etc/NetworkManager/system-connections/"
-    target_nm = os.path.join(
-        root_mount_point, "etc/NetworkManager/system-connections/"
-        )
+    source_nm, target_nm = path_pair(root_mount_point, "etc/NetworkManager/system-connections/")
 
     # Sanity checks.  We don't want to do anything if a network
     # configuration already exists on the target
@@ -63,27 +123,16 @@ def run():
 
             try:
                 shutil.copy(source_network, target_network, follow_symlinks=False)
-                if live_user in open(target_network).read():
-                    text = []
-                    with open(target_network, "r") as network_conf:
-                        text = network_conf.readlines()
-                        with open(target_network, "w") as network_conf:
-                            for line in text:
-                                if 'permissions=user:{}:;'.format(live_user) in line:
-                                    line = 'permissions=user:{}:;\n'.format(user)
-                                network_conf.write(line)
-                    network_conf.close()
+                replace_username(target_network, live_user, user)
             except FileNotFoundError:
                 libcalamares.utils.debug(
-                    "Can't copy network configuration files in "
-                    + "{}".format(source_network)
+                    "Can't copy network configuration files in {}".format(source_network)
                     )
             except FileExistsError:
                 pass
 
     # We need to overwrite the default resolv.conf in the chroot.
-    source_resolv = "/etc/resolv.conf"
-    target_resolv = os.path.join(root_mount_point, "etc/resolv.conf")
+    source_resolv, target_resolv = path_pair(root_mount_point, "etc/resolv.conf")
     if source_resolv != target_resolv and os.path.exists(source_resolv):
         try:
             os.remove(target_resolv)
diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp
index 54f971f4e6ca26b4fd99a48d92dcfd0b18360d16..806c0ceb37113a2c222246eba6c263ba98cc7dbe 100644
--- a/src/modules/partition/core/PartUtils.cpp
+++ b/src/modules/partition/core/PartUtils.cpp
@@ -126,23 +126,22 @@ canBeResized( Partition* candidate, const Logger::Once& o )
         return false;
     }
 
-    cDebug() << o << "Checking if" << convenienceName( candidate ) << "can be resized.";
     if ( !candidate->fileSystem().supportGrow() || !candidate->fileSystem().supportShrink() )
     {
-        cDebug() << Logger::SubEntry << "NO, filesystem" << candidate->fileSystem().name()
-                 << "does not support resize.";
+        cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", filesystem"
+                 << candidate->fileSystem().name() << "does not support resize.";
         return false;
     }
 
     if ( isPartitionFreeSpace( candidate ) )
     {
-        cDebug() << Logger::SubEntry << "NO, partition is free space";
+        cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition is free space";
         return false;
     }
 
     if ( candidate->isMounted() )
     {
-        cDebug() << Logger::SubEntry << "NO, partition is mounted";
+        cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition is mounted";
         return false;
     }
 
@@ -151,14 +150,14 @@ canBeResized( Partition* candidate, const Logger::Once& o )
         PartitionTable* table = dynamic_cast< PartitionTable* >( candidate->parent() );
         if ( !table )
         {
-            cDebug() << Logger::SubEntry << "NO, no partition table found";
+            cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", no partition table found";
             return false;
         }
 
         if ( table->numPrimaries() >= table->maxPrimaries() )
         {
-            cDebug() << Logger::SubEntry << "NO, partition table already has" << table->maxPrimaries()
-                     << "primary partitions.";
+            cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition table already has"
+                     << table->maxPrimaries() << "primary partitions.";
             return false;
         }
     }
@@ -167,7 +166,8 @@ canBeResized( Partition* candidate, const Logger::Once& o )
     double requiredStorageGiB = getRequiredStorageGiB( ok );
     if ( !ok )
     {
-        cDebug() << Logger::SubEntry << "NO, requiredStorageGiB is not set correctly.";
+        cDebug() << o << "Can not resize" << convenienceName( candidate )
+                 << ", requiredStorageGiB is not set correctly.";
         return false;
     }
 
@@ -200,24 +200,25 @@ canBeResized( Partition* candidate, const Logger::Once& o )
 bool
 canBeResized( DeviceModel* dm, const QString& partitionPath, const Logger::Once& o )
 {
-    cDebug() << o << "Checking if" << partitionPath << "can be resized.";
-    QString partitionWithOs = partitionPath;
-    if ( partitionWithOs.startsWith( "/dev/" ) )
+    if ( partitionPath.startsWith( "/dev/" ) )
     {
         for ( int i = 0; i < dm->rowCount(); ++i )
         {
             Device* dev = dm->deviceForIndex( dm->index( i ) );
-            Partition* candidate = CalamaresUtils::Partition::findPartitionByPath( { dev }, partitionWithOs );
+            Partition* candidate = CalamaresUtils::Partition::findPartitionByPath( { dev }, partitionPath );
             if ( candidate )
             {
                 return canBeResized( candidate, o );
             }
         }
-        cDebug() << Logger::SubEntry << "no Partition* found for" << partitionWithOs;
+        cWarning() << "Can not resize" << partitionPath << ", no Partition* found.";
+        return false;
+    }
+    else
+    {
+        cWarning() << "Can not resize" << partitionPath << ", does not start with /dev";
+        return false;
     }
-
-    cDebug() << Logger::SubEntry << "Partition" << partitionWithOs << "CANNOT BE RESIZED FOR AUTOINSTALL.";
-    return false;
 }
 
 
@@ -250,8 +251,6 @@ lookForFstabEntries( const QString& partitionPath )
     {
         QFile fstabFile( mount.path() + "/etc/fstab" );
 
-        cDebug() << Logger::SubEntry << "reading" << fstabFile.fileName();
-
         if ( fstabFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
         {
             const QStringList fstabLines = QString::fromLocal8Bit( fstabFile.readAll() ).split( '\n' );
@@ -261,10 +260,11 @@ lookForFstabEntries( const QString& partitionPath )
                 fstabEntries.append( FstabEntry::fromEtcFstab( rawLine ) );
             }
             fstabFile.close();
-            cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "lines.";
+            const int lineCount = fstabEntries.count();
             std::remove_if(
                 fstabEntries.begin(), fstabEntries.end(), []( const FstabEntry& x ) { return !x.isValid(); } );
-            cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "fstab entries.";
+            cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "fstab entries from" << lineCount
+                     << "lines in" << fstabFile.fileName();
         }
         else
         {
@@ -529,7 +529,7 @@ efiFilesystemMinimumSize()
 QString
 canonicalFilesystemName( const QString& fsName, FileSystem::Type* fsType )
 {
-    cPointerSetter type( fsType );
+    cScopedAssignment type( fsType );
     if ( fsName.isEmpty() )
     {
         type = FileSystem::Ext4;