diff --git a/src/core/raid/softwareraid.cpp b/src/core/raid/softwareraid.cpp index a3efff1..f5e5b2c 100644 --- a/src/core/raid/softwareraid.cpp +++ b/src/core/raid/softwareraid.cpp @@ -1,548 +1,538 @@ /************************************************************************* * Copyright (C) 2018 by Caio Carvalho * * * * 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 "softwareraid.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "core/partition.h" #include "core/volumemanagerdevice_p.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/externalcommand.h" #include #include #include #define d_ptr std::static_pointer_cast(d) QString SoftwareRAID::s_raidConfigurationFile = QString(); class SoftwareRAIDPrivate : public VolumeManagerDevicePrivate { public: qint32 m_raidLevel; qint64 m_chunkSize; qint64 m_totalChunk; qint64 m_arraySize; QString m_UUID; QStringList m_devicePathList; SoftwareRAID::Status m_status; }; SoftwareRAID::SoftwareRAID(const QString& name, SoftwareRAID::Status status, const QString& iconName) : VolumeManagerDevice(std::make_shared(), name, (QStringLiteral("/dev/") + name), status == SoftwareRAID::Status::Inactive ? 0 : getChunkSize(QStringLiteral("/dev/") + name), status == SoftwareRAID::Status::Inactive ? 0 : getTotalChunk(QStringLiteral("/dev/") + name), iconName, Device::Type::SoftwareRAID_Device) { d_ptr->m_raidLevel = getRaidLevel(deviceNode()); d_ptr->m_chunkSize = logicalSize(); d_ptr->m_totalChunk = totalLogical(); d_ptr->m_arraySize = getArraySize(deviceNode()); d_ptr->m_UUID = getUUID(deviceNode()); d_ptr->m_devicePathList = getDevicePathList(deviceNode()); d_ptr->m_status = status; initPartitions(); } const QStringList SoftwareRAID::deviceNodes() const { return d_ptr->m_devicePathList; } const QStringList& SoftwareRAID::partitionNodes() const { return {}; } qint64 SoftwareRAID::partitionSize(QString &partitionPath) const { Q_UNUSED(partitionPath) return 0; } bool SoftwareRAID::growArray(Report &report, const QStringList &devices) { Q_UNUSED(report) Q_UNUSED(devices) return false; } bool SoftwareRAID::shrinkArray(Report &report, const QStringList &devices) { Q_UNUSED(report) Q_UNUSED(devices) return false; } QString SoftwareRAID::prettyName() const { QString raidInfo; if (status() == SoftwareRAID::Status::Active) raidInfo = xi18nc("@item:inlistbox [RAID level]", " [RAID %1]", raidLevel()); else if (status() == SoftwareRAID::Status::Recovery) raidInfo = xi18nc("@item:inlistbox [RAID level - Recovering]", " [RAID %1 - Recovering]", raidLevel()); else if (status() == SoftwareRAID::Status::Resync) raidInfo = xi18nc("@item:inlistbox [RAID level - Resyncing]", " [RAID %1 - Resyncing]", raidLevel()); else raidInfo = QStringLiteral(" [RAID]"); return VolumeManagerDevice::prettyName() + raidInfo; } bool SoftwareRAID::operator ==(const Device& other) const { bool equalDeviceNode = Device::operator ==(other); if (other.type() == Device::Type::SoftwareRAID_Device) { const SoftwareRAID& raid = static_cast(other); if (!equalDeviceNode) return raid.uuid() == uuid(); } return equalDeviceNode; } qint32 SoftwareRAID::raidLevel() const { return d_ptr->m_raidLevel; } qint64 SoftwareRAID::chunkSize() const { return d_ptr->m_chunkSize; } qint64 SoftwareRAID::totalChunk() const { return d_ptr->m_totalChunk; } qint64 SoftwareRAID::arraySize() const { return d_ptr->m_arraySize; } QString SoftwareRAID::uuid() const { return d_ptr->m_UUID; } QStringList SoftwareRAID::devicePathList() const { return d_ptr->m_devicePathList; } SoftwareRAID::Status SoftwareRAID::status() const { return d_ptr->m_status; } void SoftwareRAID::setStatus(SoftwareRAID::Status status) { d_ptr->m_status = status; } void SoftwareRAID::scanSoftwareRAID(QList& devices) { QStringList availableInConf; // TODO: Support custom config files. QString config = getRAIDConfiguration(); if (!config.isEmpty()) { QRegularExpression re(QStringLiteral("([\\t\\r\\n\\f\\s]|INACTIVE-)ARRAY \\/dev\\/([\\/\\w-]+)")); QRegularExpressionMatchIterator i = re.globalMatch(config); while (i.hasNext()) { QRegularExpressionMatch reMatch = i.next(); QString deviceName = reMatch.captured(2).trimmed(); availableInConf << deviceName; } } QFile mdstat(QStringLiteral("/proc/mdstat")); if (mdstat.open(QIODevice::ReadOnly)) { QTextStream stream(&mdstat); QString content = stream.readAll(); mdstat.close(); QRegularExpression re(QStringLiteral("md([\\/\\w]+)\\s+:\\s+([\\w]+)")); QRegularExpressionMatchIterator i = re.globalMatch(content); while (i.hasNext()) { QRegularExpressionMatch reMatch = i.next(); QString deviceNode = QStringLiteral("/dev/md") + reMatch.captured(1).trimmed(); QString status = reMatch.captured(2).trimmed(); SoftwareRAID* d = static_cast(CoreBackendManager::self()->backend()->scanDevice(deviceNode)); // Just to prevent segfault in some case if (d == nullptr) continue; const QStringList constAvailableInConf = availableInConf; for (const QString& path : constAvailableInConf) if (getUUID(QStringLiteral("/dev/") + path) == d->uuid()) availableInConf.removeAll(path); devices << d; if (status == QStringLiteral("inactive")) d->setStatus(SoftwareRAID::Status::Inactive); if (d->raidLevel() > 0) { QRegularExpression reMirrorStatus(d->name() + QStringLiteral("\\s+:\\s+(.*\\n\\s+)+\\[[=>.]+\\]\\s+(resync|recovery)")); QRegularExpressionMatch reMirrorStatusMatch = reMirrorStatus.match(content); if (reMirrorStatusMatch.hasMatch()) { if (reMirrorStatusMatch.captured(2) == QStringLiteral("resync")) d->setStatus(SoftwareRAID::Status::Resync); else if (reMirrorStatusMatch.captured(2) == QStringLiteral("recovery")) d->setStatus(SoftwareRAID::Status::Recovery); } } } } for (const QString& name : qAsConst(availableInConf)) { SoftwareRAID *raidDevice = new SoftwareRAID(name, SoftwareRAID::Status::Inactive); devices << raidDevice; } } qint32 SoftwareRAID::getRaidLevel(const QString &path) { QString output = getDetail(path); if (!output.isEmpty()) { QRegularExpression re(QStringLiteral("Raid Level :\\s+\\w+(\\d+)")); QRegularExpressionMatch reMatch = re.match(output); if (reMatch.hasMatch()) - return reMatch.captured(1).toLongLong(); + return reMatch.captured(1).toInt(); } return -1; } qint64 SoftwareRAID::getChunkSize(const QString &path) { if (getRaidLevel(path) == 1) { QStringList devices = getDevicePathList(path); if (!devices.isEmpty()) { QString device = devices[0]; // Look sector size for the first device/partition on the list, as RAID 1 is composed by mirrored devices ExternalCommand sectorSize(QStringLiteral("blockdev"), { QStringLiteral("--getss"), device }); - if (sectorSize.run(-1) && sectorSize.exitCode() == 0) { - int sectors = sectorSize.output().trimmed().toLongLong(); - return sectors; - } + if (sectorSize.run(-1) && sectorSize.exitCode() == 0) + return sectorSize.output().trimmed().toLongLong(); } } else { QString output = getDetail(path); if (!output.isEmpty()) { QRegularExpression re(QStringLiteral("Chunk Size :\\s+(\\d+)")); QRegularExpressionMatch reMatch = re.match(output); if (reMatch.hasMatch()) return reMatch.captured(1).toLongLong(); } } return -1; - } qint64 SoftwareRAID::getTotalChunk(const QString &path) { return getArraySize(path) / getChunkSize(path); } qint64 SoftwareRAID::getArraySize(const QString &path) { QString output = getDetail(path); if (!output.isEmpty()) { QRegularExpression re(QStringLiteral("Array Size :\\s+(\\d+)")); QRegularExpressionMatch reMatch = re.match(output); if (reMatch.hasMatch()) return reMatch.captured(1).toLongLong() * 1024; } return -1; } QString SoftwareRAID::getUUID(const QString &path) { QString output = getDetail(path); if (!output.isEmpty()) { QRegularExpression re(QStringLiteral("UUID :\\s+([\\w:]+)")); QRegularExpressionMatch reMatch = re.match(output); if (reMatch.hasMatch()) return reMatch.captured(1); } // If UUID was not found in detail output, it should be searched in config file // TODO: Support custom config files. QString config = getRAIDConfiguration(); if (!config.isEmpty()) { QRegularExpression re(QStringLiteral("([\\t\\r\\n\\f\\s]|INACTIVE-)ARRAY \\/dev\\/md([\\/\\w-]+)(.*)")); QRegularExpressionMatchIterator i = re.globalMatch(config); while (i.hasNext()) { QRegularExpressionMatch reMatch = i.next(); QString deviceNode = QStringLiteral("/dev/md") + reMatch.captured(2).trimmed(); QString otherInfo = reMatch.captured(3).trimmed(); // Consider device node as name=host:deviceNode when the captured device node string has '-' character // It happens when user have included the device to config file using 'mdadm --examine --scan' if (deviceNode.contains(QLatin1Char('-'))) { QRegularExpression reName(QStringLiteral("name=[\\w:]+\\/dev\\/md\\/([\\/\\w]+)")); QRegularExpressionMatch nameMatch = reName.match(otherInfo); if (nameMatch.hasMatch()) deviceNode = nameMatch.captured(1); } if (deviceNode == path) { QRegularExpression reUUID(QStringLiteral("(UUID=|uuid=)([\\w:]+)")); QRegularExpressionMatch uuidMatch = reUUID.match(otherInfo); if (uuidMatch.hasMatch()) return uuidMatch.captured(2); } } } return QString(); } QStringList SoftwareRAID::getDevicePathList(const QString &path) { QStringList result; QString detail = getDetail(path); if (!detail.isEmpty()) { QRegularExpression re(QStringLiteral("\\s+\\/dev\\/(\\w+)")); QRegularExpressionMatchIterator i = re.globalMatch(detail); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString device = QStringLiteral("/dev/") + match.captured(1); if (device != path) result << device; } } return result; } bool SoftwareRAID::isRaidPath(const QString &devicePath) { return !getDetail(devicePath).isEmpty(); } bool SoftwareRAID::createSoftwareRAID(Report &report, const QString &name, const QStringList devicePathList, const qint32 raidLevel, const qint32 chunkSize) { + QString path = QStringLiteral("/dev/") + name; + QStringList args; - args << QStringLiteral("--create") << name; + args << QStringLiteral("--create") << path; args << QStringLiteral("--level=") + QString::number(raidLevel); args << QStringLiteral("--chunk=") + QString::number(chunkSize); args << QStringLiteral("--raid-devices=") + QString::number(devicePathList.size()); - for (const QString path : qAsConst(devicePathList)) { - eraseDeviceMDSuperblock(path); + for (const QString &p : qAsConst(devicePathList)) { + eraseDeviceMDSuperblock(p); - args << path; + args << p; } ExternalCommand cmd(report, QStringLiteral("mdadm"), args); if (!cmd.run(-1) || cmd.exitCode() != 0) return false; - // TODO: Support custom config files. - return updateConfigurationFile(name); + updateConfigurationFile(path); + + return true; } bool SoftwareRAID::deleteSoftwareRAID(Report &report, SoftwareRAID &raidDevice) { Q_UNUSED(report) Q_UNUSED(raidDevice) return false; } bool SoftwareRAID::assembleSoftwareRAID(const QString& deviceNode) { if (!isRaidPath(deviceNode)) return false; ExternalCommand cmd(QStringLiteral("mdadm"), { QStringLiteral("--assemble"), QStringLiteral("--scan"), deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool SoftwareRAID::stopSoftwareRAID(Report& report, const QString& deviceNode) { if (!isRaidPath(deviceNode)) return false; ExternalCommand cmd(report, QStringLiteral("mdadm"), { QStringLiteral("--manage"), QStringLiteral("--stop"), deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool SoftwareRAID::reassembleSoftwareRAID(Report& report, const QString &deviceNode) { // TODO: Include report return stopSoftwareRAID(report, deviceNode) && assembleSoftwareRAID(deviceNode); } QString SoftwareRAID::getRaidArrayName(const QString &partitionPath) { ExternalCommand cmd(QStringLiteral("mdadm"), { QStringLiteral("--misc"), QStringLiteral("--query"), partitionPath }); if (cmd.run(-1) && cmd.exitCode() == 0) { QRegularExpression ex(QStringLiteral("device active raid\\d+\\s([\\/\\w]+).")); QRegularExpressionMatch match = ex.match(cmd.output()); if (match.hasMatch()) return match.captured(1); } return QString(); } void SoftwareRAID::initPartitions() { } qint64 SoftwareRAID::mappedSector(const QString &partitionPath, qint64 sector) const { + Q_UNUSED(partitionPath); + Q_UNUSED(sector); return -1; } bool SoftwareRAID::eraseDeviceMDSuperblock(const QString &path) { ExternalCommand cmd(QStringLiteral("mdadm"), { QStringLiteral("--misc"), QStringLiteral("--zero-superblock"), path}); return cmd.run(-1) && cmd.exitCode() == 0; } -bool SoftwareRAID::updateConfigurationFile(const QString &deviceName) +bool SoftwareRAID::updateConfigurationFile(const QString &path) { - // TODO: Don't use QFile, it is not authenticated and will fail without sudo - QFile config(raidConfigurationFilePath()); - - if (!config.open(QIODevice::WriteOnly | QIODevice::Append)) - return false; - - QTextStream out(&config); - - QString info = getDeviceInformation(deviceName); - - if (!info.isEmpty()) - out << info << QLatin1Char('\n'); + ExternalCommand cmd(QStringLiteral("/usr/") + QStringLiteral(LIBEXECDIRPATH) + QStringLiteral("/kpmcore_mdadmupdateconf"), + { path, raidConfigurationFilePath() }); - config.close(); - - return true; + return cmd.run(-1) && cmd.exitCode() == 0; } QString SoftwareRAID::getDetail(const QString &path) { ExternalCommand cmd(QStringLiteral("mdadm"), { QStringLiteral("--misc"), QStringLiteral("--detail"), path }); return (cmd.run(-1) && cmd.exitCode() == 0) ? cmd.output() : QString(); } QString SoftwareRAID::getRAIDConfiguration() { QFile config(raidConfigurationFilePath()); if (!config.open(QIODevice::ReadOnly)) return QString(); QTextStream stream(&config); QString result = stream.readAll(); config.close(); return result; } QString SoftwareRAID::getDeviceInformation(const QString &deviceName) { ExternalCommand cmd(QStringLiteral("mdadm"), { QStringLiteral("--misc"), QStringLiteral("--detail"), QStringLiteral("--scan"), deviceName }); // TODO: Get only information about the device line. // Because if there is any error on config file, it will print more information than needed. return (cmd.run(-1) && cmd.exitCode() == 0) ? cmd.output() : QString(); } void SoftwareRAID::setRaidConfigurationFilePath(const QString &filePath) { s_raidConfigurationFile = filePath; } QString SoftwareRAID::raidConfigurationFilePath() { if (s_raidConfigurationFile.isEmpty()) s_raidConfigurationFile = getDefaultRaidConfigFile(); return s_raidConfigurationFile; } QString SoftwareRAID::getDefaultRaidConfigFile() { if (QFile::exists(QStringLiteral("/etc/mdadm.conf"))) return QStringLiteral("/etc/mdadm.conf"); else if (QFile::exists(QStringLiteral("/etc/mdadm/mdadm.conf"))) return QStringLiteral("/etc/mdadm/mdadm.conf"); return QString(); } diff --git a/src/core/raid/softwareraid.h b/src/core/raid/softwareraid.h index b1b342f..8fec188 100644 --- a/src/core/raid/softwareraid.h +++ b/src/core/raid/softwareraid.h @@ -1,118 +1,118 @@ /************************************************************************* * Copyright (C) 2018 by Caio Carvalho * * * * 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 .* *************************************************************************/ #if !defined(KPMCORE_SOFTWARERAID_H) #define KPMCORE_SOFTWARERAID_H #include "core/volumemanagerdevice.h" #include "util/libpartitionmanagerexport.h" #include "util/report.h" class LIBKPMCORE_EXPORT SoftwareRAID : public VolumeManagerDevice { Q_DISABLE_COPY(SoftwareRAID) public: enum class Status { Active, Inactive, Resync, Recovery, }; SoftwareRAID(const QString& name, SoftwareRAID::Status status = SoftwareRAID::Status::Active, const QString& iconName = QString()); const QStringList deviceNodes() const override; const QStringList& partitionNodes() const override; qint64 partitionSize(QString &partitionPath) const override; virtual bool growArray(Report& report, const QStringList& devices); virtual bool shrinkArray(Report& report, const QStringList& devices); virtual QString prettyName() const override; virtual bool operator==(const Device& other) const override; qint32 raidLevel() const; qint64 chunkSize() const; qint64 totalChunk() const; qint64 arraySize() const; QString uuid() const; QStringList devicePathList() const; SoftwareRAID::Status status() const; void setStatus(SoftwareRAID::Status status); public: static void scanSoftwareRAID(QList& devices); static qint32 getRaidLevel(const QString& path); static qint64 getChunkSize(const QString& path); static qint64 getTotalChunk(const QString& path); static qint64 getArraySize(const QString& path); static QString getUUID(const QString& path); static QStringList getDevicePathList(const QString& path); static bool isRaidPath(const QString& devicePath); static bool createSoftwareRAID(Report& report, const QString& name, const QStringList devicePathList, const qint32 raidLevel, const qint32 chunkSize); static bool deleteSoftwareRAID(Report& report, SoftwareRAID& raidDevice); static bool assembleSoftwareRAID(const QString& deviceNode); static bool stopSoftwareRAID(Report& report, const QString& deviceNode); static bool reassembleSoftwareRAID(Report& report, const QString& deviceNode); static QString getRaidArrayName(const QString& partitionPath); static void setRaidConfigurationFilePath(const QString& filePath); static QString raidConfigurationFilePath(); static QString getDefaultRaidConfigFile(); protected: void initPartitions() override; qint64 mappedSector(const QString &partitionPath, qint64 sector) const override; private: static bool eraseDeviceMDSuperblock(const QString& path); - static bool updateConfigurationFile(const QString& deviceName); + static bool updateConfigurationFile(const QString& path); static QString getDetail(const QString& path); static QString getRAIDConfiguration(); static QString getDeviceInformation(const QString& deviceName); private: static QString s_raidConfigurationFile; }; #endif // SOFTWARERAID_H diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 1106ba3..34dcbb9 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,57 +1,66 @@ set(application_interface_xml org.kde.kpmcore.applicationinterface.xml) set(helper_interface_xml org.kde.kpmcore.helperinterface.xml) qt5_generate_dbus_interface( util/externalcommand.h ${application_interface_xml} OPTIONS -a ) qt5_generate_dbus_interface( util/externalcommandhelper.h ${helper_interface_xml} OPTIONS -a ) qt5_add_dbus_interface(ApplicationInterface_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${application_interface_xml} externalcommand_interface) qt5_add_dbus_interface(HelperInterface_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${helper_interface_xml} externalcommandhelper_interface) set(UTIL_SRC ${HelperInterface_SRCS} util/capacity.cpp util/externalcommand.cpp util/globallog.cpp util/helpers.cpp util/htmlreport.cpp util/report.cpp ) set(UTIL_LIB_HDRS util/libpartitionmanagerexport.h util/capacity.h util/externalcommand.h util/globallog.h util/helpers.h util/htmlreport.h util/report.h ) add_executable(kpmcore_externalcommand ${ApplicationInterface_SRCS} util/externalcommandhelper.cpp ) +add_executable(kpmcore_mdadmupdateconf + util/mdadmupdateconf.cpp +) + +add_definitions( + -DLIBEXECDIRPATH="${LIBEXEC_INSTALL_DIR}" +) + target_link_libraries(kpmcore_externalcommand qca-qt5 Qt5::Core Qt5::DBus KF5::Auth KF5::I18n ) +install(TARGETS kpmcore_mdadmupdateconf DESTINATION ${LIBEXEC_INSTALL_DIR}) install(TARGETS kpmcore_externalcommand DESTINATION ${KAUTH_HELPER_INSTALL_DIR}) install( FILES util/org.kde.kpmcore.helperinterface.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d ) install( FILES util/org.kde.kpmcore.applicationinterface.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d ) kauth_install_helper_files(kpmcore_externalcommand org.kde.kpmcore.externalcommand root) kauth_install_actions(org.kde.kpmcore.externalcommand util/org.kde.kpmcore.externalcommand.actions) diff --git a/src/util/externalcommand_whitelist.h b/src/util/externalcommand_whitelist.h index 79160aa..04aea3f 100644 --- a/src/util/externalcommand_whitelist.h +++ b/src/util/externalcommand_whitelist.h @@ -1,107 +1,108 @@ /************************************************************************* * Copyright (C) 2018 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 .* *************************************************************************/ #ifndef KPMCORE_EXTERNALCOMMAND_WHITELIST_H #define KPMCORE_EXTERNALCOMMAND_WHITELIST_H -QString allowedCommands[] = { +const QString allowedCommands[] = { // TODO try to remove these later QStringLiteral("mv"), QStringLiteral("dd"), // TODO no root needed QStringLiteral("lsblk"), QStringLiteral("udevadm"), //Core programs QStringLiteral("blockdev"), QStringLiteral("sfdisk"), QStringLiteral("wipefs"), QStringLiteral("lvm"), QStringLiteral("mdadm"), QStringLiteral("mount"), QStringLiteral("umount"), QStringLiteral("smartctl"), // FileSystem utilties QStringLiteral("btrfs"), QStringLiteral("mkfs.btrfs"), QStringLiteral("btrfstune"), QStringLiteral("exfatfsck"), QStringLiteral("mkfs.exfat"), QStringLiteral("exfatlabel"), QStringLiteral("dumpe2fs"), QStringLiteral("e2fsck"), QStringLiteral("mkfs.ext2"), QStringLiteral("resize2fs"), QStringLiteral("e2label"), QStringLiteral("tune2fs"), QStringLiteral("mkfs.ext3"), QStringLiteral("mkfs.ext4"), QStringLiteral("mkfs.f2fs"), QStringLiteral("fsck.f2fs"), QStringLiteral("resize.f2fs"), QStringLiteral("fsck.fat"), QStringLiteral("fatlabel"), QStringLiteral("mkfs.fat"), QStringLiteral("fatresize"), QStringLiteral("hfsck"), QStringLiteral("hformat"), QStringLiteral("fsck.hfsplus"), QStringLiteral("mkfs.hfsplus"), QStringLiteral("jfs_debugfs"), QStringLiteral("jfs_tune"), QStringLiteral("fsck.jfs"), QStringLiteral("mkfs.jfs"), QStringLiteral("mkswap"), QStringLiteral("swaplabel"), QStringLiteral("swapon"), QStringLiteral("swapoff"), QStringLiteral("cryptsetup"), QStringLiteral("dmsetup"), QStringLiteral("fsck.nilfs2"), QStringLiteral("mkfs.nilfs2"), QStringLiteral("nilfs-tune"), QStringLiteral("nilfs-resize"), QStringLiteral("ntfsresize"), QStringLiteral("mkfs.ntfs"), QStringLiteral("ntfsclone"), QStringLiteral("ntfslabel"), QStringLiteral("fsck.ocfs2"), QStringLiteral("mkfs.ocfs2"), QStringLiteral("debugfs.ocfs2"), QStringLiteral("tunefs.ocfs2"), QStringLiteral("debugfs.reiser4"), QStringLiteral("fsck.reiser4"), QStringLiteral("mkfs.reiser4"), QStringLiteral("debugreiserfs"), QStringLiteral("reiserfstune"), QStringLiteral("fsck.reiserfs"), QStringLiteral("mkfs.reiserfs"), QStringLiteral("resize_reiserfs"), QStringLiteral("mkudffs"), QStringLiteral("udfinfo"), QStringLiteral("udflabel"), QStringLiteral("xfs_db"), QStringLiteral("xfs_repair"), QStringLiteral("mkfs.xfs"), QStringLiteral("xfs_copy"), QStringLiteral("xfs_growfs"), -QStringLiteral("zpool") +QStringLiteral("zpool"), +QStringLiteral("kpmcore_mdadmupdateconf") }; #endif diff --git a/src/util/mdadmupdateconf.cpp b/src/util/mdadmupdateconf.cpp new file mode 100644 index 0000000..10f345a --- /dev/null +++ b/src/util/mdadmupdateconf.cpp @@ -0,0 +1,20 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + if (argc != 3) + return 1; + + char command[] = "mdadm --detail --scan "; + + strcat(command, argv[1]); + + strcat(command, " >> "); + + strcat(command, argv[2]); + + system(command); + + return 0; +}