mirror of
https://github.com/parchlinux/calamares.git
synced 2025-02-23 02:15:44 -05:00
Merge branch 'calamares' of github.com:calamares/calamares into calamares
This commit is contained in:
commit
e78f8840ea
15 changed files with 139 additions and 46 deletions
12
README.md
12
README.md
|
@ -17,16 +17,16 @@
|
|||
|
||||
> Calamares is a distribution-independent system installer, with an advanced partitioning
|
||||
> feature for both manual and automated partitioning operations. Calamares is designed to
|
||||
> be customizable by distribution maintainers without need for cumbersome patching,
|
||||
> thanks to third party branding and external modules support.
|
||||
> be customizable by distribution maintainers without the need for cumbersome patching,
|
||||
> thanks to third-party branding and external modules support.
|
||||
|
||||
## Target Audience
|
||||
|
||||
Calamares is a Linux installer; users who install Linux on a computer will hopefully
|
||||
use it just **once**, to install their Linux distribution. Calamares is not
|
||||
a "ready to use" application: distributions apply a huge amount of customisation
|
||||
a "ready to use" application: distributions apply a huge amount of customization
|
||||
and configuration to Calamares, and the target audience for this repository
|
||||
is those distributions, and the people who make those Linux distro's.
|
||||
is those distributions, and the people who make those Linux distros.
|
||||
|
||||
Calamares has some [generic user documentation](https://calamares.io/docs/users-guide/)
|
||||
for end-users, but most of what we have is for distro developers.
|
||||
|
@ -45,10 +45,10 @@ The dependencies are explained in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|||
## Contributing to Calamares
|
||||
|
||||
Calamares welcomes PRs. New issues are welcome, too.
|
||||
There are both the Calamares **core** repository (this one),
|
||||
There are both the Calamares **core** repository (this one)
|
||||
and an **extensions** repository ([Calamares extensions](https://github.com/calamares/calamares-extensions)).
|
||||
|
||||
Contributions to code, modules, documentation, the wiki and the website are all welcome.
|
||||
Contributions to code, modules, documentation, the wiki, and the website are all welcome.
|
||||
There is more information in the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
|
||||
## Join the Conversation
|
||||
|
|
|
@ -197,6 +197,8 @@ desktop_environments = [
|
|||
DesktopEnvironment('/usr/bin/sway', 'sway'),
|
||||
DesktopEnvironment('/usr/bin/ukui-session', 'ukui'),
|
||||
DesktopEnvironment('/usr/bin/cutefish-session', 'cutefish-xsession'),
|
||||
DesktopEnvironment('/usr/bin/river', 'river'),
|
||||
DesktopEnvironment('/usr/bin/Hyprland', 'hyprland'),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -54,8 +54,9 @@ class cpuinfo(object):
|
|||
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"
|
||||
if 'vendor_id' in cpu['proc0']:
|
||||
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
|
||||
|
|
|
@ -9,7 +9,6 @@ calamares_add_plugin(luksbootkeyfile
|
|||
SOURCES
|
||||
LuksBootKeyFileJob.cpp
|
||||
SHARED_LIB
|
||||
NO_CONFIG
|
||||
)
|
||||
|
||||
calamares_add_test(luksbootkeyfiletest SOURCES Tests.cpp LuksBootKeyFileJob.cpp)
|
||||
|
|
|
@ -135,34 +135,64 @@ generateTargetKeyfile()
|
|||
}
|
||||
|
||||
static bool
|
||||
setupLuks( const LuksDevice& d )
|
||||
setupLuks( const LuksDevice& d, const QString& luks2Hash )
|
||||
{
|
||||
// Sometimes this error is thrown: "All key slots full"
|
||||
// luksAddKey will fail. So, remove the first slot to make room
|
||||
// Get luksDump for this device
|
||||
auto luks_dump = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "cryptsetup", "luksDump", d.device }, QString(), QString(), std::chrono::seconds( 5 ) );
|
||||
if ( luks_dump.getExitCode() == 0 )
|
||||
{ QStringLiteral( "cryptsetup" ), QStringLiteral( "luksDump" ), d.device },
|
||||
QString(),
|
||||
QString(),
|
||||
std::chrono::seconds( 5 ) );
|
||||
if ( luks_dump.getExitCode() != 0 )
|
||||
{
|
||||
QRegularExpression re( QStringLiteral( R"(\d+:\s*enabled)" ), QRegularExpression::CaseInsensitiveOption );
|
||||
int count = luks_dump.getOutput().count( re );
|
||||
cDebug() << "Luks Dump slot count: " << count;
|
||||
if ( count >= 7 )
|
||||
cWarning() << "Could not get LUKS information on " << d.device << ':' << luks_dump.getOutput() << "(exit code"
|
||||
<< luks_dump.getExitCode() << ')';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check LUKS version
|
||||
int luks_version = 0;
|
||||
QRegularExpression version_re( QStringLiteral( R"(version:\s*([0-9]))" ),
|
||||
QRegularExpression::CaseInsensitiveOption );
|
||||
QRegularExpressionMatch match = version_re.match( luks_dump.getOutput() );
|
||||
if ( ! match.hasMatch() )
|
||||
{
|
||||
cWarning() << "Could not get LUKS version on device: " << d.device;
|
||||
return false;
|
||||
}
|
||||
bool ok;
|
||||
luks_version = match.captured(1).toInt(&ok);
|
||||
if( ! ok )
|
||||
{
|
||||
cWarning() << "Could not get LUKS version on device: " << d.device;
|
||||
return false;
|
||||
}
|
||||
cDebug() << "LUKS" << luks_version << " found on device: " << d.device;
|
||||
|
||||
// Check the number of slots used for LUKS1 devices
|
||||
if ( luks_version == 1 )
|
||||
{
|
||||
QRegularExpression slots_re( QStringLiteral( R"(\d+:\s*enabled)" ),
|
||||
QRegularExpression::CaseInsensitiveOption );
|
||||
if ( luks_dump.getOutput().count( slots_re ) == 8 )
|
||||
{
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "cryptsetup", "luksKillSlot", d.device, "1" }, QString(), d.passphrase, std::chrono::seconds( 60 ) );
|
||||
if ( r.getExitCode() != 0 )
|
||||
{
|
||||
cWarning() << "Could not kill a slot to make room on" << d.device << ':' << r.getOutput()
|
||||
<< "(exit code" << r.getExitCode() << ')';
|
||||
return false;
|
||||
}
|
||||
cWarning() << "No key slots left on LUKS1 device: " << d.device;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Adding the key can take some times, measured around 15 seconds with
|
||||
// a HDD (spinning rust) and a slow-ish computer. Give it a minute.
|
||||
// Add the key to the keyfile
|
||||
QStringList args = { QStringLiteral( "cryptsetup" ), QStringLiteral( "luksAddKey" ), d.device, keyfile };
|
||||
if ( luks_version == 2 && luks2Hash != QString() )
|
||||
{
|
||||
args.insert(2, "--pbkdf");
|
||||
args.insert(3, luks2Hash);
|
||||
}
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "cryptsetup", "luksAddKey", d.device, keyfile }, QString(), d.passphrase, std::chrono::seconds( 60 ) );
|
||||
args,
|
||||
QString(),
|
||||
d.passphrase,
|
||||
std::chrono::seconds( 60 ) );
|
||||
if ( r.getExitCode() != 0 )
|
||||
{
|
||||
cWarning() << "Could not configure LUKS keyfile on" << d.device << ':' << r.getOutput() << "(exit code"
|
||||
|
@ -259,15 +289,15 @@ LuksBootKeyFileJob::exec()
|
|||
|
||||
if ( it == s.devices.begin() )
|
||||
{
|
||||
// Then there was no root partition
|
||||
cDebug() << Logger::SubEntry << "No root partition.";
|
||||
// User has configured non-root partition for encryption
|
||||
cDebug() << Logger::SubEntry << "No root partition, skipping keyfile creation.";
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
// /boot partition is not encrypted, keyfile must not be used
|
||||
// But only if root partition is not encrypted
|
||||
if ( hasUnencryptedSeparateBoot() && !hasEncryptedRoot() )
|
||||
{
|
||||
// /boot partition is not encrypted, keyfile must not be used
|
||||
// But only if root partition is not encrypted
|
||||
cDebug() << Logger::SubEntry << "/boot partition is not encrypted, skipping keyfile creation.";
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
@ -295,13 +325,22 @@ LuksBootKeyFileJob::exec()
|
|||
continue;
|
||||
}
|
||||
|
||||
if ( !setupLuks( d ) )
|
||||
return Calamares::JobResult::error(
|
||||
tr( "Encrypted rootfs setup error" ),
|
||||
tr( "Could not configure LUKS key file on partition %1." ).arg( d.device ) );
|
||||
if ( !setupLuks( d, m_luks2Hash ) )
|
||||
{
|
||||
// Could not configure the LUKS partition
|
||||
// This should not stop the installation: do not return Calamares::JobResult::error.
|
||||
cError() << "Encrypted rootfs setup error: could not configure LUKS key file on partition " << d.device;
|
||||
}
|
||||
}
|
||||
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
void
|
||||
LuksBootKeyFileJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_luks2Hash = CalamaresUtils::getString(
|
||||
configurationMap, QStringLiteral( "luks2Hash" ), QString() );
|
||||
}
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( LuksBootKeyFileJobFactory, registerPlugin< LuksBootKeyFileJob >(); )
|
||||
|
|
|
@ -30,6 +30,11 @@ public:
|
|||
QString prettyName() const override;
|
||||
|
||||
Calamares::JobResult exec() override;
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
private:
|
||||
QString m_luks2Hash;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( LuksBootKeyFileJobFactory )
|
||||
|
|
13
src/modules/luksbootkeyfile/luksbootkeyfile.conf
Normal file
13
src/modules/luksbootkeyfile/luksbootkeyfile.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
# Luksbootkeyfile configuration. A key file is created for the
|
||||
# LUKS encrypted devices.
|
||||
---
|
||||
# Set Password-Based Key Derivation Function (PBKDF) algorithm
|
||||
# for LUKS keyslot.
|
||||
#
|
||||
# There are three usable values: pbkdf2, argon2i or argon2id.
|
||||
#
|
||||
# When not set, the cryptsetup default is used
|
||||
#luks2Hash: argon2id
|
9
src/modules/luksbootkeyfile/luksbootkeyfile.schema.yaml
Normal file
9
src/modules/luksbootkeyfile/luksbootkeyfile.schema.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SPDX-FileCopyrightText: 2023 Arjen Balfoort <arjenbalfoort@hotmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
---
|
||||
$schema: https://json-schema.org/schema#
|
||||
$id: https://calamares.io/schemas/luksbootkeyfile
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
luks2Hash: { type: string, enum: [ pbkdf2, argon2i, argon2id ] }
|
|
@ -282,12 +282,12 @@ class PMDnf(PackageManager):
|
|||
backend = "dnf"
|
||||
|
||||
def install(self, pkgs, from_local=False):
|
||||
check_target_env_call(["dnf", "-y", "install"] + pkgs)
|
||||
check_target_env_call(["dnf-3", "-y", "install"] + pkgs)
|
||||
|
||||
def remove(self, pkgs):
|
||||
# ignore the error code for now because dnf thinks removing a
|
||||
# nonexistent package is an error
|
||||
target_env_call(["dnf", "--disablerepo=*", "-C", "-y",
|
||||
target_env_call(["dnf-3", "--disablerepo=*", "-C", "-y",
|
||||
"remove"] + pkgs)
|
||||
|
||||
def update_db(self):
|
||||
|
@ -295,7 +295,7 @@ class PMDnf(PackageManager):
|
|||
pass
|
||||
|
||||
def update_system(self):
|
||||
check_target_env_call(["dnf", "-y", "upgrade"])
|
||||
check_target_env_call(["dnf-3", "-y", "upgrade"])
|
||||
|
||||
|
||||
class PMDummy(PackageManager):
|
||||
|
|
|
@ -415,6 +415,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
|||
m_requiredPartitionTableType = CalamaresUtils::getStringList( configurationMap, "requiredPartitionTableType" );
|
||||
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
gs->insert( "armInstall", CalamaresUtils::getBool( configurationMap, "armInstall", false ) );
|
||||
fillGSConfigurationEFI( gs, configurationMap );
|
||||
fillConfigurationFSTypes( configurationMap );
|
||||
}
|
||||
|
|
|
@ -443,7 +443,15 @@ runOsprober( DeviceModel* dm )
|
|||
bool
|
||||
isEfiSystem()
|
||||
{
|
||||
return QDir( "/sys/firmware/efi/efivars" ).exists();
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
if ( gs->contains( "armInstall" ) && gs->value( "armInstall" ).toBool() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return QDir( "/sys/firmware/efi/efivars" ).exists();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -95,8 +95,16 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
|
|||
// the logical sector size (usually 512B). EFI starts with 2MiB
|
||||
// empty and a EFI boot partition, while BIOS starts at
|
||||
// the 1MiB boundary (usually sector 2048).
|
||||
int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB;
|
||||
|
||||
// ARM empty sectors are 16 MiB in size.
|
||||
int empty_space_sizeB;
|
||||
if ( gs->contains( "armInstall" ) && gs->value( "armInstall" ).toBool() )
|
||||
{
|
||||
empty_space_sizeB = 16_MiB;
|
||||
}
|
||||
else
|
||||
{
|
||||
empty_space_sizeB = isEfi ? 2_MiB : 1_MiB;
|
||||
}
|
||||
// Since sectors count from 0, if the space is 2048 sectors in size,
|
||||
// the first free sector has number 2048 (and there are 2048 sectors
|
||||
// before that one, numbered 0..2047).
|
||||
|
|
|
@ -124,6 +124,13 @@ initialPartitioningChoice: none
|
|||
# one of the items from the options.
|
||||
initialSwapChoice: none
|
||||
|
||||
# armInstall
|
||||
#
|
||||
# Leaves 16MB empty at the start of a drive when partitioning
|
||||
# where usually the u-boot loader goes
|
||||
#
|
||||
# armInstall: false
|
||||
|
||||
# Default partition table type, used when a "erase" disk is made.
|
||||
#
|
||||
# When erasing a disk, a new partition table is created on disk.
|
||||
|
|
|
@ -14,6 +14,7 @@ properties:
|
|||
userSwapChoices: { type: array, items: { type: string, enum: [ none, reuse, small, suspend, file ] } }
|
||||
# ensureSuspendToDisk: { type: boolean, default: true } # Legacy
|
||||
# neverCreateSwap: { type: boolean, default: false } # Legacy
|
||||
armInstall: { type: boolean, default: false }
|
||||
|
||||
allowZfsEncryption: { type: boolean, default: true }
|
||||
drawNestedPartitions: { type: boolean, default: false }
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
# # finally masks pacman-init (an ArchLinux-only service).
|
||||
# #
|
||||
# units:
|
||||
# - name: "NetworkManager"
|
||||
# - name: "NetworkManager.service"
|
||||
# action: "enable"
|
||||
# mandatory: true
|
||||
#
|
||||
|
@ -40,12 +40,12 @@
|
|||
# # The property "mandatory" is taken to be false by default here
|
||||
# # because it is not specified
|
||||
#
|
||||
# - name: "graphical"
|
||||
# - name: "graphical.target"
|
||||
# action: "enable"
|
||||
# # The property "mandatory" is taken to be false by default here
|
||||
# # because it is not specified
|
||||
#
|
||||
# - name: "pacman-init"
|
||||
# - name: "pacman-init.service"
|
||||
# action: "mask"
|
||||
# # The property "mandatory" is taken to be false by default here
|
||||
# # because it is not specified
|
||||
|
|
Loading…
Add table
Reference in a new issue