diff --git a/CMakeLists.txt b/CMakeLists.txt index b1bd72d..e78da86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,116 +1,117 @@ # Copyright (C) 2008 by Volker Lanz # Copyright (C) 2014-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 . project(kpmcore) cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(CMAKE_USE_RELATIVE_PATHS OFF) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) set(QT_MIN_VERSION "5.7.0") set(VERSION_MAJOR "3") set(VERSION_MINOR "3") set(VERSION_RELEASE "0") set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}) set(SOVERSION "8") add_definitions(-D'VERSION="${VERSION}"') #" set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(ECM 1.0.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(FeatureSummary) include(GenerateExportHeader) include(ECMSetupVersion) include(ECMPackageConfigHelpers) ecm_setup_version(${VERSION} VARIABLE_PREFIX KPMCORE VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kpmcore_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfigVersion.cmake" SOVERSION ${SOVERSION}) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core DBus Gui Widgets ) # Load the frameworks we need find_package(KF5 REQUIRED Auth I18n CoreAddons WidgetsAddons ) # use sane compile flags add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_TO_ASCII -DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_CAST_TO_BYTEARRAY -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_USE_FAST_OPERATOR_PLUS ) kde_enable_exceptions() - -find_package(PkgConfig REQUIRED) -pkg_check_modules(BLKID REQUIRED blkid>=2.30) +if(LINUX) + find_package(PkgConfig REQUIRED) + pkg_check_modules(BLKID REQUIRED blkid>=2.30) +endif() include_directories(${Qt5Core_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${BLKID_INCLUDE_DIRS} lib/ src/) add_subdirectory(src) # create a Config.cmake and a ConfigVersion.cmake file and install them set(INCLUDE_INSTALL_DIR "include/kpmcore/") set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KPMcore") ecm_configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KPMcoreConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KPMcoreTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KPMcoreTargets.cmake ) ki18n_install(po) set_target_properties( kpmcore PROPERTIES VERSION ${VERSION} SOVERSION ${SOVERSION} ) message(STATUS "kpmcore ${VERSION} will be built for install into ${CMAKE_INSTALL_PREFIX}") feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) enable_testing() add_subdirectory(test) diff --git a/src/core/fstab.cpp b/src/core/fstab.cpp index dd1e4a4..6a8e827 100644 --- a/src/core/fstab.cpp +++ b/src/core/fstab.cpp @@ -1,206 +1,210 @@ /************************************************************************* * Copyright (C) 2009, 2010 by Volker Lanz * * Copyright (C) 2016 by Teo Mrnjavac * * 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 "core/fstab.h" #include "util/externalcommand.h" -#include +#if defined(Q_OS_LINUX) + #include +#endif #include #include #include #include #include #include static void parseFsSpec(const QString& m_fsSpec, FstabEntryType& m_entryType, QString& m_deviceNode); static QString findBlkIdDevice(const QString& token, const QString& value); FstabEntry::FstabEntry(const QString& fsSpec, const QString& mountPoint, const QString& type, const QString& options, int dumpFreq, int passNumber, const QString& comment) : m_fsSpec(fsSpec) , m_mountPoint(mountPoint) , m_type(type) , m_dumpFreq(dumpFreq) , m_passNumber(passNumber) , m_comment(comment) { m_options = options.split(QLatin1Char(',')); parseFsSpec(m_fsSpec, m_entryType, m_deviceNode); } /** @param s the new value for the fs_spec field of fstab entry */ void FstabEntry::setFsSpec(const QString& s) { m_fsSpec = s; parseFsSpec(m_fsSpec, m_entryType, m_deviceNode); } FstabEntryList readFstabEntries( const QString& fstabPath ) { FstabEntryList fstabEntries; QFile fstabFile( fstabPath ); if ( fstabFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { const QStringList fstabLines = QString::fromLocal8Bit(fstabFile.readAll()).split( QLatin1Char('\n') ); for ( const QString& rawLine : fstabLines ) { QString line = rawLine.trimmed(); if ( line.startsWith( QLatin1Char('#') ) || line.isEmpty()) { fstabEntries.append( { {}, {}, {}, {}, {}, {}, line } ); continue; } QString comment = line.section( QLatin1Char('#'), 1 ); QStringList splitLine = line.section( QLatin1Char('#'), 0, 0 ).split( QRegularExpression(QStringLiteral("[\\s]+")), QString::SkipEmptyParts ); // We now split the standard components of /etc/fstab entry: // (0) path, or UUID, or LABEL, etc, // (1) mount point, // (2) file system type, // (3) options, // (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). switch (splitLine.length()) { case 4: fstabEntries.append( {splitLine.at(0), splitLine.at(1), splitLine.at(2), splitLine.at(3) } ); break; case 5: fstabEntries.append( {splitLine.at(0), splitLine.at(1), splitLine.at(2), splitLine.at(3), splitLine.at(4).toInt() } ); break; case 6: fstabEntries.append( {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 } ); break; default: fstabEntries.append( { {}, {}, {}, {}, {}, {}, QLatin1Char('#') + line } ); } } fstabFile.close(); if (fstabEntries.last().entryType() == comment && fstabEntries.last().comment().isEmpty()) fstabEntries.removeLast(); } return fstabEntries; } QStringList possibleMountPoints(const QString& deviceNode, const QString& fstabPath) { QStringList mountPoints; QString canonicalPath = QFileInfo(deviceNode).canonicalFilePath(); const FstabEntryList fstabEntryList = readFstabEntries( fstabPath ); for (const FstabEntry &entry : fstabEntryList) if (QFileInfo(entry.deviceNode()).canonicalFilePath() == canonicalPath) mountPoints.append(entry.mountPoint()); return mountPoints; } static QString findBlkIdDevice(const QString& token, const QString& value) { QString rval; +#if defined(Q_OS_LINUX) if (char* c = blkid_evaluate_tag(token.toLocal8Bit().constData(), value.toLocal8Bit().constData(), nullptr)) { rval = QString::fromLocal8Bit(c); free(c); } +#endif return rval; } static void parseFsSpec(const QString& m_fsSpec, FstabEntryType& m_entryType, QString& m_deviceNode) { m_entryType = FstabEntryType::comment; if (m_fsSpec.startsWith(QStringLiteral("UUID="))) { m_entryType = FstabEntryType::uuid; m_deviceNode = findBlkIdDevice(QStringLiteral("UUID"), QString(m_fsSpec).remove(QStringLiteral("UUID="))); } else if (m_fsSpec.startsWith(QStringLiteral("LABEL="))) { m_entryType = FstabEntryType::label; m_deviceNode = findBlkIdDevice(QStringLiteral("LABEL"), QString(m_fsSpec).remove(QStringLiteral("LABEL="))); } else if (m_fsSpec.startsWith(QStringLiteral("PARTUUID="))) { m_entryType = FstabEntryType::uuid; m_deviceNode = findBlkIdDevice(QStringLiteral("PARTUUID"), QString(m_fsSpec).remove(QStringLiteral("PARTUUID="))); } else if (m_fsSpec.startsWith(QStringLiteral("PARTLABEL="))) { m_entryType = FstabEntryType::label; m_deviceNode = findBlkIdDevice(QStringLiteral("PARTLABEL"), QString(m_fsSpec).remove(QStringLiteral("PARTLABEL="))); } else if (m_fsSpec.startsWith(QStringLiteral("/"))) { m_entryType = FstabEntryType::deviceNode; m_deviceNode = m_fsSpec; } } static void writeEntry(QFile& output, const FstabEntry& entry) { QTextStream s(&output); if (entry.entryType() == FstabEntryType::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" << entry.comment() << "\n"; } bool writeMountpoints(const FstabEntryList fstabEntries, const QString& filename) { QTemporaryFile out; out.setAutoRemove(false); if (!out.open()) { qWarning() << "could not open output file " << out.fileName(); return false; } else { for (const auto &e : fstabEntries) writeEntry(out, e); out.close(); const QString bakFilename = QStringLiteral("%1.bak").arg(filename); ExternalCommand mvCmd(QStringLiteral("mv"), { filename, bakFilename } ); if ( !(mvCmd.run(-1) && mvCmd.exitCode() == 0) ) { qWarning() << "could not backup " << filename << " to " << bakFilename; return false; } ExternalCommand mvCmd2(QStringLiteral("mv"), { out.fileName(), filename } ); if ( !(mvCmd2.run(-1) && mvCmd2.exitCode() == 0) ) { qWarning() << "could not move " << out.fileName() << " to " << filename; return false; } } return true; }