diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 3964eb3e6..700eff37b 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -77,6 +77,14 @@ set( libSources utils/Yaml.cpp ) +### OPTIONAL Automount support (requires dbus) +# +# +if( Qt5DBus_FOUND) + list( APPEND libSources partition/AutoMount.cpp ) + list( APPEND OPTIONAL_PRIVATE_LIBRARIES Qt5::DBus ) +endif() + ### OPTIONAL Python support # # @@ -252,3 +260,8 @@ calamares_add_test( add_executable( test_geoip geoip/test_geoip.cpp ${geoip_src} ) target_link_libraries( test_geoip calamares Qt5::Network yamlcpp ) calamares_automoc( test_geoip ) + +if ( Qt5DBus_FOUND ) + add_executable( test_automount partition/calautomount.cpp ) + target_link_libraries( test_automount calamares Qt5::DBus ) +endif() diff --git a/src/libcalamares/partition/AutoMount.cpp b/src/libcalamares/partition/AutoMount.cpp new file mode 100644 index 000000000..0fc253067 --- /dev/null +++ b/src/libcalamares/partition/AutoMount.cpp @@ -0,0 +1,89 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + */ + +#include "AutoMount.h" + +#include "utils/Logger.h" + +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +struct AutoMountInfo +{ + bool wasSolidModuleAutoLoaded = false; +}; + +static inline QDBusMessage +kdedCall( const QString& method ) +{ + return QDBusMessage::createMethodCall( + QStringLiteral( "org.kde.kded5" ), QStringLiteral( "/kded" ), QStringLiteral( "org.kde.kded5" ), method ); +} + +// This code comes, roughly, from the KCM for removable devices. +static void +enableSolidAutoMount( QDBusConnection& dbus, bool enable ) +{ + const auto moduleName = QVariant( QStringLiteral( "device_automounter" ) ); + + // Stop module from auto-loading + { + auto msg = kdedCall( QStringLiteral( "setModuleAutoloading" ) ); + msg.setArguments( { moduleName, QVariant( enable ) } ); + dbus.call( msg, QDBus::NoBlock ); + } + + // Stop module + { + auto msg = kdedCall( enable ? QStringLiteral( "loadModule" ) : QStringLiteral( "unloadModule" ) ); + msg.setArguments( { moduleName } ); + dbus.call( msg, QDBus::NoBlock ); + } +} + +static void +querySolidAutoMount( QDBusConnection& dbus, AutoMountInfo& info ) +{ + const auto moduleName = QVariant( QStringLiteral( "device_automounter" ) ); + + // Find previous setting; this **does** need to block + auto msg = kdedCall( QStringLiteral( "isModuleAutoloaded" ) ); + msg.setArguments( { moduleName } ); + QDBusMessage r = dbus.call( msg, QDBus::Block ); + if ( r.type() == QDBusMessage::ReplyMessage ) + { + auto arg = r.arguments(); + cDebug() << arg; + info.wasSolidModuleAutoLoaded = false; + } +} + +std::shared_ptr< AutoMountInfo > +automountDisable( bool disable ) +{ + auto u = std::make_shared< AutoMountInfo >(); + QDBusConnection dbus = QDBusConnection::sessionBus(); + querySolidAutoMount( dbus, *u ); + enableSolidAutoMount( dbus, !disable ); + return u; +} + + +void +automountRestore( std::shared_ptr< AutoMountInfo >&& t ) +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + enableSolidAutoMount( dbus, t->wasSolidModuleAutoLoaded ); +} + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/libcalamares/partition/AutoMount.h b/src/libcalamares/partition/AutoMount.h new file mode 100644 index 000000000..a9a88e320 --- /dev/null +++ b/src/libcalamares/partition/AutoMount.h @@ -0,0 +1,51 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + * + */ + +#ifndef PARTITION_AUTOMOUNT_H +#define PARTITION_AUTOMOUNT_H + +#include "DllMacro.h" + +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +struct AutoMountInfo; + +/** @brief Disable automount + * + * Various subsystems can do "agressive automount", which can get in the + * way of partitioning actions. In particular, Solid can be configured + * to automount every device it sees, and partitioning happens in multiple + * steps (create table, create partition, set partition flags) which are + * blocked if the partition gets mounted partway through the operation. + * + * @param disable set this to false to reverse the sense of the function + * call and force *enabling* automount, instead. + * + * Returns an opaque structure which can be passed to automountRestore() + * to return the system to the previously-configured automount settings. + */ +DLLEXPORT std::shared_ptr< AutoMountInfo > automountDisable( bool disable = true ); + +/** @brief Restore automount settings + * + * Pass the value returned from automountDisable() to restore the + * previous settings. + */ +DLLEXPORT void automountRestore( std::shared_ptr< AutoMountInfo >&& t ); + +} // namespace Partition +} // namespace CalamaresUtils + +#endif diff --git a/src/libcalamares/partition/Sync.h b/src/libcalamares/partition/Sync.h index 8bb516214..bcb2832ed 100644 --- a/src/libcalamares/partition/Sync.h +++ b/src/libcalamares/partition/Sync.h @@ -11,6 +11,8 @@ #ifndef PARTITION_SYNC_H #define PARTITION_SYNC_H +#include "DllMacro.h" + namespace CalamaresUtils { namespace Partition @@ -24,10 +26,10 @@ namespace Partition * are sensitive, and systemd tends to keep disks busy after a change * for a while). */ -void sync(); +DLLEXPORT void sync(); /** @brief RAII class for calling sync() */ -struct Syncer +struct DLLEXPORT Syncer { ~Syncer() { sync(); } }; diff --git a/src/libcalamares/partition/calautomount.cpp b/src/libcalamares/partition/calautomount.cpp new file mode 100644 index 000000000..a91fc3dda --- /dev/null +++ b/src/libcalamares/partition/calautomount.cpp @@ -0,0 +1,52 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2020 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + * + */ + +/** @brief Command-line tool to enable or disable automounting + * + * This application uses Calamares methods to enable or disable + * automount settings in the running system. This can be used to + * test the automount-manipulating code without running + * a full Calamares or doing an installation. + * + */ + +static const char usage[] = "Usage: calautomount <-e|-d>\n" + "\n" + "Enables (if `-e` is passed as command-line option) or\n" + "Disables (if `-d` is passed as command-line option)\n" + "\n" + "automounting of disks in the host system as best it can.\n" + "Exits with code 0 on success or 1 if an unknown option is\n" + "passed on the command-line.\n\n"; + +#include "AutoMount.h" +#include "Sync.h" +#include "utils/Logger.h" + +#include +#include + +int +main( int argc, char** argv ) +{ + QCoreApplication app( argc, argv ); + + if ( ( argc != 2 ) || ( argv[ 1 ][ 0 ] != '-' ) || ( argv[ 1 ][ 1 ] != 'e' && argv[ 1 ][ 1 ] != 'd' ) ) + { + qWarning() << usage; + return 1; + } + + Logger::setupLogfile(); + Logger::setupLogLevel( Logger::LOGDEBUG ); + CalamaresUtils::Partition::automountDisable( argv[ 1 ][ 1 ] == 'd' ); + + return 0; +}