Merge branch 'fstab'
This commit is contained in:
commit
fbe54e21f3
|
@ -21,6 +21,8 @@
|
|||
#include "util/externalcommand.h"
|
||||
#include "util/report.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <blkid/blkid.h>
|
||||
#endif
|
||||
|
@ -34,6 +36,8 @@
|
|||
|
||||
static void parseFsSpec(const QString& m_fsSpec, FstabEntry::Type& m_entryType, QString& m_deviceNode);
|
||||
static QString findBlkIdDevice(const char *token, const QString& value);
|
||||
static void writeEntry(QTextStream& s, const FstabEntry& entry, std::array<unsigned int, 4> columnWidth);
|
||||
std::array<unsigned int, 4> fstabColumnWidth(const FstabEntryList& fstabEntries);
|
||||
|
||||
struct FstabEntryPrivate
|
||||
{
|
||||
|
@ -59,6 +63,7 @@ FstabEntry::FstabEntry(const QString& fsSpec, const QString& mountPoint, const Q
|
|||
d->m_comment = comment;
|
||||
|
||||
d->m_options = options.split(QLatin1Char(','));
|
||||
d->m_options.removeAll(QStringLiteral("defaults"));
|
||||
parseFsSpec(d->m_fsSpec, d->m_entryType, d->m_deviceNode);
|
||||
}
|
||||
|
||||
|
@ -88,15 +93,20 @@ FstabEntryList readFstabEntries( const QString& fstabPath )
|
|||
// (4) dump frequency (optional, defaults to 0), no comment is allowed if omitted,
|
||||
// (5) pass number (optional, defaults to 0), no comment is allowed if omitted,
|
||||
// (#) comment (optional).
|
||||
auto fsSpec = splitLine.at(0);
|
||||
auto mountPoint = splitLine.at(1);
|
||||
auto fsType = splitLine.at(2);
|
||||
auto options = splitLine.at(3);
|
||||
|
||||
switch (splitLine.length()) {
|
||||
case 4:
|
||||
fstabEntries.push_back( {splitLine.at(0), splitLine.at(1), splitLine.at(2), splitLine.at(3) } );
|
||||
fstabEntries.push_back( {fsSpec, mountPoint, fsType, options } );
|
||||
break;
|
||||
case 5:
|
||||
fstabEntries.push_back( {splitLine.at(0), splitLine.at(1), splitLine.at(2), splitLine.at(3), splitLine.at(4).toInt() } );
|
||||
fstabEntries.push_back( {fsSpec, mountPoint, fsType, options, splitLine.at(4).toInt() } );
|
||||
break;
|
||||
case 6:
|
||||
fstabEntries.push_back( {splitLine.at(0), splitLine.at(1), splitLine.at(2), splitLine.at(3), splitLine.at(4).toInt(), splitLine.at(5).toInt(), comment.isEmpty() ? QString() : QLatin1Char('#') + comment } );
|
||||
fstabEntries.push_back( {fsSpec, mountPoint, fsType, options, splitLine.at(4).toInt(), splitLine.at(5).toInt(), comment.isEmpty() ? QString() : QLatin1Char('#') + comment } );
|
||||
break;
|
||||
default:
|
||||
fstabEntries.push_back( { {}, {}, {}, {}, {}, {}, QLatin1Char('#') + line } );
|
||||
|
@ -142,6 +152,11 @@ const QStringList& FstabEntry::options() const
|
|||
return d->m_options;
|
||||
}
|
||||
|
||||
const QString FstabEntry::optionsString() const
|
||||
{
|
||||
return options().size() > 0 ? options().join(QLatin1Char(',')) : QStringLiteral("defaults");
|
||||
}
|
||||
|
||||
int FstabEntry::dumpFreq() const
|
||||
{
|
||||
return d->m_dumpFreq;
|
||||
|
@ -232,40 +247,50 @@ static void parseFsSpec(const QString& m_fsSpec, FstabEntry::Type& m_entryType,
|
|||
}
|
||||
}
|
||||
|
||||
static void writeEntry(QTextStream& s, const FstabEntry& entry)
|
||||
|
||||
// Used to nicely format fstab file
|
||||
std::array<unsigned int, 4> fstabColumnWidth(const FstabEntryList& fstabEntries)
|
||||
{
|
||||
std::array<unsigned int, 4> columnWidth;
|
||||
|
||||
#define FIELD_WIDTH(x) 3 + std::max_element(fstabEntries.begin(), fstabEntries.end(), [](const FstabEntry& a, const FstabEntry& b) {return a.x().length() < b.x().length(); })->x().length();
|
||||
|
||||
columnWidth[0] = FIELD_WIDTH(fsSpec);
|
||||
columnWidth[1] = FIELD_WIDTH(mountPoint);
|
||||
columnWidth[2] = FIELD_WIDTH(type);
|
||||
columnWidth[3] = FIELD_WIDTH(optionsString);
|
||||
|
||||
return columnWidth;
|
||||
}
|
||||
|
||||
static void writeEntry(QTextStream& s, const FstabEntry& entry, std::array<unsigned int, 4> columnWidth)
|
||||
{
|
||||
if (entry.entryType() == FstabEntry::Type::comment) {
|
||||
s << entry.comment() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
QString options;
|
||||
if (entry.options().size() > 0) {
|
||||
options = entry.options().join(QLatin1Char(','));
|
||||
if (options.isEmpty())
|
||||
options = QStringLiteral("defaults");
|
||||
}
|
||||
else
|
||||
options = QStringLiteral("defaults");
|
||||
|
||||
s << entry.fsSpec() << "\t"
|
||||
<< (entry.mountPoint().isEmpty() ? QStringLiteral("none") : entry.mountPoint()) << "\t"
|
||||
<< entry.type() << "\t"
|
||||
<< options << "\t"
|
||||
<< entry.dumpFreq() << "\t"
|
||||
<< entry.passNumber() << "\t"
|
||||
s.setFieldAlignment(QTextStream::AlignLeft);
|
||||
s.setFieldWidth(columnWidth[0]);
|
||||
s << entry.fsSpec()
|
||||
<< qSetFieldWidth(columnWidth[1]) << (entry.mountPoint().isEmpty() ? QStringLiteral("none") : entry.mountPoint())
|
||||
<< qSetFieldWidth(columnWidth[2]) << entry.type()
|
||||
<< qSetFieldWidth(columnWidth[3]) << entry.optionsString() << qSetFieldWidth(0)
|
||||
<< entry.dumpFreq() << " "
|
||||
<< entry.passNumber() << " "
|
||||
<< entry.comment() << "\n";
|
||||
}
|
||||
|
||||
bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename)
|
||||
{
|
||||
Report report(nullptr);
|
||||
QByteArray fstabContents;
|
||||
QString fstabContents;
|
||||
QTextStream out(&fstabContents);
|
||||
|
||||
std::array<unsigned int, 4> columnWidth = fstabColumnWidth(fstabEntries);
|
||||
|
||||
for (const auto &e : fstabEntries)
|
||||
writeEntry(out, e);
|
||||
writeEntry(out, e, columnWidth);
|
||||
|
||||
ExternalCommand cmd;
|
||||
return cmd.writeData(report, fstabContents, filename, 0);
|
||||
return cmd.createFile(fstabContents.toLocal8Bit(), filename);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,11 @@ public:
|
|||
*/
|
||||
const QStringList& options() const;
|
||||
|
||||
/**
|
||||
* @return the mount options associated with the file system
|
||||
*/
|
||||
const QString optionsString() const;
|
||||
|
||||
/**
|
||||
* @return the fs_freq field of fstab entry
|
||||
*/
|
||||
|
|
|
@ -124,11 +124,6 @@ bool ExternalCommand::start(int timeout)
|
|||
if (command().isEmpty())
|
||||
return false;
|
||||
|
||||
if (!QDBusConnection::systemBus().isConnected()) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (report())
|
||||
report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" "))));
|
||||
|
||||
|
@ -139,10 +134,9 @@ bool ExternalCommand::start(int timeout)
|
|||
if (cmd.isEmpty())
|
||||
cmd = QStandardPaths::findExecutable(command(), { QStringLiteral("/sbin/"), QStringLiteral("/usr/sbin/"), QStringLiteral("/usr/local/sbin/") });
|
||||
|
||||
auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"),
|
||||
QStringLiteral("/Helper"), QDBusConnection::systemBus(), this);
|
||||
|
||||
interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
bool rval = false;
|
||||
|
||||
|
@ -176,18 +170,13 @@ bool ExternalCommand::copyBlocks(const CopySource& source, CopyTarget& target)
|
|||
bool rval = true;
|
||||
const qint64 blockSize = 10 * 1024 * 1024; // number of bytes per block to copy
|
||||
|
||||
if (!QDBusConnection::systemBus().isConnected()) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO KF6:Use new signal-slot syntax
|
||||
connect(m_job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(emitProgress(KJob*, unsigned long)));
|
||||
connect(m_job, &KAuth::ExecuteJob::newData, this, &ExternalCommand::emitReport);
|
||||
|
||||
auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"),
|
||||
QStringLiteral("/Helper"), QDBusConnection::systemBus(), this);
|
||||
interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
QDBusPendingCall pcall = interface->copyblocks(source.path(), source.firstByte(), source.length(),
|
||||
target.path(), target.firstByte(), blockSize);
|
||||
|
@ -222,19 +211,40 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer,
|
|||
if (report())
|
||||
report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" "))));
|
||||
|
||||
bool rval = true;
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
QDBusPendingCall pcall = interface->writeData(buffer, deviceNode, firstByte);
|
||||
return waitForDbusReply(pcall);
|
||||
}
|
||||
|
||||
bool ExternalCommand::createFile(const QByteArray& buffer, const QString& deviceNode)
|
||||
{
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
QDBusPendingCall pcall = interface->createFile(buffer, deviceNode);
|
||||
return waitForDbusReply(pcall);
|
||||
}
|
||||
|
||||
OrgKdeKpmcoreExternalcommandInterface* ExternalCommand::helperInterface()
|
||||
{
|
||||
if (!QDBusConnection::systemBus().isConnected()) {
|
||||
qWarning() << QDBusConnection::systemBus().lastError().message();
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"),
|
||||
QStringLiteral("/Helper"), QDBusConnection::systemBus(), this);
|
||||
interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days
|
||||
|
||||
QDBusPendingCall pcall = interface->writeData(buffer, deviceNode, firstByte);
|
||||
return interface;
|
||||
}
|
||||
|
||||
bool ExternalCommand::waitForDbusReply(QDBusPendingCall &pcall)
|
||||
{
|
||||
bool rval = true;
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
|
||||
QEventLoop loop;
|
||||
|
||||
|
@ -255,7 +265,6 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer,
|
|||
return rval;
|
||||
}
|
||||
|
||||
|
||||
bool ExternalCommand::write(const QByteArray& input)
|
||||
{
|
||||
if ( qEnvironmentVariableIsSet( "KPMCORE_DEBUG" ))
|
||||
|
|
|
@ -38,6 +38,8 @@ class Report;
|
|||
class CopySource;
|
||||
class CopyTarget;
|
||||
class QDBusInterface;
|
||||
class QDBusPendingCall;
|
||||
class OrgKdeKpmcoreExternalcommandInterface;
|
||||
|
||||
struct ExternalCommandPrivate;
|
||||
|
||||
|
@ -71,6 +73,7 @@ public:
|
|||
public:
|
||||
bool copyBlocks(const CopySource& source, CopyTarget& target);
|
||||
bool writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray
|
||||
bool createFile(const QByteArray& buffer, const QString& deviceNode); // similar to writeData but creates a new file
|
||||
|
||||
/**< @param cmd the command to run */
|
||||
void setCommand(const QString& cmd);
|
||||
|
@ -128,6 +131,8 @@ public Q_SLOTS:
|
|||
private:
|
||||
void setExitCode(int i);
|
||||
void onReadOutput();
|
||||
bool waitForDbusReply(QDBusPendingCall &pcall);
|
||||
OrgKdeKpmcoreExternalcommandInterface* helperInterface();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ExternalCommandPrivate> d;
|
||||
|
|
|
@ -118,7 +118,7 @@ bool ExternalCommandHelper::readData(const QString& sourceDevice, QByteArray& bu
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Writes the data from buffer to a given device or file.
|
||||
/** Writes the data from buffer to a given device.
|
||||
@param targetDevice device or file to write to
|
||||
@param buffer the data that we write
|
||||
@param offset offset where to begin writing
|
||||
|
@ -128,7 +128,8 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
|
|||
{
|
||||
QFile device(targetDevice);
|
||||
|
||||
if (!device.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)) {
|
||||
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered | QIODevice::Append;
|
||||
if (!device.open(flags)) {
|
||||
qCritical() << xi18n("Could not open device <filename>%1</filename> for writing.", targetDevice);
|
||||
return false;
|
||||
}
|
||||
|
@ -146,6 +147,29 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Creates a new file with given contents.
|
||||
@param filePath file to write to
|
||||
@param fileContents the data that we write
|
||||
@return true on success
|
||||
*/
|
||||
bool ExternalCommandHelper::createFile(const QString &filePath, const QByteArray& fileContents)
|
||||
{
|
||||
QFile device(filePath);
|
||||
|
||||
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered;
|
||||
if (!device.open(flags)) {
|
||||
qCritical() << xi18n("Could not open file <filename>%1</filename> for writing.", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (device.write(fileContents) != fileContents.size()) {
|
||||
qCritical() << xi18n("Could not write to file <filename>%1</filename>.", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If targetDevice is empty then return QByteArray with data that was read from disk.
|
||||
QVariantMap ExternalCommandHelper::copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
|
||||
{
|
||||
|
@ -239,12 +263,20 @@ QVariantMap ExternalCommandHelper::copyblocks(const QString& sourceDevice, const
|
|||
bool ExternalCommandHelper::writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte)
|
||||
{
|
||||
// Do not allow using this helper for writing to arbitrary location
|
||||
if ( targetDevice.left(5) != QStringLiteral("/dev/") && !targetDevice.contains(QStringLiteral("/etc/fstab")))
|
||||
if ( targetDevice.left(5) != QStringLiteral("/dev/") )
|
||||
return false;
|
||||
|
||||
return writeData(targetDevice, buffer, targetFirstByte);
|
||||
}
|
||||
|
||||
bool ExternalCommandHelper::createFile(const QByteArray& fileContents, const QString& filePath)
|
||||
{
|
||||
// Do not allow using this helper for writing to arbitrary location
|
||||
if ( !filePath.contains(QStringLiteral("/etc/fstab")) )
|
||||
return false;
|
||||
|
||||
return createFile(filePath, fileContents);
|
||||
}
|
||||
|
||||
QVariantMap ExternalCommandHelper::start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
|
||||
{
|
||||
|
|
|
@ -41,12 +41,14 @@ Q_SIGNALS:
|
|||
public:
|
||||
bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size);
|
||||
bool writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset);
|
||||
bool createFile(const QString& filePath, const QByteArray& fileContents);
|
||||
|
||||
public Q_SLOTS:
|
||||
ActionReply init(const QVariantMap& args);
|
||||
Q_SCRIPTABLE QVariantMap start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
|
||||
Q_SCRIPTABLE QVariantMap copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
|
||||
Q_SCRIPTABLE bool writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte);
|
||||
Q_SCRIPTABLE bool createFile(const QByteArray& fileContents, const QString& filePath);
|
||||
Q_SCRIPTABLE void exit();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue