Skip to content

Commit

Permalink
[systemsettings] Expose format, unmount, and mount from partitionmode…
Browse files Browse the repository at this point in the history
…l. Contributes to JB#40936
  • Loading branch information
rainemak committed Aug 21, 2018
1 parent 016a17b commit bdedc51
Show file tree
Hide file tree
Showing 17 changed files with 935 additions and 125 deletions.
1 change: 1 addition & 0 deletions src/logging.cpp
Expand Up @@ -33,3 +33,4 @@

Q_LOGGING_CATEGORY(lcVpnLog, "org.sailfishos.settings.vpn", QtWarningMsg)
Q_LOGGING_CATEGORY(lcDeveloperModeLog, "org.sailfishos.settings.developermode", QtWarningMsg)
Q_LOGGING_CATEGORY(lcMemoryCardLog, "org.sailfishos.settings.memorycard", QtWarningMsg)
1 change: 1 addition & 0 deletions src/logging_p.h
Expand Up @@ -36,5 +36,6 @@

Q_DECLARE_LOGGING_CATEGORY(lcVpnLog)
Q_DECLARE_LOGGING_CATEGORY(lcDeveloperModeLog)
Q_DECLARE_LOGGING_CATEGORY(lcMemoryCardLog)

#endif
5 changes: 5 additions & 0 deletions src/partition.cpp
Expand Up @@ -101,6 +101,11 @@ QString Partition::deviceName() const
return d ? d->deviceName : QString();
}

QString Partition::deviceLabel() const
{
return d ? d->deviceLabel : QString();
}

QString Partition::mountPath() const
{
return d ? d->mountPath : QString();
Expand Down
24 changes: 23 additions & 1 deletion src/partition.h
Expand Up @@ -33,6 +33,7 @@
#define PARTITION_H

#include <QSharedData>
#include <QObject>

#include <systemsettingsglobal.h>

Expand All @@ -59,11 +60,31 @@ class SYSTEMSETTINGS_EXPORT Partition
Unmounted,
Mounting,
Mounted,
Unmounting
Unmounting,
Formatting,
Formatted
};

Q_DECLARE_FLAGS(StorageTypes, StorageType)

enum Error {
ErrorFailed,
ErrorCancelled,
ErrorAlreadyCancelled,
ErrorNotAuthorized,
ErrorNotAuthorizedCanObtain,
ErrorNotAuthorizedDismissed,
ErrorAlreadyMounted,
ErrorNotMounted,
ErrorOptionNotPermitted,
ErrorMountedByOtherUser,
ErrorAlreadyUnmounting,
ErrorNotSupported,
ErrorTimedout,
ErrorWouldWakeup,
ErrorDeviceBusy
};

Partition();
Partition(const Partition &partition);
Partition &operator =(const Partition &partition);
Expand All @@ -83,6 +104,7 @@ class SYSTEMSETTINGS_EXPORT Partition

QString devicePath() const;
QString deviceName() const;
QString deviceLabel() const;
QString mountPath() const;

QString filesystemType() const;
Expand Down
4 changes: 4 additions & 0 deletions src/partition_p.h
Expand Up @@ -50,6 +50,7 @@ class PartitionPrivate : public QSharedData
, canMount(false)
, mountFailed(false)
, deviceRoot(false)
, valid(false)
{
}

Expand All @@ -62,6 +63,7 @@ class PartitionPrivate : public QSharedData

QString deviceName;
QString devicePath;
QString deviceLabel;
QString mountPath;
QString filesystemType;
QString activeState;
Expand All @@ -74,6 +76,8 @@ class PartitionPrivate : public QSharedData
bool canMount;
bool mountFailed;
bool deviceRoot;
// If valid, only mount status and available bytes will be checked
bool valid;
};

#endif
107 changes: 63 additions & 44 deletions src/partitionmanager.cpp
Expand Up @@ -31,6 +31,7 @@

#include "partitionmanager_p.h"
#include "udisks2monitor_p.h"
#include "logging_p.h"

#include <QFile>
#include <QRegularExpression>
Expand All @@ -43,6 +44,8 @@
static const auto userName = QString(qgetenv("USER"));
static const auto externalMountPath = QString("/run/media/%1/").arg(userName);

static const QRegularExpression externalMedia(QString("^%1$").arg(externalDevice));

PartitionManagerPrivate *PartitionManagerPrivate::sharedInstance = nullptr;

PartitionManagerPrivate::PartitionManagerPrivate()
Expand All @@ -51,6 +54,11 @@ PartitionManagerPrivate::PartitionManagerPrivate()

sharedInstance = this;
m_udisksMonitor.reset(new UDisks2::Monitor(this));
connect(m_udisksMonitor.data(), &UDisks2::Monitor::status, this, &PartitionManagerPrivate::status);
connect(m_udisksMonitor.data(), &UDisks2::Monitor::errorMessage, this, &PartitionManagerPrivate::errorMessage);
connect(m_udisksMonitor.data(), &UDisks2::Monitor::mountError, this, &PartitionManagerPrivate::mountError);
connect(m_udisksMonitor.data(), &UDisks2::Monitor::unmountError, this, &PartitionManagerPrivate::unmountError);
connect(m_udisksMonitor.data(), &UDisks2::Monitor::formatError, this, &PartitionManagerPrivate::formatError);

QExplicitlySharedDataPointer<PartitionPrivate> root(new PartitionPrivate(this));
root->storageType = Partition::System;
Expand Down Expand Up @@ -97,6 +105,8 @@ PartitionManagerPrivate::PartitionManagerPrivate()
if (root->status == Partition::Mounted) {
m_root = Partition(QExplicitlySharedDataPointer<PartitionPrivate>(root));
}

m_udisksMonitor->getBlockDevices();
}

PartitionManagerPrivate::~PartitionManagerPrivate()
Expand Down Expand Up @@ -156,7 +166,6 @@ void PartitionManagerPrivate::refresh()
partitionFile.readLine();

static const QRegularExpression whitespace(QStringLiteral("\\s+"));
static const QRegularExpression externalMedia(QString("^%1$").arg(externalDevice));
static const QRegularExpression deviceRoot(QStringLiteral("^mmcblk\\d+$"));

while (!partitionFile.atEnd()) {
Expand Down Expand Up @@ -234,14 +243,16 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
for (auto partition : partitions) {
// Reset properties to the unmounted defaults. If the partition is mounted these will be restored
// by the refresh.
partition->status = partition->activeState == QStringLiteral("activating")
? Partition::Mounting
: Partition::Unmounted;
partition->bytesFree = 0;
partition->bytesAvailable = 0;
partition->canMount = false;
partition->readOnly = true;
partition->filesystemType.clear();
if (!partition->valid) {
partition->status = partition->activeState == QStringLiteral("activating")
? Partition::Mounting
: Partition::Unmounted;
partition->canMount = false;
partition->readOnly = true;
partition->filesystemType.clear();
}
}

FILE *mtab = setmntent("/etc/mtab", "r");
Expand All @@ -256,9 +267,11 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
const QString mountPath = QString::fromUtf8(mountEntry.mnt_dir);
const QString devicePath = QString::fromUtf8(mountEntry.mnt_fsname);


for (auto partition : partitions) {
if ((partition->status == Partition::Mounted || partition->status == Partition::Mounting)
&& (partition->storageType != Partition::External || partition->mountPath.startsWith(externalMountPath))) {
if (partition->valid || ((partition->status == Partition::Mounted || partition->status == Partition::Mounting) &&
(partition->storageType != Partition::External ||
partition->mountPath.startsWith(externalMountPath)))) {
continue;
}

Expand All @@ -279,21 +292,6 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
}

endmntent(mtab);

blkid_cache cache = nullptr;

// Query filesystems supported by this device
// Note this will only find filesystems supported either directly by the
// kernel, or by modules already loaded.
QStringList supportedFs;
QFile filesystems(QStringLiteral("/proc/filesystems"));
if (filesystems.open(QIODevice::ReadOnly)) {
QString line = filesystems.readLine();
while (line.length() > 0) {
supportedFs << line.trimmed().split('\t').last();
line = filesystems.readLine();
}
}

for (auto partition : partitions) {
if (partition->status == Partition::Mounted) {
Expand All @@ -312,33 +310,54 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
partition->bytesFree = bytesFree;
partition->bytesAvailable = bytesAvailable;
}
} else if (partition->storageType == Partition::External) {
// Presume the file system can be mounted, unless we can confirm otherwise.
partition->canMount = true;
}
}
}

// If an external partition is unmounted, query the uuid to get the prospective mount path.
if (!cache && blkid_get_cache(&cache, nullptr) < 0) {
qWarning("Failed to load blkid cache");
continue;
}
void PartitionManagerPrivate::mount(const Partition &partition)
{
qCInfo(lcMemoryCardLog) << "Can mount:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName();
if (externalMedia.match(partition.deviceName()).hasMatch()) {
m_udisksMonitor->mount(partition.deviceName());
}
}

// Directly probing the device would be better but requires root permissions.
if (char * const uuid = blkid_get_tag_value(
cache, "UUID", partition->devicePath.toUtf8().constData())) {
partition->mountPath = externalMountPath + QString::fromUtf8(uuid);
void PartitionManagerPrivate::unmount(const Partition &partition)
{
qCInfo(lcMemoryCardLog) << "Can unmount:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName();
if (externalMedia.match(partition.deviceName()).hasMatch()) {
m_udisksMonitor->instance()->unmount(partition.deviceName());
} else {
qCWarning(lcMemoryCardLog) << "Unmount allowed only for external memory cards," << partition.devicePath() << "is not allowed";
}
}

::free(uuid);
}
void PartitionManagerPrivate::format(const Partition &partition, const QString &type, const QString &label)
{
qCInfo(lcMemoryCardLog) << "Can format:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName();

if (char * const type = blkid_get_tag_value(
cache, "TYPE", partition->devicePath.toUtf8().constData())) {
partition->filesystemType = QString::fromUtf8(type);
partition->canMount = !partition->filesystemType.isEmpty() && supportedFs.contains(partition->filesystemType);
if (externalMedia.match(partition.deviceName()).hasMatch()) {
m_udisksMonitor->instance()->format(partition.deviceName(), type, label);
} else {
qCWarning(lcMemoryCardLog) << "Formatting allowed only for external memory cards," << partition.devicePath() << "is not allowed";
}
}

::free(type);
}
QStringList PartitionManagerPrivate::supportedFileSystems() const
{
// Query filesystems supported by this device
// Note this will only find filesystems supported either directly by the
// kernel, or by modules already loaded.
QStringList supportedFs;
QFile filesystems(QStringLiteral("/proc/filesystems"));
if (filesystems.open(QIODevice::ReadOnly)) {
QString line = filesystems.readLine();
while (line.length() > 0) {
supportedFs << line.trimmed().split('\t').last();
line = filesystems.readLine();
}
}
return supportedFs;
}

PartitionManager::PartitionManager(QObject *parent)
Expand Down
12 changes: 12 additions & 0 deletions src/partitionmanager_p.h
Expand Up @@ -63,11 +63,23 @@ class PartitionManagerPrivate : public QObject, public QSharedData
void refresh(PartitionPrivate *partition);
void refresh(const Partitions &partitions, Partitions &changedPartitions);

void mount(const Partition &partition);
void unmount(const Partition &partition);
void format(const Partition &partition, const QString &type, const QString &label);

QStringList supportedFileSystems() const;

signals:
void partitionChanged(const Partition &partition);
void partitionAdded(const Partition &partition);
void partitionRemoved(const Partition &partition);

void status(const QString &deviceName, Partition::Status);
void errorMessage(const QString &objectPath, const QString &errorName);
void mountError(Partition::Error error);
void unmountError(Partition::Error error);
void formatError(Partition::Error error);

private:
static PartitionManagerPrivate *sharedInstance;

Expand Down

0 comments on commit bdedc51

Please sign in to comment.