calamares/src/libcalamares/partition/AutoMount.cpp
2022-02-28 11:29:45 +01:00

150 lines
4.2 KiB
C++

/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
* 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 <QtDBus>
#include <optional>
namespace CalamaresUtils
{
namespace Partition
{
struct AutoMountInfo
{
bool hasSolid = false;
bool wasSolidModuleAutoLoaded = false;
};
/** @section Solid
*
* KDE Solid automount management.
*
* Solid can be influenced through DBus calls to kded5. The following code
* handles Solid: if Solid exists (e.g. we're in a KDE Plasma desktop)
* then try to turn off automount that way.
*/
/** @brief Boilerplate for a call to kded5
*
* Returns a method-call message, ready for arguments and call().
*/
static inline QDBusMessage
kdedCall( const QString& method )
{
return QDBusMessage::createMethodCall(
QStringLiteral( "org.kde.kded5" ), QStringLiteral( "/kded" ), QStringLiteral( "org.kde.kded5" ), method );
}
/** @brief Enables (or disables) automount for Solid
*
* If @p enable is @c true, enables automount. Otherwise, disables it.
* This throws some DBbus messages on the wire and forgets about them.
*/
// 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 );
}
}
/** @brief Check if Solid exists and has automount set
*
* Updates the @p info object with the discovered information.
* - if there is no Solid available on DBus, sets hasSolid to @c false
* - if there is Solid available on DBusm, sets *hasSolid* to @c true
* and places the queried value of automounting in *wasSolidModuleAutoLoaded*.
*/
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 } );
std::optional< bool > result;
QDBusMessage r = dbus.call( msg, QDBus::Block );
if ( r.type() == QDBusMessage::ReplyMessage )
{
auto arg = r.arguments();
if ( arg.length() == 1 )
{
auto v = arg.at( 0 );
if ( v.isValid() && v.type() == QVariant::Bool )
{
result = v.toBool();
}
}
if ( !r.has_value() )
{
cDebug() << "No viable response from Solid" << r.path();
}
}
else
{
// It's an error message
cDebug() << "Solid not available:" << r.errorMessage();
}
info.hasSolid = result.has_value();
info.wasSolidModuleAutoLoaded = result.has_value() ? result.value() : false;
}
std::shared_ptr< AutoMountInfo >
automountDisable( bool disable )
{
auto info = std::make_shared< AutoMountInfo >();
QDBusConnection dbus = QDBusConnection::sessionBus();
// KDE Plasma (Solid) handling
querySolidAutoMount( dbus, *info );
if ( info->hasSolid )
{
cDebug() << "Setting Solid automount to" << ( disable ? "disabled" : "enabled" );
enableSolidAutoMount( dbus, !disable );
}
// TODO: other environments
return info;
}
void
automountRestore( const std::shared_ptr< AutoMountInfo >& info )
{
QDBusConnection dbus = QDBusConnection::sessionBus();
// KDE Plasma (Solid) handling
if ( info->hasSolid )
{
enableSolidAutoMount( dbus, info->wasSolidModuleAutoLoaded );
}
// TODO: other environments
}
} // namespace Partition
} // namespace CalamaresUtils