Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a525359a5 | ||
|
|
7716052fbb | ||
|
|
5e7c6ef005 | ||
|
|
83da9b2485 | ||
|
|
ceea4db418 | ||
|
|
86823162c6 | ||
|
|
19ffdc47bb | ||
|
|
0bd415f83e | ||
|
|
028042afe7 | ||
|
|
59556074cc | ||
|
|
a6a9dc6890 | ||
|
|
ed7d63d913 | ||
|
|
9b1da6ff8c | ||
|
|
7d3c483b35 | ||
|
|
0d057478b0 | ||
|
|
7f750cb145 | ||
|
|
86e77b975f | ||
|
|
70fa9fa766 | ||
|
|
c43bd06860 |
28
CHANGES
Normal file
28
CHANGES
Normal file
@@ -0,0 +1,28 @@
|
||||
<!-- SPDX-FileCopyrightText: no
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
|
||||
This is the changelog for Calamares-Extensions. For each release, the major
|
||||
changes and contributors are listed. Note that Calamares-Extensions does not
|
||||
have a historical changelog -- this log starts with version 1.0.0.
|
||||
|
||||
|
||||
# 1.1.0 (2021-01-04) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Oliver Smith
|
||||
|
||||
Changes and new modules in this release:
|
||||
- *mobile* module bugfixes
|
||||
- *mobile* module SSH daemon can be disabled
|
||||
|
||||
|
||||
# 1.0.0 (2020-12-05) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Oliver Smith
|
||||
- ShalokShalom
|
||||
|
||||
Initial release of Calamares-Extensions as such, with one new module
|
||||
- *mobile*, for PostmarketOS initial configuration
|
||||
|
||||
@@ -26,13 +26,33 @@
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
||||
project(calamares-extensions
|
||||
VERSION 1.0.0
|
||||
VERSION 1.1.0
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
find_package(Calamares 3.2.26 REQUIRED)
|
||||
|
||||
find_package(YAMLCPP REQUIRED)
|
||||
find_package(YAMLCPP REQUIRED) # Needed to untangle some dependencies before Calamares 3.2.36
|
||||
|
||||
### CMAKE SETUP
|
||||
#
|
||||
# Enable IN_LIST
|
||||
if( POLICY CMP0057 )
|
||||
cmake_policy( SET CMP0057 NEW )
|
||||
endif()
|
||||
# Let ``AUTOMOC`` and ``AUTOUIC`` process ``GENERATED`` files.
|
||||
if( POLICY CMP0071 )
|
||||
cmake_policy( SET CMP0071 NEW )
|
||||
endif()
|
||||
# Recognize more macros to trigger automoc
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.10.0")
|
||||
list(APPEND CMAKE_AUTOMOC_MACRO_NAMES
|
||||
"K_PLUGIN_FACTORY_WITH_JSON"
|
||||
"K_EXPORT_PLASMA_DATAENGINE_WITH_JSON"
|
||||
"K_EXPORT_PLASMA_RUNNER"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
### BRANDING
|
||||
#
|
||||
@@ -67,6 +87,9 @@ calamares_add_module_subdirectory( modules/slowpython ) # Python job
|
||||
# which builds a list of explanations; show that list.
|
||||
calamares_explain_skipped_modules( ${SKIPPED_MODULES} )
|
||||
|
||||
### RELEASE SUPPORT
|
||||
#
|
||||
#
|
||||
set( CALAMARES_VERSION ${calamares-extensions_VERSION_MAJOR}.${calamares-extensions_VERSION_MINOR}.${calamares-extensions_VERSION_PATCH} )
|
||||
# In rare cases we have hotfix-releases with a tweak
|
||||
if( calamares-extensions_VERSION_TWEAK )
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
#include "Config.h"
|
||||
#include "PartitionJob.h"
|
||||
#include "UsersJob.h"
|
||||
|
||||
#include "ViewManager.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
Config::Config( QObject* parent )
|
||||
@@ -8,37 +14,88 @@ Config::Config( QObject* parent )
|
||||
{
|
||||
}
|
||||
|
||||
QString
|
||||
cfgStr( const QVariantMap& cfgMap, QString key, QString defaultStr )
|
||||
{
|
||||
QString ret = cfgMap.value( key ).toString();
|
||||
if ( ret.isEmpty() )
|
||||
{
|
||||
return defaultStr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setConfigurationMap( const QVariantMap& cfgMap )
|
||||
{
|
||||
m_osName = cfgStr( cfgMap, "osName", "(unknown)" );
|
||||
m_arch = cfgStr( cfgMap, "arch", "(unknown)" );
|
||||
m_device = cfgStr( cfgMap, "device", "(unknown)" );
|
||||
m_userInterface = cfgStr( cfgMap, "userInterface", "(unknown)" );
|
||||
m_version = cfgStr( cfgMap, "version", "(unknown)" );
|
||||
m_username = cfgStr( cfgMap, "username", "user" );
|
||||
using namespace CalamaresUtils;
|
||||
|
||||
m_cmdLuksFormat = cfgStr( cfgMap, "cmdLuksFormat", "cryptsetup luksFormat --use-random" );
|
||||
m_cmdLuksOpen = cfgStr( cfgMap, "cmdLuksOpen", "cryptsetup luksOpen" );
|
||||
m_cmdMkfsRoot = cfgStr( cfgMap, "cmdMkfsRoot", "mkfs.ext4 -L 'unknownOS_root'" );
|
||||
m_cmdMount = cfgStr( cfgMap, "cmdMount", "mount" );
|
||||
m_targetDeviceRoot = cfgStr( cfgMap, "targetDeviceRoot", "/dev/unknown" );
|
||||
m_osName = getString( cfgMap, "osName", "(unknown)" );
|
||||
m_arch = getString( cfgMap, "arch", "(unknown)" );
|
||||
m_device = getString( cfgMap, "device", "(unknown)" );
|
||||
m_userInterface = getString( cfgMap, "userInterface", "(unknown)" );
|
||||
m_version = getString( cfgMap, "version", "(unknown)" );
|
||||
m_username = getString( cfgMap, "username", "user" );
|
||||
|
||||
m_cmdPasswd = cfgStr( cfgMap, "cmdPasswd", "passwd" );
|
||||
m_cmdSshdEnable = cfgStr( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" );
|
||||
m_cmdSshdDisable = cfgStr( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" );
|
||||
m_cmdSshdUseradd = cfgStr( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" );
|
||||
m_featureSshd = getBool( cfgMap, "featureSshd", true );
|
||||
|
||||
m_cmdLuksFormat = getString( cfgMap, "cmdLuksFormat", "cryptsetup luksFormat --use-random" );
|
||||
m_cmdLuksOpen = getString( cfgMap, "cmdLuksOpen", "cryptsetup luksOpen" );
|
||||
m_cmdMkfsRoot = getString( cfgMap, "cmdMkfsRoot", "mkfs.ext4 -L 'unknownOS_root'" );
|
||||
m_cmdMount = getString( cfgMap, "cmdMount", "mount" );
|
||||
m_targetDeviceRoot = getString( cfgMap, "targetDeviceRoot", "/dev/unknown" );
|
||||
m_targetDeviceRootInternal = getString( cfgMap, "targetDeviceRootInternal", "" );
|
||||
|
||||
m_cmdInternalStoragePrepare = getString( cfgMap, "cmdInternalStoragePrepare", "ondev-internal-storage-prepare" );
|
||||
m_cmdPasswd = getString( cfgMap, "cmdPasswd", "passwd" );
|
||||
m_cmdSshdEnable = getString( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" );
|
||||
m_cmdSshdDisable = getString( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" );
|
||||
m_cmdSshdUseradd = getString( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" );
|
||||
}
|
||||
|
||||
Calamares::JobList
|
||||
Config::createJobs()
|
||||
{
|
||||
QList< Calamares::job_ptr > list;
|
||||
QString cmdSshd = m_isSshEnabled ? m_cmdSshdEnable : m_cmdSshdDisable;
|
||||
|
||||
/* Put users job in queue (should run after unpackfs) */
|
||||
Calamares::Job* j = new UsersJob( m_featureSshd,
|
||||
m_cmdPasswd,
|
||||
cmdSshd,
|
||||
m_cmdSshdUseradd,
|
||||
m_isSshEnabled,
|
||||
m_username,
|
||||
m_userPassword,
|
||||
m_sshdUsername,
|
||||
m_sshdPassword );
|
||||
list.append( Calamares::job_ptr( j ) );
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
Config::runPartitionJobThenLeave( bool b )
|
||||
{
|
||||
/* HACK: run partition job
|
||||
* The "mobile" module has two jobs, the partition job and the users job.
|
||||
* If we added both of them in Config::createJobs(), Calamares would run
|
||||
* them right after each other. But we need the "unpackfs" module to run
|
||||
* inbetween, that's why as workaround, the partition job is started here.
|
||||
* To solve this properly, we would need to place the partition job in an
|
||||
* own module and pass everything via globalstorage. But then we might as
|
||||
* well refactor everything so we can unify the mobile's partition job with
|
||||
* the proper partition job from Calamares. */
|
||||
Calamares::Job* j = new PartitionJob( m_cmdInternalStoragePrepare,
|
||||
m_cmdLuksFormat,
|
||||
m_cmdLuksOpen,
|
||||
m_cmdMkfsRoot,
|
||||
m_cmdMount,
|
||||
m_targetDeviceRoot,
|
||||
m_targetDeviceRootInternal,
|
||||
m_installFromExternalToInternal,
|
||||
m_isFdeEnabled,
|
||||
m_fdePassword );
|
||||
Calamares::JobResult res = j->exec();
|
||||
|
||||
Calamares::ViewManager* v = Calamares::ViewManager::instance();
|
||||
if ( res )
|
||||
{
|
||||
v->next();
|
||||
}
|
||||
else
|
||||
{
|
||||
v->onInstallationFailed( res.message(), res.details() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -80,3 +137,9 @@ Config::setIsFdeEnabled( const bool isFdeEnabled )
|
||||
{
|
||||
m_isFdeEnabled = isFdeEnabled;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setInstallFromExternalToInternal( const bool val )
|
||||
{
|
||||
m_installFromExternalToInternal = val;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "Job.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
@@ -19,6 +22,7 @@ class Config : public QObject
|
||||
Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged )
|
||||
|
||||
/* ssh server + credentials */
|
||||
Q_PROPERTY( bool featureSshd READ featureSshd CONSTANT FINAL )
|
||||
Q_PROPERTY( QString sshdUsername READ sshdUsername WRITE setSshdUsername NOTIFY sshdUsernameChanged )
|
||||
Q_PROPERTY( QString sshdPassword READ sshdPassword WRITE setSshdPassword NOTIFY sshdPasswordChanged )
|
||||
Q_PROPERTY( bool isSshEnabled READ isSshEnabled WRITE setIsSshEnabled )
|
||||
@@ -28,11 +32,16 @@ class Config : public QObject
|
||||
Q_PROPERTY( bool isFdeEnabled READ isFdeEnabled WRITE setIsFdeEnabled )
|
||||
|
||||
/* partition job */
|
||||
Q_PROPERTY( bool runPartitionJobThenLeave READ runPartitionJobThenLeaveDummy WRITE runPartitionJobThenLeave )
|
||||
Q_PROPERTY( QString cmdInternalStoragePrepare READ cmdInternalStoragePrepare CONSTANT FINAL )
|
||||
Q_PROPERTY( QString cmdLuksFormat READ cmdLuksFormat CONSTANT FINAL )
|
||||
Q_PROPERTY( QString cmdLuksOpen READ cmdLuksOpen CONSTANT FINAL )
|
||||
Q_PROPERTY( QString cmdMkfsRoot READ cmdMkfsRoot CONSTANT FINAL )
|
||||
Q_PROPERTY( QString cmdMount READ cmdMount CONSTANT FINAL )
|
||||
Q_PROPERTY( QString targetDeviceRoot READ targetDeviceRoot CONSTANT FINAL )
|
||||
Q_PROPERTY( QString targetDeviceRootInternal READ targetDeviceRootInternal CONSTANT FINAL )
|
||||
Q_PROPERTY(
|
||||
bool installFromExternalToInternal READ installFromExternalToInternal WRITE setInstallFromExternalToInternal )
|
||||
|
||||
/* users job */
|
||||
Q_PROPERTY( QString cmdSshdEnable READ cmdSshdEnable CONSTANT FINAL )
|
||||
@@ -41,6 +50,7 @@ class Config : public QObject
|
||||
public:
|
||||
Config( QObject* parent = nullptr );
|
||||
void setConfigurationMap( const QVariantMap& );
|
||||
Calamares::JobList createJobs();
|
||||
|
||||
/* welcome */
|
||||
QString osName() const { return m_osName; }
|
||||
@@ -55,6 +65,7 @@ public:
|
||||
void setUserPassword( const QString& userPassword );
|
||||
|
||||
/* ssh server + credetials */
|
||||
bool featureSshd() { return m_featureSshd; }
|
||||
QString sshdUsername() const { return m_sshdUsername; }
|
||||
QString sshdPassword() const { return m_sshdPassword; }
|
||||
bool isSshEnabled() { return m_isSshEnabled; }
|
||||
@@ -69,11 +80,17 @@ public:
|
||||
void setIsFdeEnabled( bool isFdeEnabled );
|
||||
|
||||
/* partition job */
|
||||
bool runPartitionJobThenLeaveDummy() { return 0; }
|
||||
void runPartitionJobThenLeave( bool b );
|
||||
QString cmdInternalStoragePrepare() const { return m_cmdInternalStoragePrepare; }
|
||||
QString cmdLuksFormat() const { return m_cmdLuksFormat; }
|
||||
QString cmdLuksOpen() const { return m_cmdLuksOpen; }
|
||||
QString cmdMkfsRoot() const { return m_cmdMkfsRoot; }
|
||||
QString cmdMount() const { return m_cmdMount; }
|
||||
QString targetDeviceRoot() const { return m_targetDeviceRoot; }
|
||||
QString targetDeviceRootInternal() const { return m_targetDeviceRootInternal; }
|
||||
bool installFromExternalToInternal() { return m_installFromExternalToInternal; }
|
||||
void setInstallFromExternalToInternal( const bool val );
|
||||
|
||||
/* users job */
|
||||
QString cmdPasswd() const { return m_cmdPasswd; }
|
||||
@@ -94,6 +111,7 @@ private:
|
||||
QString m_userPassword;
|
||||
|
||||
/* ssh server + credetials */
|
||||
bool m_featureSshd;
|
||||
QString m_sshdUsername;
|
||||
QString m_sshdPassword;
|
||||
bool m_isSshEnabled;
|
||||
@@ -103,11 +121,14 @@ private:
|
||||
bool m_isFdeEnabled = false;
|
||||
|
||||
/* partition job */
|
||||
QString m_cmdInternalStoragePrepare;
|
||||
QString m_cmdLuksFormat;
|
||||
QString m_cmdLuksOpen;
|
||||
QString m_cmdMkfsRoot;
|
||||
QString m_cmdMount;
|
||||
QString m_targetDeviceRoot;
|
||||
QString m_targetDeviceRootInternal;
|
||||
bool m_installFromExternalToInternal;
|
||||
|
||||
/* users job */
|
||||
QString m_cmdPasswd;
|
||||
@@ -116,13 +137,14 @@ private:
|
||||
QString m_cmdSshdUseradd;
|
||||
|
||||
signals:
|
||||
/* booleans we don't read from QML (like isSshEnabled) don't need a signal */
|
||||
|
||||
/* default user */
|
||||
void userPasswordChanged( QString userPassword );
|
||||
|
||||
/* ssh server + credetials */
|
||||
/* ssh server + credentials */
|
||||
void sshdUsernameChanged( QString sshdUsername );
|
||||
void sshdPasswordChanged( QString sshdPassword );
|
||||
/* isSshEnabled doesn't need a signal, we don't read it from QML */
|
||||
|
||||
/* full disk encryption */
|
||||
void fdePasswordChanged( QString fdePassword );
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
#include "MobileQmlViewStep.h"
|
||||
#include "PartitionJob.h"
|
||||
#include "UsersJob.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "locale/LabelModel.h"
|
||||
#include "utils/Dirs.h"
|
||||
@@ -35,34 +32,7 @@ MobileQmlViewStep::MobileQmlViewStep( QObject* parent )
|
||||
void
|
||||
MobileQmlViewStep::onLeave()
|
||||
{
|
||||
Calamares::Job *partition, *users;
|
||||
|
||||
/* HACK: run partition job now */
|
||||
partition = new PartitionJob( m_config->cmdLuksFormat(),
|
||||
m_config->cmdLuksOpen(),
|
||||
m_config->cmdMkfsRoot(),
|
||||
m_config->cmdMount(),
|
||||
m_config->targetDeviceRoot(),
|
||||
m_config->isFdeEnabled(),
|
||||
m_config->fdePassword() );
|
||||
Calamares::JobResult res = partition->exec();
|
||||
if ( !res )
|
||||
{
|
||||
cError() << "PARTITION JOB FAILED: " << res.message();
|
||||
}
|
||||
|
||||
/* Put users job in queue (should run after unpackfs) */
|
||||
m_jobs.clear();
|
||||
QString cmdSshd = m_config->isSshEnabled() ? m_config->cmdSshdEnable() : m_config->cmdSshdDisable();
|
||||
users = new UsersJob( m_config->cmdPasswd(),
|
||||
cmdSshd,
|
||||
m_config->cmdSshdUseradd(),
|
||||
m_config->isSshEnabled(),
|
||||
m_config->username(),
|
||||
m_config->userPassword(),
|
||||
m_config->sshdUsername(),
|
||||
m_config->sshdPassword() );
|
||||
m_jobs.append( Calamares::job_ptr( users ) );
|
||||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -95,7 +65,7 @@ MobileQmlViewStep::isAtEnd() const
|
||||
Calamares::JobList
|
||||
MobileQmlViewStep::jobs() const
|
||||
{
|
||||
return m_jobs;
|
||||
return m_config->createJobs();
|
||||
}
|
||||
|
||||
QObject*
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
|
||||
private:
|
||||
Config* m_config;
|
||||
QList< Calamares::job_ptr > m_jobs;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( MobileQmlViewStepFactory )
|
||||
|
||||
@@ -12,19 +12,25 @@
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
PartitionJob::PartitionJob( QString cmdLuksFormat,
|
||||
QString cmdLuksOpen,
|
||||
QString cmdMkfsRoot,
|
||||
QString cmdMount,
|
||||
QString targetDeviceRoot,
|
||||
PartitionJob::PartitionJob( const QString& cmdInternalStoragePrepare,
|
||||
const QString& cmdLuksFormat,
|
||||
const QString& cmdLuksOpen,
|
||||
const QString& cmdMkfsRoot,
|
||||
const QString& cmdMount,
|
||||
const QString& targetDeviceRoot,
|
||||
const QString& targetDeviceRootInternal,
|
||||
bool installFromExternalToInternal,
|
||||
bool isFdeEnabled,
|
||||
const QString& password )
|
||||
: Calamares::Job()
|
||||
, m_cmdInternalStoragePrepare( cmdInternalStoragePrepare )
|
||||
, m_cmdLuksFormat( cmdLuksFormat )
|
||||
, m_cmdLuksOpen( cmdLuksOpen )
|
||||
, m_cmdMkfsRoot( cmdMkfsRoot )
|
||||
, m_cmdMount( cmdMount )
|
||||
, m_targetDeviceRoot( targetDeviceRoot )
|
||||
, m_targetDeviceRootInternal( targetDeviceRootInternal )
|
||||
, m_installFromExternalToInternal( installFromExternalToInternal )
|
||||
, m_isFdeEnabled( isFdeEnabled )
|
||||
, m_password( password )
|
||||
{
|
||||
@@ -77,10 +83,18 @@ PartitionJob::exec()
|
||||
QString cryptDev = "/dev/mapper/" + cryptName;
|
||||
QString passwordStdin = m_password + "\n";
|
||||
QString dev = m_targetDeviceRoot;
|
||||
QList< QPair< QStringList, QString > > commands = {};
|
||||
|
||||
QList< QPair< QStringList, QString > > commands = {
|
||||
{ { "mkdir", "-p", pathMount }, QString() },
|
||||
};
|
||||
if ( m_installFromExternalToInternal )
|
||||
{
|
||||
dev = m_targetDeviceRootInternal;
|
||||
|
||||
commands.append( {
|
||||
{ { "sh", "-c", m_cmdInternalStoragePrepare }, QString() },
|
||||
} );
|
||||
}
|
||||
|
||||
commands.append( { { { "mkdir", "-p", pathMount }, QString() } } );
|
||||
|
||||
if ( m_isFdeEnabled )
|
||||
{
|
||||
|
||||
@@ -8,11 +8,14 @@ class PartitionJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PartitionJob( QString cmdLuksFormat,
|
||||
QString cmdLuksOpen,
|
||||
QString cmdMkfsRoot,
|
||||
QString cmdMount,
|
||||
QString targetDeviceRoot,
|
||||
PartitionJob( const QString& cmdInternalStoragePrepare,
|
||||
const QString& cmdLuksFormat,
|
||||
const QString& cmdLuksOpen,
|
||||
const QString& cmdMkfsRoot,
|
||||
const QString& cmdMount,
|
||||
const QString& targetDeviceRoot,
|
||||
const QString& targetDeviceRootInternal,
|
||||
bool installFromExternalToInternal,
|
||||
bool isFdeEnabled,
|
||||
const QString& password );
|
||||
|
||||
@@ -22,11 +25,14 @@ public:
|
||||
Calamares::JobList createJobs();
|
||||
|
||||
private:
|
||||
QString m_cmdInternalStoragePrepare;
|
||||
QString m_cmdLuksFormat;
|
||||
QString m_cmdLuksOpen;
|
||||
QString m_cmdMkfsRoot;
|
||||
QString m_cmdMount;
|
||||
QString m_targetDeviceRoot;
|
||||
QString m_targetDeviceRootInternal;
|
||||
bool m_installFromExternalToInternal;
|
||||
bool m_isFdeEnabled;
|
||||
QString m_password;
|
||||
};
|
||||
|
||||
@@ -12,15 +12,17 @@
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
UsersJob::UsersJob( QString cmdPasswd,
|
||||
QString cmdSshd,
|
||||
QString cmdSshdUseradd,
|
||||
UsersJob::UsersJob( bool featureSshd,
|
||||
const QString& cmdPasswd,
|
||||
const QString& cmdSshd,
|
||||
const QString& cmdSshdUseradd,
|
||||
bool isSshEnabled,
|
||||
QString username,
|
||||
QString password,
|
||||
QString sshdUsername,
|
||||
QString sshdPassword )
|
||||
const QString& username,
|
||||
const QString& password,
|
||||
const QString& sshdUsername,
|
||||
const QString& sshdPassword )
|
||||
: Calamares::Job()
|
||||
, m_featureSshd( featureSshd )
|
||||
, m_cmdPasswd( cmdPasswd )
|
||||
, m_cmdSshd( cmdSshd )
|
||||
, m_cmdSshdUseradd( cmdSshdUseradd )
|
||||
@@ -48,14 +50,18 @@ UsersJob::exec()
|
||||
|
||||
QList< QPair< QStringList, QString > > commands = {
|
||||
{ { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" },
|
||||
{ { "sh", "-c", m_cmdSshd }, QString() },
|
||||
};
|
||||
|
||||
if ( m_isSshEnabled )
|
||||
if ( m_featureSshd )
|
||||
{
|
||||
commands.append( { { "sh", "-c", m_cmdSshdUseradd + " " + m_sshdUsername }, QString() } );
|
||||
commands.append(
|
||||
{ { "sh", "-c", m_cmdPasswd + " " + m_sshdUsername }, m_sshdPassword + "\n" + m_sshdPassword + "\n" } );
|
||||
commands.append( { { "sh", "-c", m_cmdSshd }, QString() } );
|
||||
|
||||
if ( m_isSshEnabled )
|
||||
{
|
||||
commands.append( { { "sh", "-c", m_cmdSshdUseradd + " " + m_sshdUsername }, QString() } );
|
||||
commands.append(
|
||||
{ { "sh", "-c", m_cmdPasswd + " " + m_sshdUsername }, m_sshdPassword + "\n" + m_sshdPassword + "\n" } );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( auto command, commands )
|
||||
|
||||
@@ -8,14 +8,15 @@ class UsersJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
UsersJob( QString cmdPasswd,
|
||||
QString cmdSshd,
|
||||
QString cmdSshdUseradd,
|
||||
UsersJob( bool featureSshd,
|
||||
const QString& cmdPasswd,
|
||||
const QString& cmdSshd,
|
||||
const QString& cmdSshdUseradd,
|
||||
bool isSshEnabled,
|
||||
QString username,
|
||||
QString password,
|
||||
QString sshdUsername,
|
||||
QString sshdPassword );
|
||||
const QString& username,
|
||||
const QString& password,
|
||||
const QString& sshdUsername,
|
||||
const QString& sshdPassword );
|
||||
|
||||
QString prettyName() const override;
|
||||
Calamares::JobResult exec() override;
|
||||
@@ -23,6 +24,7 @@ public:
|
||||
Calamares::JobList createJobs();
|
||||
|
||||
private:
|
||||
bool m_featureSshd;
|
||||
QString m_cmdPasswd;
|
||||
QString m_cmdSshd;
|
||||
QString m_cmdSshdUseradd;
|
||||
|
||||
@@ -88,7 +88,7 @@ Item {
|
||||
onClicked: {
|
||||
if (validatePin(userPin, userPinRepeat, errorText)) {
|
||||
config.userPassword = userPin.text;
|
||||
navTo("ssh_confirm");
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Item {
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: welcomeText
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
@@ -37,29 +37,29 @@ Item {
|
||||
}
|
||||
|
||||
Button {
|
||||
id: enableButton
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: welcomeText.bottom
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Enable")
|
||||
onClicked: {
|
||||
config.isFdeEnabled = true;
|
||||
navTo("fde_pass");
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: enableButton.bottom
|
||||
anchors.top: firstButton.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Disable")
|
||||
onClicked: {
|
||||
config.isFdeEnabled = false;
|
||||
navTo("install_confirm");
|
||||
navNextFeature();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ Item {
|
||||
onClicked: {
|
||||
if (validatePassword(password, passwordRepeat, errorText)) {
|
||||
config.fdePassword = password.text;
|
||||
navTo("install_confirm");
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,24 +19,38 @@ Item {
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: welcomeText
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
text: "Once you hit 'install', the installation will begin. It will" +
|
||||
" typically take a few minutes. Do not power off the device" +
|
||||
" until it is done. Afterwards, it will reboot into the" +
|
||||
" installed system."
|
||||
text: (function() {
|
||||
var ret = "Once you hit 'install', the installation will begin." +
|
||||
" It will typically take a few minutes. Do not power off the" +
|
||||
" device until it is done.<br><br>";
|
||||
|
||||
if (config.installFromExternalToInternal) {
|
||||
ret += "<b>After the installation, your device will shutdown" +
|
||||
" automatically. You must remove the external storage" +
|
||||
" (SD card) before booting again.</b>" +
|
||||
"<br><br>" +
|
||||
"Otherwise, your device will boot into the installer" +
|
||||
" again, and not into the installed system."
|
||||
} else {
|
||||
ret += "Afterwards, it will reboot into the installed system.";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}())
|
||||
|
||||
width: 500
|
||||
}
|
||||
|
||||
Button {
|
||||
id: enableButton
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: welcomeText.bottom
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
|
||||
64
modules/mobile/install_target.qml
Normal file
64
modules/mobile/install_target.qml
Normal file
@@ -0,0 +1,64 @@
|
||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
import io.calamares.core 1.0
|
||||
import io.calamares.ui 1.0
|
||||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.10
|
||||
import QtQuick.Layouts 1.3
|
||||
import org.kde.kirigami 2.7 as Kirigami
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Window 2.3
|
||||
import QtQuick.VirtualKeyboard 2.1
|
||||
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
text: "The installation was started from an external storage medium." +
|
||||
"<br>" +
|
||||
"You can either install to the same medium and overwrite the" +
|
||||
" installer, or install to the internal storage.<br>" +
|
||||
"<br>" +
|
||||
"Where would you like to install " + config.osName + "?"
|
||||
|
||||
width: 500
|
||||
}
|
||||
|
||||
Button {
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Internal (eMMC)")
|
||||
onClicked: {
|
||||
config.installFromExternalToInternal = true;
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: firstButton.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("External (SD card)")
|
||||
onClicked: {
|
||||
config.installFromExternalToInternal = false;
|
||||
navNextFeature();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
modules/mobile/install_target_confirm.qml
Normal file
58
modules/mobile/install_target_confirm.qml
Normal file
@@ -0,0 +1,58 @@
|
||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
import io.calamares.core 1.0
|
||||
import io.calamares.ui 1.0
|
||||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.10
|
||||
import QtQuick.Layouts 1.3
|
||||
import org.kde.kirigami 2.7 as Kirigami
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Window 2.3
|
||||
import QtQuick.VirtualKeyboard 2.1
|
||||
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
text: "Are you sure that you want to overwrite the internal storage?" +
|
||||
"<br><br>" +
|
||||
"<b>All existing data on the device will be lost!</b>"
|
||||
width: 500
|
||||
}
|
||||
|
||||
Button {
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Yes")
|
||||
onClicked: {
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: firstButton.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("No")
|
||||
onClicked: {
|
||||
navBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,32 @@
|
||||
## Name of the device (e.g. PinePhone)
|
||||
# device: "(unknown)"
|
||||
|
||||
## Partition that will be formatted and mounted (optionally with FDE) for the rootfs
|
||||
## Partition that will be formatted and mounted (optionally with FDE) for the
|
||||
## rootfs
|
||||
# targetDeviceRoot: "/dev/unknown"
|
||||
|
||||
## Partition that will be formatted and mounted (optionally with FDE) for the
|
||||
## rootfs, on internal storage. The installer OS must not set this, if it was
|
||||
## booted from the internal storage (this is not checked in the mobile
|
||||
## module!).
|
||||
## If this is set, the user gets asked whether they want to install on internal
|
||||
## or external storage. If the user chose internal storage,
|
||||
## cmdInternalStoragePrepare (see below) runs before this partition gets
|
||||
## formatted (see below). A note is displayed, that the device is powered off
|
||||
## after installation and that the user should remove the external storage
|
||||
## medium. So you need to adjust the installer OS to poweroff in that case, and
|
||||
## not reboot. See postmarketos-ondev.git for reference.
|
||||
# targetDeviceRootInternal: ""
|
||||
|
||||
######
|
||||
### Installer Features
|
||||
######
|
||||
|
||||
## Ask whether sshd should be enabled or not. If enabled, add a dedicated ssh
|
||||
## user with proper username and password and suggest to change to key-based
|
||||
## authentication after installation.
|
||||
# featureSshd: true
|
||||
|
||||
#######
|
||||
### Commands running in the installer OS
|
||||
#######
|
||||
@@ -52,6 +75,13 @@
|
||||
## Arguments: <device> <mountpoint>
|
||||
# cmdMount: "mount"
|
||||
|
||||
## When user selects installation from external storage to internal storage
|
||||
## (see targetDeviceRootInternal above), use this command to prepare the
|
||||
## internal storage medium. The command must create a partition table with
|
||||
## two partitions (boot, root) and fill the boot partition. See the
|
||||
## ondev-internal-storage-prepare.sh in postmarketos-ondev as example.
|
||||
# cmdInternalStoragePrepare: "ondev-internal-storage-prepare"
|
||||
|
||||
#######
|
||||
### Commands running in the target OS (chroot)
|
||||
#######
|
||||
|
||||
@@ -17,6 +17,8 @@ Page
|
||||
property var screenPrevious: []
|
||||
property var titles: {
|
||||
"welcome": null, /* titlebar disabled */
|
||||
"install_target": "Installation target",
|
||||
"install_target_confirm": "Warning",
|
||||
"default_pin": "Lockscreen PIN",
|
||||
"ssh_confirm": "SSH server",
|
||||
"ssh_credentials": "SSH credentials",
|
||||
@@ -25,6 +27,31 @@ Page
|
||||
"install_confirm": "Ready to install",
|
||||
"wait": null
|
||||
}
|
||||
property var features: [
|
||||
{"name": "welcome",
|
||||
"screens": ["welcome"]},
|
||||
{"name": "installTarget",
|
||||
"screens": ["install_target", "install_target_confirm"]},
|
||||
{"name": "userPin",
|
||||
"screens": ["default_pin"]},
|
||||
{"name": "sshd",
|
||||
"screens": ["ssh_confirm", "ssh_credentials"]},
|
||||
{"name": "fde",
|
||||
"screens": ["fde_confirm", "fde_pass"]},
|
||||
{"name": "installConfirm",
|
||||
"screens": ["install_confirm", "wait"]}
|
||||
]
|
||||
property var featureIdByScreen: (function() {
|
||||
/* Put "features" above into an index of screen name -> feature id:
|
||||
* featureIdByScreen = {"welcome": 0, "default_pin": 1, ...} */
|
||||
var ret = {};
|
||||
for (var i=0; i<features.length; i++) {
|
||||
for (var j=0; j<features[i]["screens"].length; j++) {
|
||||
ret[ features[i]["screens"][j] ] = i;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}())
|
||||
/* Only allow characters, that can be typed in with the initramfs on-screen keyboard
|
||||
* (osk-sdl: see src/keyboard.cpp). FIXME: make configurable, but keep this as default? */
|
||||
property var allowed_chars:
|
||||
@@ -120,8 +147,13 @@ Page
|
||||
id: timer
|
||||
}
|
||||
|
||||
function skipFeatureInstallTarget() {
|
||||
return config.targetDeviceRootInternal == "";
|
||||
}
|
||||
|
||||
/* Navigation related */
|
||||
function navTo(name, historyPush=true) {
|
||||
console.log("Navigating to screen: " + name);
|
||||
if (historyPush)
|
||||
screenPrevious.push(screen);
|
||||
screen = name;
|
||||
@@ -131,15 +163,71 @@ Page
|
||||
Qt.inputMethod.hide();
|
||||
}
|
||||
function navFinish() {
|
||||
/* Show a waiting screen and wait a second (so it can render), then let
|
||||
* MobileQmlViewStep.cpp::onLeave() create the (encrypted) partition
|
||||
* and mount it. We can't have this as proper job due to ondev#18. */
|
||||
/* Show a waiting screen and wait a second (so it can render). The big
|
||||
* comment in Config.cpp::runPartitionJobThenLeave() explains why this
|
||||
* is necessary. */
|
||||
navTo("wait");
|
||||
timer.interval = 1000;
|
||||
timer.repeat = false;
|
||||
timer.triggered.connect(ViewManager.next);
|
||||
timer.triggered.connect(function() {
|
||||
/* Trigger Config.cpp::runPartitionJobThenLeave(). (We could expose
|
||||
* the function directly with qmlRegisterSingletonType somehow, but
|
||||
* I haven't seen existing Calamares code do that with the Config
|
||||
* object, so just use the side effect of setting the variable, as
|
||||
* done in existing code of Calamares modules.) */
|
||||
config.runPartitionJobThenLeave = 1
|
||||
});
|
||||
timer.start();
|
||||
}
|
||||
function navNextFeature() {
|
||||
var id = featureIdByScreen[screen] + 1;
|
||||
|
||||
/* Skip disabled features */
|
||||
do {
|
||||
/* First letter uppercase */
|
||||
var name = features[id]["name"];
|
||||
var nameUp = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
|
||||
/* Check config.Feature<Name> */
|
||||
var configOption = "feature" + nameUp;
|
||||
if (config[configOption] === false) {
|
||||
console.log("Skipping feature (disabled in config): " + name);
|
||||
id += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check skipFeature<Name>() */
|
||||
var funcName = "skipFeature" + nameUp;
|
||||
if (eval("typeof " + funcName) === "function"
|
||||
&& eval(funcName + "()")) {
|
||||
console.log("Skipping feature (skip function): " + name);
|
||||
id += 1;
|
||||
continue;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
console.log("Navigating to feature: " + features[id]["name"]);
|
||||
return navTo(features[id]["screens"][0]);
|
||||
}
|
||||
function navNext() {
|
||||
var featureId = featureIdByScreen[screen];
|
||||
var featureScreens = features[featureId]["screens"];
|
||||
for (var i = 0; i<featureScreens.length; i++) {
|
||||
/* Seek ahead until i is current screen */
|
||||
if (featureScreens[i] != screen)
|
||||
continue;
|
||||
|
||||
/* Navigate to next screen in same feature */
|
||||
if (i + 1 < featureScreens.length) {
|
||||
var screenNext = featureScreens[i + 1];
|
||||
return navTo(screenNext);
|
||||
}
|
||||
|
||||
/* Screen is last in feature */
|
||||
return navNextFeature();
|
||||
}
|
||||
console.log("ERROR: navNext() failed for screen: " + screen);
|
||||
}
|
||||
function navBack() {
|
||||
if (screenPrevious.length)
|
||||
return navTo(screenPrevious.pop(), false);
|
||||
@@ -183,7 +271,7 @@ Page
|
||||
if (repeat != pin)
|
||||
return validationFailure(errorText,
|
||||
"The PINs don't match.");
|
||||
|
||||
|
||||
return validationFailureClear(errorText);
|
||||
}
|
||||
function validateSshdUsername(username, errorText) {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
<file>welcome.qml</file>
|
||||
|
||||
<file>install_target.qml</file> <!-- install from external to internal? -->
|
||||
<file>install_target_confirm.qml</file> <!-- overwrite internal storage? -->
|
||||
|
||||
<file>default_pin.qml</file> <!-- default user: pin -->
|
||||
<file>ssh_confirm.qml</file> <!-- sshd: enable or not? -->
|
||||
<file>ssh_credentials.qml</file> <!-- sshd user: username, password -->
|
||||
|
||||
@@ -19,7 +19,7 @@ Item {
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: welcomeText
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
@@ -40,29 +40,29 @@ Item {
|
||||
}
|
||||
|
||||
Button {
|
||||
id: enableButton
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: welcomeText.bottom
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Enable")
|
||||
onClicked: {
|
||||
config.isSshEnabled = true;
|
||||
navTo("ssh_credentials");
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: enableButton.bottom
|
||||
anchors.top: firstButton.bottom
|
||||
anchors.topMargin: 40
|
||||
width: 500
|
||||
|
||||
text: qsTr("Disable")
|
||||
onClicked: {
|
||||
config.isSshEnabled = false;
|
||||
navTo("fde_confirm");
|
||||
navNextFeature();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ Item {
|
||||
config.sshdUsername = username.text;
|
||||
config.sshdPassword = password.text;
|
||||
|
||||
navTo("fde_confirm");
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ Page
|
||||
source: "file:///usr/share/calamares/branding/default-mobile/logo.png"
|
||||
}
|
||||
Text {
|
||||
id: welcomeText
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: logo.bottom
|
||||
anchors.topMargin: 50
|
||||
@@ -53,12 +53,12 @@ Page
|
||||
|
||||
Button {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: welcomeText.bottom
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 50
|
||||
width: 500
|
||||
|
||||
text: qsTr("Continue")
|
||||
onClicked: navTo("default_pin")
|
||||
onClicked: navNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user