Merge branch 'cpp-umount' into calamares
This commit is contained in:
commit
79683dd83d
@ -14,6 +14,7 @@
|
|||||||
#include "partition/Sync.h"
|
#include "partition/Sync.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/String.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
@ -92,7 +93,7 @@ struct TemporaryMount::Private
|
|||||||
|
|
||||||
|
|
||||||
TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options )
|
TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options )
|
||||||
: m_d( std::make_unique<Private>() )
|
: m_d( std::make_unique< Private >() )
|
||||||
{
|
{
|
||||||
m_d->m_devicePath = devicePath;
|
m_d->m_devicePath = devicePath;
|
||||||
m_d->m_mountDir.setAutoRemove( false );
|
m_d->m_mountDir.setAutoRemove( false );
|
||||||
@ -123,5 +124,32 @@ TemporaryMount::path() const
|
|||||||
return m_d ? m_d->m_mountDir.path() : QString();
|
return m_d ? m_d->m_mountDir.path() : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList< MtabInfo >
|
||||||
|
MtabInfo::fromMtabFilteredByPrefix( const QString& mountPrefix, const QString& mtabPath )
|
||||||
|
{
|
||||||
|
QFile f( mtabPath.isEmpty() ? "/etc/mtab" : mtabPath );
|
||||||
|
if ( !f.open( QIODevice::ReadOnly ) )
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in( &f );
|
||||||
|
QList< MtabInfo > l;
|
||||||
|
while ( !f.atEnd() )
|
||||||
|
{
|
||||||
|
QStringList line = in.readLine().split( ' ', SplitSkipEmptyParts );
|
||||||
|
if ( line.length() == 3 && !line[ 0 ].startsWith( '#' ) )
|
||||||
|
{
|
||||||
|
// Lines have format: <device> <mountpoint> <options>, so check
|
||||||
|
// the mountpoint field. Everything starts with an empty string.
|
||||||
|
if ( line[ 1 ].startsWith( mountPrefix ) )
|
||||||
|
{
|
||||||
|
l.append( { line[ 0 ], line[ 1 ] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Partition
|
} // namespace Partition
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@ -50,6 +51,13 @@ DLLEXPORT int mount( const QString& devicePath,
|
|||||||
*/
|
*/
|
||||||
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
|
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Mount and automatically unmount a device
|
||||||
|
*
|
||||||
|
* The TemporaryMount object mounts a filesystem, and is like calling
|
||||||
|
* the mount() function, above. When the object is destroyed, unmount()
|
||||||
|
* is called with suitable options to undo the original mount.
|
||||||
|
*/
|
||||||
class DLLEXPORT TemporaryMount
|
class DLLEXPORT TemporaryMount
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -68,6 +76,36 @@ private:
|
|||||||
std::unique_ptr< Private > m_d;
|
std::unique_ptr< Private > m_d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Information about a mount point from /etc/mtab
|
||||||
|
*
|
||||||
|
* Entries in /etc/mtab are of the form: <device> <mountpoint> <other>
|
||||||
|
* This struct only stores device and mountpoint.
|
||||||
|
*
|
||||||
|
* The main way of getting these structs is to call fromMtab() to read
|
||||||
|
* an /etc/mtab-like file and storing all of the entries from it.
|
||||||
|
*/
|
||||||
|
struct DLLEXPORT MtabInfo
|
||||||
|
{
|
||||||
|
QString device;
|
||||||
|
QString mountPoint;
|
||||||
|
|
||||||
|
/** @brief Reads an mtab-like file and returns the entries from it
|
||||||
|
*
|
||||||
|
* When @p mtabPath is given, that file is read. If the given name is
|
||||||
|
* empty (e.g. the default) then /etc/mtab is read, instead.
|
||||||
|
*
|
||||||
|
* If @p mountPrefix is given, then only entries that have a mount point
|
||||||
|
* that starts with that prefix are returned.
|
||||||
|
*/
|
||||||
|
static QList< MtabInfo > fromMtabFilteredByPrefix( const QString& mountPrefix = QString(),
|
||||||
|
const QString& mtabPath = QString() );
|
||||||
|
/// @brief Predicate to sort MtabInfo objects by device-name
|
||||||
|
static bool deviceOrder( const MtabInfo& a, const MtabInfo& b ) { return a.device > b.device; }
|
||||||
|
/// @brief Predicate to sort MtabInfo objects by mount-point
|
||||||
|
static bool mountPointOrder( const MtabInfo& a, const MtabInfo& b ) { return a.mountPoint > b.mountPoint; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Partition
|
} // namespace Partition
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "ClearTempMountsJob.h"
|
#include "ClearTempMountsJob.h"
|
||||||
|
|
||||||
|
#include "partition/Mount.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/String.h"
|
#include "utils/String.h"
|
||||||
|
|
||||||
@ -45,51 +46,23 @@ ClearTempMountsJob::exec()
|
|||||||
{
|
{
|
||||||
Logger::Once o;
|
Logger::Once o;
|
||||||
// Fetch a list of current mounts to Calamares temporary directories.
|
// Fetch a list of current mounts to Calamares temporary directories.
|
||||||
QList< QPair< QString, QString > > lst;
|
using MtabInfo = CalamaresUtils::Partition::MtabInfo;
|
||||||
QFile mtab( "/etc/mtab" );
|
auto targetMounts = MtabInfo::fromMtabFilteredByPrefix( QStringLiteral( "/tmp/calamares-" ) );
|
||||||
if ( !mtab.open( QFile::ReadOnly | QFile::Text ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::error( tr( "Cannot get list of temporary mounts." ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
cVerbose() << o << "Opened mtab. Lines:";
|
if ( targetMounts.isEmpty() )
|
||||||
QTextStream in( &mtab );
|
|
||||||
QString lineIn = in.readLine();
|
|
||||||
while ( !lineIn.isNull() )
|
|
||||||
{
|
|
||||||
QStringList line = lineIn.split( ' ', SplitSkipEmptyParts );
|
|
||||||
cVerbose() << o << line.join( ' ' );
|
|
||||||
QString device = line.at( 0 );
|
|
||||||
QString mountPoint = line.at( 1 );
|
|
||||||
if ( mountPoint.startsWith( "/tmp/calamares-" ) )
|
|
||||||
{
|
|
||||||
lst.append( qMakePair( device, mountPoint ) );
|
|
||||||
}
|
|
||||||
lineIn = in.readLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( lst.empty() )
|
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::ok();
|
return Calamares::JobResult::ok();
|
||||||
}
|
}
|
||||||
|
std::sort( targetMounts.begin(), targetMounts.end(), MtabInfo::mountPointOrder );
|
||||||
std::sort(
|
|
||||||
lst.begin(), lst.end(), []( const QPair< QString, QString >& a, const QPair< QString, QString >& b ) -> bool {
|
|
||||||
return a.first > b.first;
|
|
||||||
} );
|
|
||||||
|
|
||||||
QStringList goodNews;
|
QStringList goodNews;
|
||||||
QProcess process;
|
for ( const auto& m : qAsConst( targetMounts ) )
|
||||||
|
|
||||||
for ( const auto& line : qAsConst( lst ) )
|
|
||||||
{
|
{
|
||||||
QString partPath = line.second;
|
cDebug() << o << "Will try to umount path" << m.mountPoint;
|
||||||
cDebug() << o << "Will try to umount path" << partPath;
|
if ( CalamaresUtils::Partition::unmount( m.mountPoint, { "-lv" } ) == 0 )
|
||||||
process.start( "umount", { "-lv", partPath } );
|
|
||||||
process.waitForFinished();
|
|
||||||
if ( process.exitCode() == 0 )
|
|
||||||
{
|
{
|
||||||
goodNews.append( QString( "Successfully unmounted %1." ).arg( partPath ) );
|
// Returns the program's exit code, so 0 is success
|
||||||
|
goodNews.append( QString( "Successfully unmounted %1." ).arg( m.mountPoint ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/modules/umount/CMakeLists.txt
Normal file
19
src/modules/umount/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
calamares_add_plugin( umount
|
||||||
|
TYPE job
|
||||||
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
|
SOURCES
|
||||||
|
UmountJob.cpp
|
||||||
|
SHARED_LIB
|
||||||
|
EMERGENCY
|
||||||
|
)
|
||||||
|
|
||||||
|
calamares_add_test(
|
||||||
|
umounttest
|
||||||
|
SOURCES
|
||||||
|
Tests.cpp
|
||||||
|
)
|
52
src/modules/umount/Tests.cpp
Normal file
52
src/modules/umount/Tests.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* === 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
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UmountJob.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
// Internals of UmountJob.cpp
|
||||||
|
|
||||||
|
// Actual tests
|
||||||
|
class UmountTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
UmountTests() {}
|
||||||
|
~UmountTests() override {}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
void testTrue();
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountTests::initTestCase()
|
||||||
|
{
|
||||||
|
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountTests::testTrue()
|
||||||
|
{
|
||||||
|
QVERIFY( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN( UmountTests )
|
||||||
|
|
||||||
|
#include "utils/moc-warnings.h"
|
||||||
|
|
||||||
|
#include "Tests.moc"
|
158
src/modules/umount/UmountJob.cpp
Normal file
158
src/modules/umount/UmountJob.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* Tags from the Python version of this module:
|
||||||
|
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2016 Anke Boersma <demm@kaosx.us>
|
||||||
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
|
* Tags for the C++ version of this module:
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UmountJob.h"
|
||||||
|
|
||||||
|
#include "partition/Mount.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
UmountJob::UmountJob( QObject* parent )
|
||||||
|
: Calamares::CppJob( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UmountJob::~UmountJob() {}
|
||||||
|
|
||||||
|
QString
|
||||||
|
UmountJob::prettyName() const
|
||||||
|
{
|
||||||
|
return tr( "Unmount file systems." );
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
unmountTargetMounts( const QString& rootMountPoint )
|
||||||
|
{
|
||||||
|
QDir targetMount( rootMountPoint );
|
||||||
|
if ( !targetMount.exists() )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(), "Could not unmount target system." ),
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"The target system is not mounted at '%1'." )
|
||||||
|
.arg( rootMountPoint ),
|
||||||
|
Calamares::JobResult::GenericError );
|
||||||
|
}
|
||||||
|
QString targetMountPath = targetMount.absolutePath();
|
||||||
|
if ( !targetMountPath.endsWith( '/' ) )
|
||||||
|
{
|
||||||
|
targetMountPath.append( '/' );
|
||||||
|
}
|
||||||
|
|
||||||
|
using MtabInfo = CalamaresUtils::Partition::MtabInfo;
|
||||||
|
auto targetMounts = MtabInfo::fromMtabFilteredByPrefix( targetMountPath );
|
||||||
|
std::sort( targetMounts.begin(), targetMounts.end(), MtabInfo::mountPointOrder );
|
||||||
|
|
||||||
|
for ( const auto& m : qAsConst( targetMounts ) )
|
||||||
|
{
|
||||||
|
if ( CalamaresUtils::Partition::unmount( m.mountPoint, { "-lv" } ) )
|
||||||
|
{
|
||||||
|
// Returns the program's exit code, so 0 is success
|
||||||
|
return Calamares::JobResult::error(
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"Could not unmount target system." ),
|
||||||
|
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
|
||||||
|
"The device '%1' is mounted in the target system. It is mounted at '%2'. "
|
||||||
|
"The device could not be unmounted." )
|
||||||
|
.arg( m.device, m.mountPoint ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Calamares::JobResult
|
||||||
|
exportZFSPools( const QString& rootMountPoint )
|
||||||
|
{
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
QStringList poolNames;
|
||||||
|
{
|
||||||
|
// The pools are dictionaries / VariantMaps
|
||||||
|
auto zfs_pool_list = gs->value( "zfsPoolInfo" ).toList();
|
||||||
|
for ( const auto& v : zfs_pool_list )
|
||||||
|
{
|
||||||
|
auto m = v.toMap();
|
||||||
|
QString poolName = m.value( "poolName" ).toString();
|
||||||
|
if ( !poolName.isEmpty() )
|
||||||
|
{
|
||||||
|
poolNames.append( poolName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poolNames.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& poolName : poolNames )
|
||||||
|
{
|
||||||
|
auto result = CalamaresUtils::System::runCommand( { "zpool", "export", poolName }, std::chrono::seconds( 30 ) );
|
||||||
|
if ( result.getExitCode() )
|
||||||
|
{
|
||||||
|
cWarning() << "Failed to export pool" << result.getOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Exporting ZFS pools does not cause the install to fail
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Calamares::JobResult
|
||||||
|
UmountJob::exec()
|
||||||
|
{
|
||||||
|
const auto* sys = CalamaresUtils::System::instance();
|
||||||
|
if ( !sys )
|
||||||
|
{
|
||||||
|
return Calamares::JobResult::internalError(
|
||||||
|
"UMount", 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(
|
||||||
|
"UMount", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the unmounting of target-system filesystems
|
||||||
|
{
|
||||||
|
auto r = unmountTargetMounts( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
if ( !r )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For ZFS systems, export the pools
|
||||||
|
{
|
||||||
|
auto r = exportZFSPools( gs->value( "rootMountPoint" ).toString() );
|
||||||
|
if ( !r )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Calamares::JobResult::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UmountJob::setConfigurationMap( const QVariantMap& map )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( UmountJobFactory, registerPlugin< UmountJob >(); )
|
41
src/modules/umount/UmountJob.h
Normal file
41
src/modules/umount/UmountJob.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* === 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
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UMOUNTJOB_H
|
||||||
|
#define UMOUNTJOB_H
|
||||||
|
|
||||||
|
#include "CppJob.h"
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
/** @brief Write 'random' data: machine id, entropy, UUIDs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class PLUGINDLLEXPORT UmountJob : public Calamares::CppJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UmountJob( QObject* parent = nullptr );
|
||||||
|
~UmountJob() override;
|
||||||
|
|
||||||
|
QString prettyName() const override;
|
||||||
|
|
||||||
|
Calamares::JobResult exec() override;
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( UmountJobFactory )
|
||||||
|
|
||||||
|
#endif // UMOUNTJOB_H
|
@ -1,126 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2016 Anke Boersma <demm@kaosx.us>
|
|
||||||
# SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
import libcalamares
|
|
||||||
from libcalamares.utils import gettext_path, gettext_languages
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
_translation = gettext.translation("calamares-python",
|
|
||||||
localedir=gettext_path(),
|
|
||||||
languages=gettext_languages(),
|
|
||||||
fallback=True)
|
|
||||||
_ = _translation.gettext
|
|
||||||
_n = _translation.ngettext
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_name():
|
|
||||||
return _( "Unmount file systems." )
|
|
||||||
|
|
||||||
|
|
||||||
def list_mounts(root_mount_point):
|
|
||||||
""" List mount points.
|
|
||||||
|
|
||||||
:param root_mount_point:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
lst = []
|
|
||||||
|
|
||||||
root_mount_point = os.path.normpath(root_mount_point)
|
|
||||||
for line in open("/etc/mtab").readlines():
|
|
||||||
device, mount_point, _ = line.split(" ", 2)
|
|
||||||
|
|
||||||
if os.path.commonprefix([root_mount_point, mount_point]) == root_mount_point:
|
|
||||||
lst.append((device, mount_point))
|
|
||||||
|
|
||||||
return lst
|
|
||||||
|
|
||||||
|
|
||||||
def export_zpools(root_mount_point):
|
|
||||||
""" Exports the zpools if defined in global storage
|
|
||||||
|
|
||||||
:param root_mount_point: The absolute path to the root of the install
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
zfs_pool_list = libcalamares.globalstorage.value("zfsPoolInfo")
|
|
||||||
zfs_pool_list.sort(reverse=True, key=lambda x: x["poolName"])
|
|
||||||
if zfs_pool_list:
|
|
||||||
for zfs_pool in zfs_pool_list:
|
|
||||||
try:
|
|
||||||
libcalamares.utils.host_env_process_output(['zpool', 'export', zfs_pool["poolName"]])
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
libcalamares.utils.warning("Failed to export zpool")
|
|
||||||
except Exception as e:
|
|
||||||
# If this fails it shouldn't cause the installation to fail
|
|
||||||
libcalamares.utils.warning("Received exception while exporting zpools: " + format(e))
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
""" Unmounts given mountpoints in decreasing order.
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
|
|
||||||
|
|
||||||
if(libcalamares.job.configuration and
|
|
||||||
"srcLog" in libcalamares.job.configuration or
|
|
||||||
"destLog" in libcalamares.job.configuration):
|
|
||||||
libcalamares.utils.error("Log-file preserving is **deprecated** in the *umount* module and removed in the next release")
|
|
||||||
if(libcalamares.job.configuration and
|
|
||||||
"srcLog" in libcalamares.job.configuration and
|
|
||||||
"destLog" in libcalamares.job.configuration):
|
|
||||||
log_source = libcalamares.job.configuration["srcLog"]
|
|
||||||
log_destination = libcalamares.job.configuration["destLog"]
|
|
||||||
# Relocate log_destination into target system
|
|
||||||
log_destination = '{!s}/{!s}'.format(root_mount_point, log_destination)
|
|
||||||
# Make sure source is a string
|
|
||||||
log_source = '{!s}'.format(log_source)
|
|
||||||
|
|
||||||
# copy installation log before umount
|
|
||||||
if os.path.exists(log_source):
|
|
||||||
try:
|
|
||||||
shutil.copy2(log_source, log_destination)
|
|
||||||
except Exception as e:
|
|
||||||
libcalamares.utils.warning("Could not preserve file {!s}, "
|
|
||||||
"error {!s}".format(log_source, e))
|
|
||||||
|
|
||||||
if not root_mount_point:
|
|
||||||
return ("No mount point for root partition in globalstorage",
|
|
||||||
"globalstorage does not contain a \"rootMountPoint\" key, "
|
|
||||||
"doing nothing")
|
|
||||||
|
|
||||||
if not os.path.exists(root_mount_point):
|
|
||||||
return ("Bad mount point for root partition in globalstorage",
|
|
||||||
"globalstorage[\"rootMountPoint\"] is \"{}\", which does not "
|
|
||||||
"exist, doing nothing".format(root_mount_point))
|
|
||||||
|
|
||||||
lst = list_mounts(root_mount_point)
|
|
||||||
# Sort the list by mount point in decreasing order. This way we can be sure
|
|
||||||
# we unmount deeper dirs first.
|
|
||||||
lst.sort(key=lambda x: x[1], reverse=True)
|
|
||||||
|
|
||||||
for device, mount_point in lst:
|
|
||||||
# On success, no output; if the command fails, its output is
|
|
||||||
# in the exception object.
|
|
||||||
subprocess.check_output(["umount", "-lv", mount_point], stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
export_zpools(root_mount_point)
|
|
||||||
|
|
||||||
os.rmdir(root_mount_point)
|
|
||||||
|
|
||||||
return None
|
|
@ -1,8 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
---
|
|
||||||
type: "job"
|
|
||||||
name: "umount"
|
|
||||||
interface: "python"
|
|
||||||
script: "main.py"
|
|
||||||
emergency: true
|
|
@ -4,31 +4,11 @@
|
|||||||
### Umount Module
|
### Umount Module
|
||||||
#
|
#
|
||||||
# This module represents the last part of the installation, the unmounting
|
# This module represents the last part of the installation, the unmounting
|
||||||
# of partitions used for the install. It is also the last place where it
|
# of partitions used for the install. After this, there is no regular way
|
||||||
# is possible to copy files to the target system.
|
# to modify the target system anymore.
|
||||||
#
|
|
||||||
# The "copy log files" functionality is deprecated; use the *preservefiles*
|
|
||||||
# module instead, which is more flexible.
|
|
||||||
#
|
|
||||||
#
|
#
|
||||||
|
|
||||||
---
|
---
|
||||||
# This is a **deprecated** example. Use the *preservefiles* module
|
|
||||||
# instead, where the equivalent configuration is this:
|
|
||||||
#
|
|
||||||
# files:
|
|
||||||
# - from: log
|
|
||||||
# dest: /var/log/installation.log
|
|
||||||
#
|
|
||||||
# Note that the "equivalent configuration" always finds the log,
|
|
||||||
# and is not dependent on specific user names or the vagaries of
|
|
||||||
# polkit configuration -- so it is a **better** "equivalent".
|
|
||||||
#
|
|
||||||
# example when using a log created by `sudo calamares -d`:
|
|
||||||
#srcLog: "/home/live/installation.log"
|
|
||||||
#destLog: "/var/log/installation.log"
|
|
||||||
srcLog: "/bogus/just/do/not/use/this/anymore.txt"
|
|
||||||
|
|
||||||
# Setting emergency to true will make it so this module is still run
|
# Setting emergency to true will make it so this module is still run
|
||||||
# when a prior module fails
|
# when a prior module fails
|
||||||
# emergency: true
|
emergency: false
|
||||||
|
@ -6,5 +6,4 @@ $id: https://calamares.io/schemas/umount
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
srcLog: { type: string }
|
emergency: { type: boolean }
|
||||||
destLog: { type: string }
|
|
||||||
|
Loading…
Reference in New Issue
Block a user