diff --git a/src/core/device.h b/src/core/device.h index 5425539..d74184b 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -1,115 +1,114 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #ifndef KPMCORE_DEVICE_H #define KPMCORE_DEVICE_H #include "util/libpartitionmanagerexport.h" #include #include #include class PartitionTable; class CreatePartitionTableOperation; class CoreBackend; class SmartStatus; class DevicePrivate; /** A device description. Represents a device like /dev/sda. Contains information about the device (name, status, size ..) but does not operate on the device itself. @see CoreBackendDevice Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. @see PartitionTable, Partition @author Volker Lanz */ class LIBKPMCORE_EXPORT Device : public QObject { Device &operator=(const Device &) = delete; friend class CreatePartitionTableOperation; friend class CoreBackend; public: enum class Type { Unknown_Device, Disk_Device, LVM_Device, /* VG */ RAID_Device, /* software RAID device */ }; -protected: explicit Device(std::shared_ptr d_ptr, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogicalSectors, const QString& iconName = QString(), Device::Type type = Device::Type::Disk_Device); public: explicit Device(const Device& other); virtual ~Device(); virtual bool operator==(const Device& other) const; virtual bool operator!=(const Device& other) const; /**< @return the Device's name, usually some manufacturer string */ virtual QString& name(); virtual const QString& name() const; /**< @return the Device's node, for example "/dev/sda" */ virtual const QString& deviceNode() const; /**< @return the logical sector size the Device uses (would be extent size for e.g. LVM devices) */ virtual qint64 logicalSize() const; /**< @return the total number of logical sectors on the device */ virtual qint64 totalLogical() const; /**< @return the Device's PartitionTable */ virtual PartitionTable* partitionTable(); virtual const PartitionTable* partitionTable() const; /** * Change the description of the partition table for different one. * The device itself is not changed; use CreatePartitionTableOperation * for that. The Device instance becomes the owner of @p ptable . */ virtual void setPartitionTable(PartitionTable* ptable); virtual qint64 capacity() const { /**< @return the Device's capacity in bytes */ return logicalSize() * totalLogical(); } /**< @return suggested icon name for this Device */ virtual const QString& iconName() const; /**< @param name set the new Icon for this Device */ virtual void setIconName(const QString& name); virtual SmartStatus& smartStatus(); virtual const SmartStatus& smartStatus() const; virtual Device::Type type() const; virtual QString prettyName() const; protected: std::shared_ptr d; }; #endif diff --git a/src/jobs/setfilesystemlabeljob.cpp b/src/jobs/setfilesystemlabeljob.cpp index ea1402b..640e275 100644 --- a/src/jobs/setfilesystemlabeljob.cpp +++ b/src/jobs/setfilesystemlabeljob.cpp @@ -1,74 +1,91 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "jobs/setfilesystemlabeljob.h" +#include "backend/corebackend.h" +#include "backend/corebackendmanager.h" +#include "backend/corebackenddevice.h" +#include "backend/corebackendpartitiontable.h" + +#include "core/device_p.h" +#include "core/operationstack.h" #include "core/partition.h" #include "fs/filesystem.h" #include "util/report.h" #include +#include + /** Creates a new SetFileSystemLabelJob @param p the Partition the FileSystem whose label is to be set is on @param newlabel the new label */ SetFileSystemLabelJob::SetFileSystemLabelJob(Partition& p, const QString& newlabel) : Job(), m_Partition(p), m_Label(newlabel) { } bool SetFileSystemLabelJob::run(Report& parent) { bool rval = true; Report* report = jobStarted(parent); // If there's no support for file system label setting for this file system, // just ignore the request and say all is well. This helps in operations because // we don't have to check for support to avoid having a failed job. if (partition().fileSystem().supportSetLabel() == FileSystem::cmdSupportNone) report->line() << xi18nc("@info:progress", "File system on partition %1 does not support setting labels. Job ignored.", partition().deviceNode()); else if (partition().fileSystem().supportSetLabel() == FileSystem::cmdSupportFileSystem && !partition().isMounted()) { rval = partition().fileSystem().writeLabel(*report, partition().deviceNode(), label()); if (rval) partition().fileSystem().setLabel(label()); } else if (partition().fileSystem().supportSetLabelOnline() == FileSystem::cmdSupportFileSystem && partition().isMounted()) { rval = partition().fileSystem().writeLabelOnline(*report, partition().deviceNode(), partition().mountPoint(), label()); if (rval) partition().fileSystem().setLabel(label()); } - // FIXME: need to commit to device + // A hack to reread partition table (commit() should be called even on non DiskDevices) + Device dev(std::make_shared(), QString(), QString(), 0, 0, QString(), Device::Type::Unknown_Device); + std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(dev); + if (backendDevice) { + std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); + + if (backendPartitionTable) + backendPartitionTable->commit(); + } jobFinished(*report, rval); return rval; } QString SetFileSystemLabelJob::description() const { return xi18nc("@info:progress", "Set the file system label on partition %1 to \"%2\"", partition().deviceNode(), label()); } diff --git a/src/plugins/sfdisk/sfdiskpartitiontable.cpp b/src/plugins/sfdisk/sfdiskpartitiontable.cpp index a33dbc9..0c6ea3d 100644 --- a/src/plugins/sfdisk/sfdiskpartitiontable.cpp +++ b/src/plugins/sfdisk/sfdiskpartitiontable.cpp @@ -1,254 +1,252 @@ /************************************************************************* * Copyright (C) 2017 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "plugins/sfdisk/sfdiskpartitiontable.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "core/partition.h" #include "core/device.h" #include "fs/filesystem.h" #include "util/report.h" #include "util/externalcommand.h" -#include - #include #include #include #include #include SfdiskPartitionTable::SfdiskPartitionTable(const Device* d) : CoreBackendPartitionTable(), m_device(d) { } SfdiskPartitionTable::~SfdiskPartitionTable() { } bool SfdiskPartitionTable::open() { return true; } bool SfdiskPartitionTable::commit(quint32 timeout) { - if ( !(ExternalCommand(QStringLiteral("udevadm"), { QStringLiteral("settle"), QStringLiteral("--timeout=") + QString::number(timeout) }).run() && - ExternalCommand(QStringLiteral("blockdev"), { QStringLiteral("--rereadpt"), m_device->deviceNode() }).run())) - sleep(1); + ExternalCommand(QStringLiteral("udevadm"), { QStringLiteral("settle"), QStringLiteral("--timeout=") + QString::number(timeout) }).run(); + ExternalCommand(QStringLiteral("blockdev"), { QStringLiteral("--rereadpt"), m_device->deviceNode() }).run(); + ExternalCommand(QStringLiteral("udevadm"), { QStringLiteral("trigger") }).run(); return true; } QString SfdiskPartitionTable::createPartition(Report& report, const Partition& partition) { if ( !(partition.roles().has(PartitionRole::Extended) || partition.roles().has(PartitionRole::Logical) || partition.roles().has(PartitionRole::Primary) ) ) { report.line() << xi18nc("@info:progress", "Unknown partition role for new partition %1 (roles: %2)", partition.deviceNode(), partition.roles().toString()); return QString(); } QByteArray type = QByteArray(); if (partition.roles().has(PartitionRole::Extended)) type = QByteArrayLiteral(" type=5"); // NOTE: at least on GPT partition types "are" partition flags ExternalCommand createCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--force"), QStringLiteral("--append"), partition.devicePath() } ); if ( createCommand.write(QByteArrayLiteral("start=") + QByteArray::number(partition.firstSector()) + type + QByteArrayLiteral(" size=") + QByteArray::number(partition.length()) + QByteArrayLiteral("\nwrite\n")) && createCommand.start(-1) && createCommand.waitFor() ) { QRegularExpression re(QStringLiteral("Created a new partition (\\d)")); QRegularExpressionMatch rem = re.match(createCommand.output()); if (rem.hasMatch()) return partition.devicePath() + rem.captured(1); } report.line() << xi18nc("@info:progress", "Failed to add partition %1 to device %2.", partition.deviceNode(), m_device->deviceNode()); return QString(); } bool SfdiskPartitionTable::deletePartition(Report& report, const Partition& partition) { ExternalCommand deleteCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--force"), QStringLiteral("--delete"), partition.devicePath(), QString::number(partition.number()) } ); if (deleteCommand.run(-1) && deleteCommand.exitCode() == 0) return true; report.line() << xi18nc("@info:progress", "Could not delete partition %1.", partition.devicePath()); return false; } bool SfdiskPartitionTable::updateGeometry(Report& report, const Partition& partition, qint64 sectorStart, qint64 sectorEnd) { ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--force"), partition.devicePath(), QStringLiteral("-N"), QString::number(partition.number()) } ); if ( sfdiskCommand.write(QByteArrayLiteral("start=") + QByteArray::number(sectorStart) + QByteArrayLiteral(" size=") + QByteArray::number(sectorEnd - sectorStart + 1) + QByteArrayLiteral("\nY\n")) && sfdiskCommand.start(-1) && sfdiskCommand.waitFor() && sfdiskCommand.exitCode() == 0) { return true; } report.line() << xi18nc("@info:progress", "Could not set geometry for partition %1 while trying to resize/move it.", partition.devicePath()); return false; } bool SfdiskPartitionTable::clobberFileSystem(Report& report, const Partition& partition) { ExternalCommand wipeCommand(report, QStringLiteral("wipefs"), { QStringLiteral("--all"), partition.partitionPath() } ); if (wipeCommand.run(-1) && wipeCommand.exitCode() == 0) return true; report.line() << xi18nc("@info:progress", "Failed to erase filesystem signature on partition %1.", partition.partitionPath()); return false; } bool SfdiskPartitionTable::resizeFileSystem(Report& report, const Partition& partition, qint64 newLength) { // sfdisk does not have any partition resize capabilities Q_UNUSED(report) Q_UNUSED(partition) Q_UNUSED(newLength) return false; } FileSystem::Type SfdiskPartitionTable::detectFileSystemBySector(Report& report, const Device& device, qint64 sector) { FileSystem::Type type = FileSystem::Type::Unknown; ExternalCommand jsonCommand(QStringLiteral("sfdisk"), { QStringLiteral("--json"), device.deviceNode() } ); if (jsonCommand.run(-1) && jsonCommand.exitCode() == 0) { const QJsonArray partitionTable = QJsonDocument::fromJson(jsonCommand.rawOutput()).object()[QLatin1String("partitiontable")].toObject()[QLatin1String("partitions")].toArray(); for (const auto &partition : partitionTable) { const QJsonObject partitionObject = partition.toObject(); const qint64 start = partitionObject[QLatin1String("start")].toVariant().toLongLong(); if (start == sector) { const QString deviceNode = partitionObject[QLatin1String("node")].toString(); type = CoreBackendManager::self()->backend()->detectFileSystem(deviceNode); return type; } } } report.line() << xi18nc("@info:progress", "Could not determine file system of partition at sector %1 on device %2.", sector, device.deviceNode()); return type; } static struct { FileSystem::Type type; QLatin1String partitionType[2]; // GPT, MBR } typemap[] = { { FileSystem::Type::Btrfs, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Ext2, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Ext3, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Ext4, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::LinuxSwap, { QLatin1String("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F"), QLatin1String("82") } }, { FileSystem::Type::Fat12, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("6") } }, { FileSystem::Type::Fat16, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("6") } }, { FileSystem::Type::Fat32, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("7") } }, { FileSystem::Type::Nilfs2, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Ntfs, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("7") } }, { FileSystem::Type::Exfat, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("7") } }, { FileSystem::Type::ReiserFS, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Reiser4, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Xfs, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Jfs, { QLatin1String("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), QLatin1String("83") } }, { FileSystem::Type::Hfs, { QLatin1String("48465300-0000-11AA-AA11-00306543ECAC"), QLatin1String("af")} }, { FileSystem::Type::HfsPlus, { QLatin1String("48465300-0000-11AA-AA11-00306543ECAC"), QLatin1String("af") } }, { FileSystem::Type::Udf, { QLatin1String("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), QLatin1String("7") } } // Add ZFS too }; static QLatin1String getPartitionType(FileSystem::Type t, PartitionTable::TableType tableType) { quint8 type; switch (tableType) { case PartitionTable::gpt: type = 0; break; case PartitionTable::msdos: case PartitionTable::msdos_sectorbased: type = 1; break; default:; return QLatin1String(); } for (quint32 i = 0; i < sizeof(typemap) / sizeof(typemap[0]); i++) if (typemap[i].type == t) return typemap[i].partitionType[type]; return QLatin1String(); } bool SfdiskPartitionTable::setPartitionSystemType(Report& report, const Partition& partition) { QString partitionType = getPartitionType(partition.fileSystem().type(), m_device->partitionTable()->type()); if (partitionType.isEmpty()) return true; ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-type"), m_device->deviceNode(), QString::number(partition.number()), partitionType } ); return sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0; } bool SfdiskPartitionTable::setFlag(Report& report, const Partition& partition, PartitionTable::Flag flag, bool state) { // We only allow setting one active partition per device if (flag == PartitionTable::FlagBoot && state == true) { ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QString::number(partition.number()) } ); if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0) return true; else return false; } else if (flag == PartitionTable::FlagBoot && state == false) { ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QStringLiteral("-") } ); if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0) return true; // FIXME: Do not return false since we have no way of checking if partition table is MBR } if (flag == PartitionTable::FlagEsp && state == true) { ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-type"), m_device->deviceNode(), QString::number(partition.number()), QStringLiteral("C12A7328-F81F-11D2-BA4B-00A0C93EC93B") } ); if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0) return true; else return false; } if (flag == PartitionTable::FlagEsp && state == false) setPartitionSystemType(report, partition); if (flag == PartitionTable::FlagBiosGrub && state == true) { ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-type"), m_device->deviceNode(), QString::number(partition.number()), QStringLiteral("21686148-6449-6E6F-744E-656564454649") } ); if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0) return true; else return false; } if (flag == PartitionTable::FlagBiosGrub && state == false) setPartitionSystemType(report, partition); return true; }