[luksopenswaphookcfg] Port to C++
Merge pull request #1845 from calamares/issue-1659 FIXES #1659 FIXES #1644
This commit is contained in:
commit
7fc2859f23
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal file
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
|
||||||
|
# use LOSH all over the place as a shorthand.
|
||||||
|
calamares_add_plugin( luksopenswaphook
|
||||||
|
TYPE job
|
||||||
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
|
SOURCES
|
||||||
|
LOSHJob.cpp
|
||||||
|
SHARED_LIB
|
||||||
|
)
|
||||||
|
|
||||||
|
calamares_add_test(
|
||||||
|
luksopenswaphooktest
|
||||||
|
SOURCES
|
||||||
|
LOSHJob.cpp
|
||||||
|
Tests.cpp
|
||||||
|
)
|
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal file
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LUKSOPENSWAPHOOKCFG_LOSHINFO_H
|
||||||
|
#define LUKSOPENSWAPHOOKCFG_LOSHINFO_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
/** @brief Information needed to create a suitable config file
|
||||||
|
*
|
||||||
|
* The LUKS swap configuration has a handful of keys that need to
|
||||||
|
* be written to the config file. This struct holds those keys
|
||||||
|
* and can find the key values from Global Storage (where the
|
||||||
|
* *partition* module sets them).
|
||||||
|
*/
|
||||||
|
struct LOSHInfo
|
||||||
|
{
|
||||||
|
// Member names copied from Python code
|
||||||
|
QString swap_outer_uuid;
|
||||||
|
QString swap_mapper_name;
|
||||||
|
QString mountable_keyfile_device;
|
||||||
|
QString swap_device_path;
|
||||||
|
QString keyfile_device_mount_options;
|
||||||
|
|
||||||
|
bool isValid() const { return !swap_device_path.isEmpty(); }
|
||||||
|
|
||||||
|
/** @brief Helper method for doing key-value replacements
|
||||||
|
*
|
||||||
|
* Given a named @p key (e.g. "duck", or "swap_device"), returns the
|
||||||
|
* value set for that key. Invalid keys (e.g. "duck") return an empty string.
|
||||||
|
*/
|
||||||
|
QString replacementFor( const QString& key ) const
|
||||||
|
{
|
||||||
|
if ( key == QStringLiteral( "swap_device" ) )
|
||||||
|
{
|
||||||
|
return swap_device_path;
|
||||||
|
}
|
||||||
|
if ( key == QStringLiteral( "crypt_swap_name" ) )
|
||||||
|
{
|
||||||
|
return swap_mapper_name;
|
||||||
|
}
|
||||||
|
if ( key == QStringLiteral( "keyfile_device" ) )
|
||||||
|
{
|
||||||
|
return mountable_keyfile_device;
|
||||||
|
}
|
||||||
|
if ( key == QStringLiteral( "keyfile_filename" ) )
|
||||||
|
{
|
||||||
|
return QStringLiteral( "crypto_keyfile.bin" );
|
||||||
|
}
|
||||||
|
if ( key == QStringLiteral( "keyfile_device_mount_options" ) )
|
||||||
|
{
|
||||||
|
return keyfile_device_mount_options;
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Creates a struct from information already set in GS
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static LOSHInfo fromGlobalStorage();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
180
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal file
180
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "LOSHJob.h"
|
||||||
|
|
||||||
|
#include "LOSHInfo.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Permissions.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
#include "utils/String.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
LOSHJob::LOSHJob( QObject* parent )
|
||||||
|
: Calamares::CppJob( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LOSHJob::~LOSHJob() {}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
LOSHJob::prettyName() const
|
||||||
|
{
|
||||||
|
return tr( "Configuring encrypted swap." );
|
||||||
|
}
|
||||||
|
|
||||||
|
STATICTEST QString
|
||||||
|
get_assignment_part( const QString& line )
|
||||||
|
{
|
||||||
|
static QRegularExpression re( "^[# \\t]*([A-Za-z_]+)[ \\t]*=" );
|
||||||
|
auto m = re.match( line );
|
||||||
|
if ( m.hasMatch() )
|
||||||
|
{
|
||||||
|
return m.captured( 1 );
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Writes the config file at @p path
|
||||||
|
*
|
||||||
|
* NOTE: @p path is relative to the target system, not an absolute path.
|
||||||
|
*/
|
||||||
|
STATICTEST void
|
||||||
|
write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info )
|
||||||
|
{
|
||||||
|
if ( info.isValid() )
|
||||||
|
{
|
||||||
|
for ( auto& line : contents )
|
||||||
|
{
|
||||||
|
const QString key = get_assignment_part( line );
|
||||||
|
QString replacement = info.replacementFor( key );
|
||||||
|
if ( !replacement.isEmpty() )
|
||||||
|
{
|
||||||
|
line.clear();
|
||||||
|
line.append( QStringLiteral( "%1=%2" ).arg( key, replacement ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cDebug() << "Writing" << contents.length() << "line configuration to" << path;
|
||||||
|
// \n between each two lines, and a \n at the end
|
||||||
|
CalamaresUtils::System::instance()->createTargetFile(
|
||||||
|
path, contents.join( '\n' ).append( '\n' ).toUtf8(), CalamaresUtils::System::WriteMode::Overwrite );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cDebug() << "Will not write an invalid configuration to" << path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobResult
|
||||||
|
LOSHJob::exec()
|
||||||
|
{
|
||||||
|
const auto* sys = CalamaresUtils::System::instance();
|
||||||
|
if ( !sys )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
"LuksOpenSwapHook", tr( "No target system available." ), Calamares::JobResult::InvalidConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::GlobalStorage* gs
|
||||||
|
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||||
|
if ( !gs || gs->value( "rootMountPoint" ).toString().isEmpty() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
"LuksOpenSwapHook", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||||
|
}
|
||||||
|
if ( m_configFilePath.isEmpty() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
"LuksOpenSwapHook", tr( "No configFilePath is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList contents = sys->readTargetFile( m_configFilePath );
|
||||||
|
if ( contents.isEmpty() )
|
||||||
|
{
|
||||||
|
contents << QStringLiteral( "# swap_device=" ) << QStringLiteral( "# crypt_swap_name=" )
|
||||||
|
<< QStringLiteral( "# keyfile_device=" ) << QStringLiteral( "# keyfile_filename=" )
|
||||||
|
<< QStringLiteral( "# keyfile_device_mount_options" );
|
||||||
|
}
|
||||||
|
|
||||||
|
write_openswap_conf( m_configFilePath, contents, LOSHInfo::fromGlobalStorage() );
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
|
{
|
||||||
|
m_configFilePath = CalamaresUtils::getString(
|
||||||
|
configurationMap, QStringLiteral( "configFilePath" ), QStringLiteral( "/etc/openswap.conf" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
STATICTEST void
|
||||||
|
globalStoragePartitionInfo( Calamares::GlobalStorage* gs, LOSHInfo& info )
|
||||||
|
{
|
||||||
|
if ( !gs )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVariantList l = gs->value( "partitions" ).toList();
|
||||||
|
if ( l.isEmpty() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& pv : l )
|
||||||
|
{
|
||||||
|
const QVariantMap partition = pv.toMap();
|
||||||
|
if ( !partition.isEmpty() )
|
||||||
|
{
|
||||||
|
QString mountPoint = partition.value( "mountPoint" ).toString();
|
||||||
|
QString fileSystem = partition.value( "fs" ).toString();
|
||||||
|
QString luksMapperName = partition.value( "luksMapperName" ).toString();
|
||||||
|
// if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
|
||||||
|
if ( fileSystem == QStringLiteral( "linuxswap" ) && !luksMapperName.isEmpty() )
|
||||||
|
{
|
||||||
|
info.swap_outer_uuid = partition.value( "luksUuid" ).toString();
|
||||||
|
info.swap_mapper_name = luksMapperName;
|
||||||
|
}
|
||||||
|
else if ( mountPoint == QStringLiteral( "/" ) && !luksMapperName.isEmpty() )
|
||||||
|
{
|
||||||
|
|
||||||
|
info.mountable_keyfile_device = QStringLiteral( "/dev/mapper/" ) + luksMapperName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !info.mountable_keyfile_device.isEmpty() && !info.swap_outer_uuid.isEmpty() )
|
||||||
|
{
|
||||||
|
info.swap_device_path = QStringLiteral( "/dev/disk/by-uuid/" ) + info.swap_outer_uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString btrfsRootSubvolume = gs->value( "btrfsRootSubvolume" ).toString();
|
||||||
|
if ( !btrfsRootSubvolume.isEmpty() )
|
||||||
|
{
|
||||||
|
CalamaresUtils::removeLeading( btrfsRootSubvolume, '/' );
|
||||||
|
info.keyfile_device_mount_options
|
||||||
|
= QStringLiteral( "keyfile_device_mount_options=--options=subvol=" ) + btrfsRootSubvolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOSHInfo
|
||||||
|
LOSHInfo::fromGlobalStorage()
|
||||||
|
{
|
||||||
|
LOSHInfo i {};
|
||||||
|
globalStoragePartitionInfo(
|
||||||
|
Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr, i );
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( LOSHJobFactory, registerPlugin< LOSHJob >(); )
|
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal file
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LUKSOPENSWAPHOOKCFG_LOSHJOB_H
|
||||||
|
#define LUKSOPENSWAPHOOKCFG_LOSHJOB_H
|
||||||
|
|
||||||
|
#include "CppJob.h"
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
class PLUGINDLLEXPORT LOSHJob : public Calamares::CppJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LOSHJob( QObject* parent = nullptr );
|
||||||
|
~LOSHJob() override;
|
||||||
|
|
||||||
|
QString prettyName() const override;
|
||||||
|
|
||||||
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_configFilePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( LOSHJobFactory )
|
||||||
|
|
||||||
|
#endif
|
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal file
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LOSHInfo.h"
|
||||||
|
#include "LOSHJob.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
// LOSH = LUKS Open Swap Hook (Job)
|
||||||
|
|
||||||
|
// Implementation details
|
||||||
|
extern QString get_assignment_part( const QString& line );
|
||||||
|
extern void write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info );
|
||||||
|
|
||||||
|
class LOSHTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
LOSHTests();
|
||||||
|
~LOSHTests() override {}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
|
||||||
|
void testAssignmentExtraction_data();
|
||||||
|
void testAssignmentExtraction();
|
||||||
|
|
||||||
|
void testLOSHInfo();
|
||||||
|
void testConfigWriting();
|
||||||
|
void testJob();
|
||||||
|
};
|
||||||
|
|
||||||
|
LOSHTests::LOSHTests() {}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::initTestCase()
|
||||||
|
{
|
||||||
|
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||||
|
cDebug() << "LOSH test started.";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::testAssignmentExtraction_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn< QString >( "line" );
|
||||||
|
QTest::addColumn< QString >( "match" );
|
||||||
|
|
||||||
|
QTest::newRow( "empty" ) << QString() << QString();
|
||||||
|
QTest::newRow( "comment-only1" ) << QStringLiteral( "# " ) << QString();
|
||||||
|
QTest::newRow( "comment-only2" ) << QStringLiteral( "###" ) << QString();
|
||||||
|
QTest::newRow( "comment-only3" ) << QStringLiteral( "# # #" ) << QString();
|
||||||
|
|
||||||
|
QTest::newRow( "comment-text" ) << QStringLiteral( "# NOTE:" ) << QString();
|
||||||
|
QTest::newRow( "comment-story" ) << QStringLiteral( "# This is a shell comment" ) << QString();
|
||||||
|
// We look for assignments, but only for single-words
|
||||||
|
QTest::newRow( "comment-space-eq" ) << QStringLiteral( "# Check that a = b" ) << QString();
|
||||||
|
|
||||||
|
|
||||||
|
QTest::newRow( "assignment1" ) << QStringLiteral( "a=1" ) << QStringLiteral( "a" );
|
||||||
|
QTest::newRow( "assignment2" ) << QStringLiteral( "a = 1" ) << QStringLiteral( "a" );
|
||||||
|
QTest::newRow( "assignment3" ) << QStringLiteral( "# a=1" ) << QStringLiteral( "a" );
|
||||||
|
QTest::newRow( "assignment4" ) << QStringLiteral( "cows = 12" ) << QStringLiteral( "cows" );
|
||||||
|
QTest::newRow( "assignment5" ) << QStringLiteral( "# # cows=1" ) << QStringLiteral( "cows" );
|
||||||
|
QTest::newRow( "assignment6" ) << QStringLiteral( "# moose='cool' # not cows" ) << QStringLiteral( "moose" );
|
||||||
|
QTest::newRow( "assignment7" ) << QStringLiteral( " moose=cows=42" ) << QStringLiteral( "moose" );
|
||||||
|
QTest::newRow( "assignment8" ) << QStringLiteral( "#swap_device=/dev/something" )
|
||||||
|
<< QStringLiteral( "swap_device" );
|
||||||
|
QTest::newRow( "assignment9" ) << QStringLiteral( "# swap_device=/dev/something" )
|
||||||
|
<< QStringLiteral( "swap_device" );
|
||||||
|
QTest::newRow( "assignment10" ) << QStringLiteral( "swap_device=/dev/something" )
|
||||||
|
<< QStringLiteral( "swap_device" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::testAssignmentExtraction()
|
||||||
|
{
|
||||||
|
QFETCH( QString, line );
|
||||||
|
QFETCH( QString, match );
|
||||||
|
|
||||||
|
QCOMPARE( get_assignment_part( line ), match );
|
||||||
|
}
|
||||||
|
|
||||||
|
static CalamaresUtils::System*
|
||||||
|
file_setup( const QTemporaryDir& tempRoot )
|
||||||
|
{
|
||||||
|
CalamaresUtils::System* ss = CalamaresUtils::System::instance();
|
||||||
|
if ( !ss )
|
||||||
|
{
|
||||||
|
ss = new CalamaresUtils::System( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::GlobalStorage* gs
|
||||||
|
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||||
|
if ( !gs )
|
||||||
|
{
|
||||||
|
cDebug() << "Creating new JobQueue";
|
||||||
|
(void)new Calamares::JobQueue();
|
||||||
|
gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||||
|
}
|
||||||
|
if ( gs )
|
||||||
|
{
|
||||||
|
// Working with a rootMountPoint set
|
||||||
|
gs->insert( "rootMountPoint", tempRoot.path() );
|
||||||
|
}
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
make_valid_loshinfo( LOSHInfo& i )
|
||||||
|
{
|
||||||
|
i.swap_outer_uuid = QStringLiteral( "UUID-0000" );
|
||||||
|
i.swap_mapper_name = QStringLiteral( "/dev/mapper/0000" );
|
||||||
|
i.swap_device_path = QStringLiteral( "/dev/sda0" );
|
||||||
|
i.mountable_keyfile_device = QStringLiteral( "/dev/ada0p0s0" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::testLOSHInfo()
|
||||||
|
{
|
||||||
|
LOSHInfo i {};
|
||||||
|
QVERIFY( !i.isValid() );
|
||||||
|
|
||||||
|
make_valid_loshinfo( i );
|
||||||
|
QVERIFY( i.isValid() );
|
||||||
|
QCOMPARE( i.replacementFor( QStringLiteral( "swap_device" ) ), QStringLiteral( "/dev/sda0" ) );
|
||||||
|
QCOMPARE( i.replacementFor( QStringLiteral( "duck" ) ), QString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::testConfigWriting()
|
||||||
|
{
|
||||||
|
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
|
||||||
|
QVERIFY( tempRoot.isValid() );
|
||||||
|
auto* ss = file_setup( tempRoot );
|
||||||
|
QVERIFY( ss );
|
||||||
|
QVERIFY( Calamares::JobQueue::instance()->globalStorage() );
|
||||||
|
QVERIFY( QFile::exists( tempRoot.path() ) );
|
||||||
|
QVERIFY( QFileInfo( tempRoot.path() ).isDir() );
|
||||||
|
|
||||||
|
const QString targetFilePath = QStringLiteral( "losh.conf" );
|
||||||
|
const QString filePath = tempRoot.filePath( targetFilePath );
|
||||||
|
QStringList contents { QStringLiteral( "# Calamares demo" ),
|
||||||
|
QStringLiteral( "# swap_device=a thing" ),
|
||||||
|
QStringLiteral( "# duck duck swap_device=another" ) };
|
||||||
|
|
||||||
|
// When the information is invalid, file contents are unchanged,
|
||||||
|
// and no file is written either.
|
||||||
|
LOSHInfo i {};
|
||||||
|
QVERIFY( !i.isValid() );
|
||||||
|
QVERIFY( !QFile::exists( filePath ) );
|
||||||
|
write_openswap_conf( targetFilePath, contents, i ); // Invalid i
|
||||||
|
QVERIFY( !QFile::exists( filePath ) );
|
||||||
|
QCOMPARE( contents.length(), 3 );
|
||||||
|
QCOMPARE( contents.at( 1 ).left( 4 ), QStringLiteral( "# s" ) );
|
||||||
|
|
||||||
|
// Can we write there at all?
|
||||||
|
QFile derp( filePath );
|
||||||
|
QVERIFY( derp.open( QIODevice::WriteOnly ) );
|
||||||
|
QVERIFY( derp.write( "xx", 2 ) );
|
||||||
|
derp.close();
|
||||||
|
QVERIFY( QFile::exists( filePath ) );
|
||||||
|
QVERIFY( QFile::remove( filePath ) );
|
||||||
|
|
||||||
|
// Once the information is valid, though, the file is written
|
||||||
|
make_valid_loshinfo( i );
|
||||||
|
QVERIFY( i.isValid() );
|
||||||
|
QVERIFY( !QFile::exists( filePath ) );
|
||||||
|
write_openswap_conf( targetFilePath, contents, i ); // Now it is valid
|
||||||
|
QVERIFY( QFile::exists( filePath ) );
|
||||||
|
QCOMPARE( contents.length(), 3 );
|
||||||
|
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/sda0" ) ); // expected key value
|
||||||
|
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/sda0" ) ); // expected line
|
||||||
|
|
||||||
|
// readLine() returns with newlines-added
|
||||||
|
QFile f( filePath );
|
||||||
|
QVERIFY( f.open( QIODevice::ReadOnly ) );
|
||||||
|
QCOMPARE( f.readLine(), QStringLiteral( "# Calamares demo\n" ) );
|
||||||
|
QCOMPARE( f.readLine(), QStringLiteral( "swap_device=/dev/sda0\n" ) );
|
||||||
|
QCOMPARE( f.readLine(), QStringLiteral( "# duck duck swap_device=another\n" ) );
|
||||||
|
QCOMPARE( f.readLine(), QString() );
|
||||||
|
QVERIFY( f.atEnd() );
|
||||||
|
|
||||||
|
// Note how the contents is updated on every write_openswap_conf()
|
||||||
|
i.swap_device_path = QStringLiteral( "/dev/zram/0.zram" );
|
||||||
|
write_openswap_conf( targetFilePath, contents, i ); // Still valid
|
||||||
|
QCOMPARE( contents.length(), 3 );
|
||||||
|
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/zram/0.zram" ) ); // expected key value
|
||||||
|
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/zram/0.zram" ) ); // expected line
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LOSHTests::testJob()
|
||||||
|
{
|
||||||
|
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
|
||||||
|
QVERIFY( tempRoot.isValid() );
|
||||||
|
auto* ss = file_setup( tempRoot );
|
||||||
|
QVERIFY( ss );
|
||||||
|
Calamares::GlobalStorage* gs
|
||||||
|
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||||
|
QVERIFY( gs );
|
||||||
|
|
||||||
|
{
|
||||||
|
QDir d( tempRoot.path() );
|
||||||
|
d.mkdir( "etc" );
|
||||||
|
}
|
||||||
|
|
||||||
|
QVERIFY( !LOSHInfo::fromGlobalStorage().isValid() );
|
||||||
|
QVariantList outerPartition;
|
||||||
|
QVariantMap innerPartition;
|
||||||
|
innerPartition.insert( "mountPoint", "/" );
|
||||||
|
innerPartition.insert( "fs", "ext4" );
|
||||||
|
innerPartition.insert( "luksMapperName", "root" );
|
||||||
|
innerPartition.insert( "luksUUID", "0000" );
|
||||||
|
outerPartition.append( innerPartition );
|
||||||
|
innerPartition.remove( "mountPoint" );
|
||||||
|
innerPartition.insert( "fs", "linuxswap" );
|
||||||
|
innerPartition.insert( "luksMapperName", "swap" );
|
||||||
|
innerPartition.insert( "luksUuid", "0001" );
|
||||||
|
outerPartition.append( innerPartition );
|
||||||
|
gs->insert( "partitions", outerPartition );
|
||||||
|
QVERIFY( LOSHInfo::fromGlobalStorage().isValid() );
|
||||||
|
|
||||||
|
LOSHJob j;
|
||||||
|
j.setConfigurationMap( QVariantMap() );
|
||||||
|
auto jobresult = j.exec();
|
||||||
|
QVERIFY( jobresult );
|
||||||
|
|
||||||
|
{
|
||||||
|
QFile f( tempRoot.filePath( "etc/openswap.conf" ) );
|
||||||
|
QVERIFY( f.exists() );
|
||||||
|
QVERIFY( f.open( QIODevice::ReadOnly ) );
|
||||||
|
cDebug() << f.readAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN( LOSHTests )
|
||||||
|
|
||||||
|
#include "utils/moc-warnings.h"
|
||||||
|
|
||||||
|
#include "Tests.moc"
|
@ -1,100 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2016 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
|
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
|
|
||||||
import libcalamares
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
_ = gettext.translation("calamares-python",
|
|
||||||
localedir=libcalamares.utils.gettext_path(),
|
|
||||||
languages=libcalamares.utils.gettext_languages(),
|
|
||||||
fallback=True).gettext
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_name():
|
|
||||||
return _("Configuring encrypted swap.")
|
|
||||||
|
|
||||||
|
|
||||||
def write_openswap_conf(partitions, root_mount_point, openswap_conf_path):
|
|
||||||
swap_outer_uuid = ""
|
|
||||||
swap_mapper_name = ""
|
|
||||||
mountable_keyfile_device = ""
|
|
||||||
|
|
||||||
for partition in partitions:
|
|
||||||
if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
|
|
||||||
swap_outer_uuid = partition["luksUuid"]
|
|
||||||
swap_mapper_name = partition["luksMapperName"]
|
|
||||||
|
|
||||||
elif partition["mountPoint"] == "/" and "luksMapperName" in partition:
|
|
||||||
mountable_keyfile_device = (
|
|
||||||
"/dev/mapper/{!s}".format(partition["luksMapperName"])
|
|
||||||
)
|
|
||||||
|
|
||||||
if not mountable_keyfile_device or not swap_outer_uuid:
|
|
||||||
return None
|
|
||||||
|
|
||||||
swap_device_path = "/dev/disk/by-uuid/{!s}".format(swap_outer_uuid)
|
|
||||||
|
|
||||||
lines = []
|
|
||||||
with open(os.path.join(root_mount_point,
|
|
||||||
openswap_conf_path), 'r') as openswap_file:
|
|
||||||
lines = [x.strip() for x in openswap_file.readlines()]
|
|
||||||
|
|
||||||
for i in range(len(lines)):
|
|
||||||
if lines[i].startswith("swap_device"):
|
|
||||||
lines[i] = "swap_device={!s}".format(swap_device_path)
|
|
||||||
|
|
||||||
elif lines[i].startswith("crypt_swap_name"):
|
|
||||||
lines[i] = "crypt_swap_name={!s}".format(swap_mapper_name)
|
|
||||||
|
|
||||||
elif lines[i].startswith("keyfile_device"):
|
|
||||||
lines[i] = "keyfile_device={!s}".format(mountable_keyfile_device)
|
|
||||||
|
|
||||||
elif lines[i].startswith("keyfile_filename"):
|
|
||||||
lines[i] = "keyfile_filename=crypto_keyfile.bin"
|
|
||||||
|
|
||||||
elif lines[i].startswith("#keyfile_device_mount_options"):
|
|
||||||
if libcalamares.globalstorage.contains("btrfsRootSubvolume"):
|
|
||||||
btrfs_root_subvolume = libcalamares.globalstorage.value("btrfsRootSubvolume")
|
|
||||||
lines[i] = "keyfile_device_mount_options=--options=subvol=" + btrfs_root_subvolume.lstrip("/")
|
|
||||||
|
|
||||||
with open(os.path.join(root_mount_point,
|
|
||||||
openswap_conf_path), 'w') as openswap_file:
|
|
||||||
openswap_file.write("\n".join(lines) + "\n")
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
"""
|
|
||||||
This module sets up the openswap hook for a resumable encrypted swap.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
|
|
||||||
openswap_conf_path = libcalamares.job.configuration["configFilePath"]
|
|
||||||
partitions = libcalamares.globalstorage.value("partitions")
|
|
||||||
|
|
||||||
if not partitions:
|
|
||||||
libcalamares.utils.warning("partitions is empty, {!s}".format(partitions))
|
|
||||||
return (_("Configuration Error"),
|
|
||||||
_("No partitions are defined for <pre>{!s}</pre> to use.").format("luksopenswaphookcfg"))
|
|
||||||
if not root_mount_point:
|
|
||||||
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("luksopenswaphookcfg"))
|
|
||||||
|
|
||||||
openswap_conf_path = openswap_conf_path.lstrip('/')
|
|
||||||
|
|
||||||
return write_openswap_conf(partitions, root_mount_point, openswap_conf_path)
|
|
@ -1,7 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
---
|
|
||||||
type: "job"
|
|
||||||
name: "luksopenswaphookcfg"
|
|
||||||
interface: "python"
|
|
||||||
script: "main.py"
|
|
Loading…
Reference in New Issue
Block a user