Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1,8 @@
add_subdirectory(solid)
add_subdirectory(tools)
ecm_qt_install_logging_categories(
EXPORT SOLID
FILE solid.categories
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
)
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
# Extract strings from all source files.
# EXTRACT_TR_STRINGS extracts strings with lupdate and convert them to .pot with
# lconvert.
$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/solid6_qt.pot
@@ -0,0 +1,120 @@
ecm_create_qm_loader(solid_QM_LOADER solid6_qt)
include(devices/CMakeLists.txt)
set(solid_LIB_SRCS ${solid_LIB_SRCS} ${solid_QM_LOADER})
add_library(KF6Solid ${solid_LIB_SRCS})
set(solid_BUILD_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_BINARY_DIR}/..
)
target_include_directories(KF6Solid PUBLIC "$<BUILD_INTERFACE:${solid_BUILD_INCLUDE_DIRS}>")
ecm_generate_export_header(KF6Solid
BASE_NAME Solid
GROUP_BASE_NAME KF
VERSION ${KF_VERSION}
USE_VERSION_HEADER
DEPRECATED_BASE_VERSION 0
DEPRECATION_VERSIONS
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
)
add_library(KF6::Solid ALIAS KF6Solid)
# Apps must include <Solid/File> or <solid/file.h>
target_include_directories(KF6Solid INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/Solid>")
target_link_libraries(KF6Solid PUBLIC Qt6::Core
PRIVATE Qt6::Xml
Qt6::Gui
${solid_OPTIONAL_LIBS}
)
if (HAVE_DBUS)
target_link_libraries(KF6Solid PRIVATE Qt6::DBus)
endif()
set_target_properties(KF6Solid PROPERTIES VERSION ${SOLID_VERSION}
SOVERSION ${SOLID_SOVERSION}
EXPORT_NAME Solid
)
ecm_generate_headers(Solid_CamelCase_HEADERS
HEADER_NAMES
Device
DeviceNotifier
DeviceInterface
GenericInterface
Processor
Block
StorageAccess
StorageDrive
OpticalDrive
StorageVolume
OpticalDisc
Camera
PortableMediaPlayer
Battery
Predicate
NetworkShare
SolidNamespace
RELATIVE devices/frontend
REQUIRED_HEADERS Solid_HEADERS
PREFIX Solid
)
install(FILES ${Solid_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/Solid/Solid COMPONENT Devel)
install(TARGETS KF6Solid EXPORT KF6SolidTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
########### static lib for tests ###############
if (BUILD_TESTING)
add_library(KF6Solid_static STATIC ${solid_LIB_SRCS})
set_target_properties(KF6Solid_static PROPERTIES COMPILE_FLAGS -DSOLID_STATIC_DEFINE=1)
target_link_libraries(KF6Solid_static PUBLIC Qt6::Core)
target_link_libraries(KF6Solid_static PRIVATE Qt6::Xml Qt6::Gui ${solid_OPTIONAL_LIBS})
if (HAVE_DBUS)
target_link_libraries(KF6Solid_static PRIVATE Qt6::DBus)
endif()
target_include_directories(KF6Solid_static PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/..;${CMAKE_CURRENT_BINARY_DIR}/..>")
endif()
########### install files ###############
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/solid_export.h
${Solid_HEADERS}
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/Solid/solid COMPONENT Devel
)
if(BUILD_QCH)
ecm_add_qch(
KF6Solid_QCH
NAME Solid
BASE_NAME KF6Solid
VERSION ${KF_VERSION}
ORG_DOMAIN org.kde
SOURCES # using only public headers, to cover only public API
${Solid_HEADERS}
"${CMAKE_SOURCE_DIR}/docs/song.md"
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
LINK_QCHS
Qt6Core_QCH
INCLUDE_DIRS
${solid_BUILD_INCLUDE_DIRS}
BLANK_MACROS
SOLID_EXPORT
SOLID_DEPRECATED
SOLID_DEPRECATED_EXPORT
"SOLID_DEPRECATED_VERSION(x, y, t)"
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
@@ -0,0 +1,131 @@
include (CheckCXXSourceCompiles)
if(WIN32)
add_definitions(-DYY_NO_UNISTD_H)
endif()
if(MSVC OR (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Intel"))
check_cxx_source_compiles("int main() { __asm { pxor mm0, mm0 }; }" HAVE_X86_MMX)
check_cxx_source_compiles("int main() { __asm { xorps xmm0, xmm0 }; }" HAVE_X86_SSE)
check_cxx_source_compiles("int main() { __asm { xorpd xmm0, xmm0 }; }" HAVE_X86_SSE2)
check_cxx_source_compiles("int main() { __asm { femms }; }" HAVE_X86_3DNOW)
else()
check_cxx_source_compiles(" #ifdef __SUNPRO_CC
#define __asm__ asm
#endif
int main() { __asm__(\"pxor %mm0, %mm0\") ; }" HAVE_X86_MMX)
check_cxx_source_compiles(" #ifdef __SUNPRO_CC
#define __asm__ asm
#endif
int main() { __asm__(\"xorps %xmm0, %xmm0\"); }" HAVE_X86_SSE)
check_cxx_source_compiles(" #ifdef __SUNPRO_CC
#define __asm__ asm
#endif
int main() { __asm__(\"xorpd %xmm0, %xmm0\"); }" HAVE_X86_SSE2)
check_cxx_source_compiles(" #ifdef __SUNPRO_CC
#define __asm__ asm
#endif
int main() { __asm__(\"femms\"); }" HAVE_X86_3DNOW)
endif()
check_cxx_source_compiles(" #ifdef __SUNPRO_CC
#define __asm__ asm
#endif
int main() { __asm__(\"mtspr 256, %0; vand %%v0, %%v0, %%v0\" : : \"r\"(-1) ); }" HAVE_PPC_ALTIVEC)
configure_file(devices/config-processor.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-processor.h )
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/devices/ ${CMAKE_CURRENT_SOURCE_DIR}/devices/frontend/ ${CMAKE_CURRENT_BINARY_DIR})
set(solid_LIB_SRCS
${solid_LIB_SRCS}
devices/managerbase.cpp
devices/solidnamespace.cpp
devices/predicateparse.cpp
devices/frontend/device.cpp
devices/frontend/devicemanager.cpp
devices/frontend/deviceinterface.cpp
devices/frontend/genericinterface.cpp
devices/frontend/processor.cpp
devices/frontend/block.cpp
devices/frontend/storagedrive.cpp
devices/frontend/opticaldrive.cpp
devices/frontend/storagevolume.cpp
devices/frontend/opticaldisc.cpp
devices/frontend/storageaccess.cpp
devices/frontend/camera.cpp
devices/frontend/portablemediaplayer.cpp
devices/frontend/networkshare.cpp
devices/frontend/battery.cpp
devices/frontend/predicate.cpp
devices/ifaces/battery.cpp
devices/ifaces/block.cpp
devices/ifaces/camera.cpp
devices/ifaces/opticaldrive.cpp
devices/ifaces/device.cpp
devices/ifaces/deviceinterface.cpp
devices/ifaces/devicemanager.cpp
devices/ifaces/genericinterface.cpp
devices/ifaces/networkshare.cpp
devices/ifaces/opticaldisc.cpp
devices/ifaces/portablemediaplayer.cpp
devices/ifaces/processor.cpp
devices/ifaces/storagedrive.cpp
devices/ifaces/storagevolume.cpp
devices/ifaces/storageaccess.cpp
devices/backends/shared/rootdevice.cpp
devices/backends/shared/cpufeatures.cpp
)
ecm_qt_declare_logging_category(solid_LIB_SRCS
HEADER devices_debug.h
IDENTIFIER Solid::Frontend::DeviceManager::DEVICEMANAGER
DEFAULT_SEVERITY Warning
CATEGORY_NAME kf.solid.frontend.devicemanager
DESCRIPTION "Solid (Device Manager)"
EXPORT SOLID
)
bison_target(SolidParser
devices/predicate_parser.y
${CMAKE_CURRENT_BINARY_DIR}/predicate_parser.c
COMPILE_FLAGS "-p Solid -d -b predicate_parser --no-lines"
)
set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/predicate_parser.h PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file
flex_target(SolidLexer
devices/predicate_lexer.l
${CMAKE_CURRENT_BINARY_DIR}/predicate_lexer.c
COMPILE_FLAGS "-P Solid --noline"
)
add_flex_bison_dependency(SolidLexer SolidParser)
list(APPEND solid_LIB_SRCS ${BISON_SolidParser_OUTPUTS} ${FLEX_SolidLexer_OUTPUTS})
include(CheckIncludeFiles)
include(CheckFunctionExists)
include(CheckCXXSourceCompiles)
#Needed for the fstab backend
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(sys/param.h HAVE_SYS_PARAM_H)
check_include_files("stdio.h;sys/mnttab.h" HAVE_SYS_MNTTAB_H)
check_include_files("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H)
check_function_exists(getmntinfo HAVE_GETMNTINFO)
check_cxx_source_compiles("
#include <sys/types.h>
#include <sys/statvfs.h>
int main(){
struct statvfs *mntbufp;
int flags;
return getmntinfo(&mntbufp, flags);
}
" GETMNTINFO_USES_STATVFS )
configure_file(devices/config-solid.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-solid.h )
set(solid_OPTIONAL_LIBS)
add_device_backends_build("${CMAKE_CURRENT_SOURCE_DIR}/devices/backends" solid_LIB_SRCS solid_OPTIONAL_LIBS)
@@ -0,0 +1,17 @@
set(backend_sources
fakebattery.cpp
fakeblock.cpp
fakecamera.cpp
fakecdrom.cpp
fakedevice.cpp
fakedeviceinterface.cpp
fakegenericinterface.cpp
fakemanager.cpp
fakenetworkshare.cpp
fakeopticaldisc.cpp
fakeportablemediaplayer.cpp
fakeprocessor.cpp
fakestorage.cpp
fakestorageaccess.cpp
fakevolume.cpp
)
@@ -0,0 +1,189 @@
/*
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2012 Lukas Tinkl <ltinkl@redhat.com>
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakebattery.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeBattery::FakeBattery(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakeBattery::~FakeBattery()
{
}
bool FakeBattery::isPresent() const
{
return fakeDevice()->property(QStringLiteral("isPresent")).toBool();
}
Solid::Battery::BatteryType FakeBattery::type() const
{
QString name = fakeDevice()->property(QStringLiteral("batteryType")).toString();
if (name == QLatin1String("pda")) {
return Solid::Battery::PdaBattery;
} else if (name == QLatin1String("ups")) {
return Solid::Battery::UpsBattery;
} else if (name == QLatin1String("primary")) {
return Solid::Battery::PrimaryBattery;
} else if (name == QLatin1String("mouse")) {
return Solid::Battery::MouseBattery;
} else if (name == QLatin1String("keyboard")) {
return Solid::Battery::KeyboardBattery;
} else if (name == QLatin1String("keyboard_mouse")) {
return Solid::Battery::KeyboardMouseBattery;
} else if (name == QLatin1String("camera")) {
return Solid::Battery::CameraBattery;
} else if (name == QLatin1String("gaminginput")) {
return Solid::Battery::GamingInputBattery;
} else if (name == QLatin1String("bluetooth")) {
return Solid::Battery::BluetoothBattery;
} else if (name == QLatin1String("tablet")) {
return Solid::Battery::TabletBattery;
} else {
return Solid::Battery::UnknownBattery;
}
}
int FakeBattery::chargePercent() const
{
int last_full = fakeDevice()->property(QStringLiteral("lastFullLevel")).toInt();
int current = fakeDevice()->property(QStringLiteral("currentLevel")).toInt();
int percent = 0;
if (last_full > 0) {
percent = (100 * current) / last_full;
}
return percent;
}
int FakeBattery::capacity() const
{
return fakeDevice()->property(QStringLiteral("capacity")).toInt();
}
int FakeBattery::cycleCount() const
{
return fakeDevice()->property(QStringLiteral("cycleCount")).toInt();
}
bool FakeBattery::isRechargeable() const
{
return fakeDevice()->property(QStringLiteral("isRechargeable")).toBool();
}
bool FakeBattery::isPowerSupply() const
{
return fakeDevice()->property(QStringLiteral("isPowerSupply")).toBool();
}
Solid::Battery::ChargeState FakeBattery::chargeState() const
{
QString state = fakeDevice()->property(QStringLiteral("chargeState")).toString();
if (state == QLatin1String("charging")) {
return Solid::Battery::Charging;
} else if (state == QLatin1String("discharging")) {
return Solid::Battery::Discharging;
} else if (state == QLatin1String("fullyCharged")) {
return Solid::Battery::FullyCharged;
} else {
return Solid::Battery::NoCharge;
}
}
qlonglong FakeBattery::timeToEmpty() const
{
return fakeDevice()->property(QStringLiteral("timeToEmpty")).toLongLong();
}
qlonglong FakeBattery::timeToFull() const
{
return fakeDevice()->property(QStringLiteral("timeToFull")).toLongLong();
}
void FakeBattery::setChargeState(Solid::Battery::ChargeState newState)
{
QString name;
switch (newState) {
case Solid::Battery::Charging:
name = QStringLiteral("charging");
break;
case Solid::Battery::Discharging:
name = QStringLiteral("discharging");
break;
case Solid::Battery::NoCharge:
name = QStringLiteral("noCharge");
break;
case Solid::Battery::FullyCharged:
name = QStringLiteral("fullyCharged");
break;
}
fakeDevice()->setProperty(QStringLiteral("chargeState"), name);
Q_EMIT chargeStateChanged(newState, fakeDevice()->udi());
}
void FakeBattery::setChargeLevel(int newLevel)
{
fakeDevice()->setProperty(QStringLiteral("currentLevel"), newLevel);
Q_EMIT chargePercentChanged(chargePercent(), fakeDevice()->udi());
}
Solid::Battery::Technology FakeBattery::technology() const
{
return (Solid::Battery::Technology)fakeDevice()->property(QStringLiteral("technology")).toInt();
}
double FakeBattery::energy() const
{
return fakeDevice()->property(QStringLiteral("energy")).toDouble();
}
double FakeBattery::energyFull() const
{
return fakeDevice()->property(QStringLiteral("energyFull")).toDouble();
}
double FakeBattery::energyFullDesign() const
{
return fakeDevice()->property(QStringLiteral("energyFullDesign")).toDouble();
}
double FakeBattery::energyRate() const
{
return fakeDevice()->property(QStringLiteral("energyRate")).toDouble();
}
double FakeBattery::voltage() const
{
return fakeDevice()->property(QStringLiteral("voltage")).toDouble();
}
double FakeBattery::temperature() const
{
return fakeDevice()->property(QStringLiteral("temperature")).toDouble();
}
QString FakeBattery::serial() const
{
return fakeDevice()->property(QStringLiteral("serial")).toString();
}
qlonglong FakeBattery::remainingTime() const
{
return fakeDevice()->property(QStringLiteral("remainingTime")).toLongLong();
}
#include "moc_fakebattery.cpp"
@@ -0,0 +1,83 @@
/*
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2012 Lukas Tinkl <ltinkl@redhat.com>
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEBATTERY_H
#define SOLID_BACKENDS_FAKEHW_FAKEBATTERY_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/battery.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeBattery : public FakeDeviceInterface, virtual public Solid::Ifaces::Battery
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Battery)
public:
explicit FakeBattery(FakeDevice *device);
~FakeBattery() override;
public Q_SLOTS:
bool isPresent() const override;
Solid::Battery::BatteryType type() const override;
int chargePercent() const override;
int capacity() const override;
int cycleCount() const override;
bool isRechargeable() const override;
bool isPowerSupply() const override;
Solid::Battery::ChargeState chargeState() const override;
qlonglong timeToEmpty() const override;
qlonglong timeToFull() const override;
void setChargeState(Solid::Battery::ChargeState newState);
void setChargeLevel(int newLevel);
Solid::Battery::Technology technology() const override;
double energy() const override;
double energyFull() const override;
double energyFullDesign() const override;
double energyRate() const override;
double voltage() const override;
double temperature() const override;
QString serial() const override;
qlonglong remainingTime() const override;
Q_SIGNALS:
void presentStateChanged(bool newState, const QString &udi) override;
void chargePercentChanged(int value, const QString &udi) override;
void capacityChanged(int value, const QString &udi) override;
void cycleCountChanged(int value, const QString &udi) override;
void powerSupplyStateChanged(bool newState, const QString &udi) override;
void chargeStateChanged(int newState, const QString &udi) override;
void timeToEmptyChanged(qlonglong time, const QString &udi) override;
void timeToFullChanged(qlonglong time, const QString &udi) override;
void energyChanged(double energy, const QString &udi) override;
void energyFullChanged(double energyFull, const QString &udi) override;
void energyFullDesignChanged(double energyFullDesign, const QString &udi) override;
void energyRateChanged(double energyRate, const QString &udi) override;
void voltageChanged(double voltage, const QString &udi) override;
void temperatureChanged(double temperature, const QString &udi) override;
void remainingTimeChanged(qlonglong time, const QString &udi) override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEBATTERY_H
@@ -0,0 +1,36 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakeblock.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeBlock::FakeBlock(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakeBlock::~FakeBlock()
{
}
int FakeBlock::deviceMajor() const
{
return fakeDevice()->property(QStringLiteral("major")).toInt();
}
int FakeBlock::deviceMinor() const
{
return fakeDevice()->property(QStringLiteral("minor")).toInt();
}
QString FakeBlock::device() const
{
return fakeDevice()->property(QStringLiteral("device")).toString();
}
#include "moc_fakeblock.cpp"
@@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEBLOCK_H
#define SOLID_BACKENDS_FAKEHW_FAKEBLOCK_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/block.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeBlock : public FakeDeviceInterface, virtual public Solid::Ifaces::Block
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Block)
public:
explicit FakeBlock(FakeDevice *device);
~FakeBlock() override;
public Q_SLOTS:
int deviceMajor() const override;
int deviceMinor() const override;
QString device() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEBLOCK_H
@@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakecamera.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeCamera::FakeCamera(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakeCamera::~FakeCamera()
{
}
QStringList FakeCamera::supportedProtocols() const
{
QString method = fakeDevice()->property(QStringLiteral("accessMethod")).toString();
return {method};
}
QStringList FakeCamera::supportedDrivers(QString /*protocol*/) const
{
if (fakeDevice()->property(QStringLiteral("gphotoSupport")).toBool()) {
return {QStringLiteral("gphoto")};
}
return {};
}
QVariant Solid::Backends::Fake::FakeCamera::driverHandle(const QString &driver) const
{
Q_UNUSED(driver);
return QVariant();
}
#include "moc_fakecamera.cpp"
@@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKECAMERA_H
#define SOLID_BACKENDS_FAKEHW_FAKECAMERA_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/camera.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeCamera : public FakeDeviceInterface, virtual public Solid::Ifaces::Camera
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Camera)
public:
explicit FakeCamera(FakeDevice *device);
~FakeCamera() override;
public Q_SLOTS:
QStringList supportedProtocols() const override;
QStringList supportedDrivers(QString protocol) const override;
QVariant driverHandle(const QString &driver) const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKECAMERA_H
@@ -0,0 +1,81 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakecdrom.h"
#include <QStringList>
using namespace Solid::Backends::Fake;
FakeCdrom::FakeCdrom(FakeDevice *device)
: FakeStorage(device)
{
}
FakeCdrom::~FakeCdrom()
{
}
Solid::OpticalDrive::MediumTypes FakeCdrom::supportedMedia() const
{
Solid::OpticalDrive::MediumTypes supported;
const QMap<QString, Solid::OpticalDrive::MediumType> map = {
{QStringLiteral("cdr"), Solid::OpticalDrive::Cdr},
{QStringLiteral("cdrw"), Solid::OpticalDrive::Cdrw},
{QStringLiteral("dvd"), Solid::OpticalDrive::Dvd},
{QStringLiteral("dvdr"), Solid::OpticalDrive::Dvdr},
{QStringLiteral("dvdrw"), Solid::OpticalDrive::Dvdrw},
{QStringLiteral("dvdram"), Solid::OpticalDrive::Dvdram},
{QStringLiteral("dvdplusr"), Solid::OpticalDrive::Dvdplusr},
{QStringLiteral("dvdplusrw"), Solid::OpticalDrive::Dvdplusrw},
{QStringLiteral("dvdplusrdl"), Solid::OpticalDrive::Dvdplusdl},
{QStringLiteral("dvdplusrwdl"), Solid::OpticalDrive::Dvdplusdlrw},
{QStringLiteral("bd"), Solid::OpticalDrive::Bd},
{QStringLiteral("bdr"), Solid::OpticalDrive::Bdr},
{QStringLiteral("bdre"), Solid::OpticalDrive::Bdre},
{QStringLiteral("hddvd"), Solid::OpticalDrive::HdDvd},
{QStringLiteral("hddvdr"), Solid::OpticalDrive::HdDvdr},
{QStringLiteral("hddvdrw"), Solid::OpticalDrive::HdDvdrw},
};
const QStringList supported_medialist = fakeDevice()->property(QStringLiteral("supportedMedia")).toString().simplified().split(QLatin1Char(','));
for (const QString &media : supported_medialist) {
supported |= map.value(media, Solid::OpticalDrive::UnknownMediumType);
}
return supported;
}
int FakeCdrom::readSpeed() const
{
return fakeDevice()->property(QStringLiteral("readSpeed")).toInt();
}
int FakeCdrom::writeSpeed() const
{
return fakeDevice()->property(QStringLiteral("writeSpeed")).toInt();
}
QList<int> FakeCdrom::writeSpeeds() const
{
QList<int> speeds;
const QStringList speed_strlist = fakeDevice()->property(QStringLiteral("writeSpeeds")).toString().simplified().split(QLatin1Char(','));
for (const QString &speed_str : speed_strlist) {
speeds << speed_str.toInt();
}
return speeds;
}
bool FakeCdrom::eject()
{
return false;
}
#include "moc_fakecdrom.cpp"
@@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKECDROM_H
#define SOLID_BACKENDS_FAKEHW_FAKECDROM_H
#include "fakestorage.h"
#include <solid/devices/ifaces/opticaldrive.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeCdrom : public FakeStorage, virtual public Solid::Ifaces::OpticalDrive
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::OpticalDrive)
public:
explicit FakeCdrom(FakeDevice *device);
~FakeCdrom() override;
public Q_SLOTS:
Solid::OpticalDrive::MediumTypes supportedMedia() const override;
int readSpeed() const override;
int writeSpeed() const override;
QList<int> writeSpeeds() const override;
bool eject() override;
Q_SIGNALS:
void ejectPressed(const QString &udi) override;
void ejectDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKECDROM_H
@@ -0,0 +1,620 @@
<!-- Please note that in this file we indent more than necessary so that the
device tree is visible -->
<machine>
<!-- This is a computer -->
<device udi="/org/kde/solid/fakehw/computer">
<property key="name">Computer</property>
<property key="vendor">Solid</property>
</device>
<!-- A system with its own AC adapter and a battery (like a laptop) -->
<device udi="/org/kde/solid/fakehw/acpi_AC">
<property key="name">AC Adapter</property>
<property key="interfaces">AcAdapter</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
<property key="isPlugged">false</property>
</device>
<device udi="/org/kde/solid/fakehw/acpi_BAT0">
<property key="name">Battery Bay</property>
<property key="vendor">Acme Corporation</property>
<property key="interfaces">Battery</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
<property key="isPresent">true</property>
<property key="batteryType">primary</property>
<property key="chargeLevelUnit">mWh</property>
<property key="maxLevel">43200000</property>
<property key="lastFullLevel">42165000</property>
<property key="currentLevel">42100000</property>
<property key="warningLevel">140550000</property>
<property key="lowLevel">7027500</property>
<property key="voltageUnit">mV</property>
<property key="voltage">11999</property>
<property key="isRechargeable">true</property>
<property key="isPowerSupply">true</property>
<property key="chargeState">discharging</property>
<property key="remainingTime">1000.5</property>
</device>
<device udi="/org/kde/solid/fakehw/acpi_BAT1">
<property key="name">Miraculous Mouse</property>
<property key="vendor">Orange Inc.</property>
<property key="interfaces">Battery</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
<property key="isPresent">false</property>
<property key="batteryType">mouse</property>
<!-- Battery properties beyond charge percentage are only reported by UPower
for primary batteries, not for other batteries like this mouse -->
<property key="isRechargeable">true</property>
<property key="isPowerSupply">false</property>
<property key="chargeState">discharging</property>
<property key="capacity">85</property>
<property key="cycleCount">175</property>
<property key="technology">1</property>
<property key="energy">72.25</property>
<property key="energyRate">21.5</property>
<property key="voltage">12.5</property>
</device>
<!-- Two CPUs -->
<device udi="/org/kde/solid/fakehw/acpi_CPU0">
<property key="name">Solid Processor #0</property>
<property key="interfaces">Processor</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
<property key="number">0</property>
<property key="maxSpeed">3200</property>
<property key="canChangeFrequency">true</property>
<property key="instructionSets">mmx,sse</property>
</device>
<device udi="/org/kde/solid/fakehw/acpi_CPU1">
<property key="name">Solid Processor #1</property>
<property key="interfaces">Processor</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
<property key="number">1</property>
<property key="maxSpeed">3200</property>
<property key="canChangeFrequency">true</property>
</device>
<!-- Platform Device for a floppy drive -->
<device udi="/org/kde/solid/fakehw/platform_floppy_0">
<property key="name">Platform Device (floppy)</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- The actual floppy device -->
<device udi="/org/kde/solid/fakehw/platform_floppy_0_storage">
<property key="name">PC Floppy Drive</property>
<property key="interfaces">StorageDrive,Block</property>
<property key="parent">/org/kde/solid/fakehw/platform_floppy_0</property>
<property key="minor">0</property>
<property key="major">2</property>
<property key="device">/dev/fd0</property>
<property key="bus">platform</property>
<property key="driveType">floppy</property>
<property key="isRemovable">true</property>
<property key="isEjectRequired">false</property>
<property key="isHotpluggable">false</property>
<property key="isMediaCheckEnabled">false</property>
</device>
<!-- A (generally) virtual volume tracking the floppy drive state -->
<device udi="/org/kde/solid/fakehw/platform_floppy_0_storage_virt_volume">
<property key="name">Floppy Disk</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/platform_floppy_0_storage</property>
<property key="minor">0</property>
<property key="major">2</property>
<property key="device">/dev/fd0</property>
<property key="isIgnored">false</property>
<property key="isMounted">true</property>
<property key="mountPoint">/media/floppy0</property>
<property key="usage">filesystem</property>
</device>
<!-- Primary IDE controller -->
<device udi="/org/kde/solid/fakehw/pci_001">
<property key="name">99021 IDE Controller #1</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- Master device... -->
<device udi="/org/kde/solid/fakehw/pci_001_ide_0_0">
<property key="name">IDE device (master)</property>
<property key="parent">/org/kde/solid/fakehw/pci_001</property>
</device>
<!-- ... is a 250GB disk... -->
<device udi="/org/kde/solid/fakehw/storage_serial_HD56890I">
<property key="name">HD250GB</property>
<property key="vendor">Acme Corporation</property>
<property key="interfaces">StorageDrive,Block</property>
<property key="parent">/org/kde/solid/fakehw/pci_001_ide_0_0</property>
<property key="minor">0</property>
<property key="major">3</property>
<property key="device">/dev/hda</property>
<property key="bus">scsi</property>
<property key="driveType">disk</property>
<property key="isRemovable">false</property>
<property key="isEjectRequired">false</property>
<property key="isHotpluggable">false</property>
<property key="isMediaCheckEnabled">false</property>
<property key="product">HD250GBSATA</property>
</device>
<!-- ... with five partitions:
- one physical partition (the root /, ext3, 20GB)
- one extended containing three logical volumes:
- a swap volume (2GB)
- /home volume (xfs, 188GB)
- /foreign volume (ntfs, 20GB)
- /data volume (encrypted Luks container, btrfs, 20GB)
-->
<device udi="/org/kde/solid/fakehw/volume_uuid_feedface">
<property key="name">/</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">1</property>
<property key="major">3</property>
<property key="device">/dev/hda1</property>
<property key="isIgnored">true</property>
<property key="isMounted">true</property>
<property key="mountPoint">/</property>
<property key="usage">filesystem</property>
<property key="fsType">ext3</property>
<property key="label">Root</property>
<property key="uuid">feedface</property>
<property key="size">21474836480</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_uuid_c0ffee">
<property key="name">/home</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">6</property>
<property key="major">3</property>
<property key="device">/dev/hda6</property>
<property key="isIgnored">true</property>
<property key="isMounted">true</property>
<property key="mountPoint">/home</property>
<property key="usage">filesystem</property>
<property key="fsType">xfs</property>
<property key="label">Home</property>
<property key="uuid">c0ffee</property>
<property key="size">201863462912</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_uuid_f00ba7">
<property key="name">/foreign</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">7</property>
<property key="major">3</property>
<property key="device">/dev/hda7</property>
<property key="isIgnored">false</property>
<property key="isMounted">true</property>
<property key="mountPoint">/foreign</property>
<property key="usage">filesystem</property>
<property key="fsType">ntfs</property>
<property key="label">Foreign</property>
<property key="uuid">f00ba7</property>
<property key="size">21474836480</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_part2_size_1024">
<property key="name">StorageVolume</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">2</property>
<property key="major">3</property>
<property key="device">/dev/hda2</property>
<property key="isIgnored">true</property>
<property key="isMounted">false</property>
<property key="usage">other</property>
<property key="size">1024</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_part5_size_1048576">
<property key="name">StorageVolume (swap)</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">5</property>
<property key="major">3</property>
<property key="device">/dev/hda5</property>
<property key="isIgnored">true</property>
<property key="isMounted">false</property>
<property key="usage">other</property>
<property key="fsType">swap</property>
<property key="size">2147483648</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_uuid_encrypted_0123">
<property key="name">Luks Container</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_HD56890I</property>
<property key="minor">8</property>
<property key="major">3</property>
<property key="device">/dev/hda8</property>
<property key="isIgnored">true</property>
<property key="isMounted">true</property>
<property key="mountPoint">/data</property>
<property key="usage">encrypted</property>
<property key="fsType">crypto_LUKS</property>
<property key="label"></property>
<property key="uuid">encrypted-0123</property>
<property key="size">21474836480</property>
</device>
<device udi="/org/kde/solid/fakehw/volume_uuid_cleartext_data_0123">
<property key="name">Encrypted data</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/</property>
<property key="minor">0</property>
<property key="major">254</property>
<property key="device">/dev/dm-0</property>
<property key="isIgnored">true</property>
<property key="isMounted">true</property>
<property key="mountPoint">/data</property>
<property key="usage">filesystem</property>
<property key="fsType">btrfs</property>
<property key="label"></property>
<property key="uuid">cleartext-data-0123</property>
<property key="size">21474835466</property>
</device>
<!-- Secondary IDE controller -->
<device udi="/org/kde/solid/fakehw/pci_002">
<property key="name">99021 IDE Controller #2</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- Master device... -->
<device udi="/org/kde/solid/fakehw/pci_002_ide_1_0">
<property key="name">IDE device (master)</property>
<property key="parent">/org/kde/solid/fakehw/pci_002</property>
</device>
<!-- ... is a DVD writer... -->
<device udi="/org/kde/solid/fakehw/storage_model_solid_writer">
<property key="name">Solid IDE DVD Writer</property>
<property key="vendor">Acme Corporation</property>
<property key="interfaces">Block,StorageDrive,OpticalDrive</property>
<property key="parent">/org/kde/solid/fakehw/pci_002_ide_1_0</property>
<property key="minor">0</property>
<property key="major">22</property>
<property key="device">/dev/hdc</property>
<property key="bus">ide</property>
<property key="driveType">cdrom</property>
<property key="isRemovable">true</property>
<property key="isEjectRequired">true</property>
<property key="isHotpluggable">false</property>
<property key="isMediaCheckEnabled">true</property>
<property key="product">Solid DVD Writer</property>
<property key="supportedMedia">cdr,cdrw,dvd,dvdr,dvdrw</property>
<property key="readSpeed">4234</property>
<property key="writeSpeed">4234</property>
<property key="writeSpeeds">4234,2822,2117,1411,706</property>
</device>
<!-- ... with a cd-r in it -->
<device udi="/org/kde/solid/fakehw/volume_uuid_5011">
<property key="name">FooDistro i386</property>
<property key="interfaces">Block,StorageVolume,OpticalDisc,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_model_solid_writer</property>
<property key="discType">cd_rw</property>
<property key="isAppendable">false</property>
<property key="isRewritable">true</property>
<property key="isBlank">false</property>
<property key="availableContent">data</property>
<property key="mountPoint">/media/cdrom</property>
<property key="uuid">5011</property>
<property key="size">731047936</property>
<property key="label">FooDistro i386</property>
</device>
<!-- Slave device... -->
<device udi="/org/kde/solid/fakehw/pci_002_ide_1_1">
<property key="name">IDE device (slave)</property>
<property key="parent">/org/kde/solid/fakehw/pci_002</property>
</device>
<!-- ... is a DVD reader... -->
<device udi="/org/kde/solid/fakehw/storage_model_solid_reader">
<property key="name">Solid IDE DVD Reader</property>
<property key="vendor">Acme Corporation</property>
<property key="interfaces">Block,StorageDrive,OpticalDrive</property>
<property key="parent">/org/kde/solid/fakehw/pci_002_ide_1_1</property>
<property key="minor">0</property>
<property key="major">22</property>
<property key="device">/dev/hdc</property>
<property key="bus">ide</property>
<property key="driveType">cdrom</property>
<property key="isRemovable">true</property>
<property key="isEjectRequired">true</property>
<property key="isHotpluggable">false</property>
<property key="isMediaCheckEnabled">true</property>
<property key="product">Solid DVD Reader</property>
<property key="supportedMedia">cdr,cdrw,dvd,dvdr,dvdrw,dvdram,dvdplusr,dvdplusrw</property>
<property key="readSpeed">4234</property>
</device>
<!-- ... with a DVD Video in it -->
<device udi="/org/kde/solid/fakehw/volume_label_SOLIDMAN_BEGINS">
<property key="name">SolidMan Begins</property>
<property key="interfaces">Block,StorageVolume,OpticalDisc</property>
<property key="parent">/org/kde/solid/fakehw/storage_model_solid_reader</property>
<property key="discType">dvd_rom</property>
<property key="isAppendable">false</property>
<property key="isRewritable">false</property>
<property key="isBlank">false</property>
<property key="availableContent">dvdvideo</property>
<property key="uuid">5012</property>
<property key="size">8033075200</property>
<property key="label">SolidMan Begins</property>
</device>
<!-- Some unmounted storage
Most attributes are irrelevant, but it has to be sorted first,
and it has to have an empty mountPoint.
-->
<device udi="/org/kde/solid/fakehw/volume_0000_unmounted_storage">
<property key="name">/</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw</property>
<property key="minor">0</property>
<property key="major">253</property>
<property key="device">/dev/sdg1</property>
<property key="isIgnored">true</property>
<property key="isMounted">false</property>
<property key="mountPoint"></property>
<property key="usage">filesystem</property>
<property key="fsType">vfat</property>
<property key="label">Unmounted_drive</property>
<property key="uuid">abcd-0123</property>
<property key="size">7742685184</property>
</device>
<!-- First USB Controller -->
<device udi="/org/kde/solid/fakehw/pci_8086_265c">
<property key="name">99021 USB2 EHCI Controller #1</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- Host Controller -->
<device udi="/org/kde/solid/fakehw/usb_device_0_0_1d_7">
<property key="name">EHCI Host Controller</property>
<property key="vendor">Kernel ehci_hcd</property>
<property key="parent">/org/kde/solid/fakehw/pci_8086_265c</property>
</device>
<!-- USB Device -->
<device udi="/org/kde/solid/fakehw/usb_device_4e8_5041">
<property key="name">Acme XO-Y4</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_0_0_1d_7</property>
</device>
<!-- Mass Storage Interface -->
<device udi="/org/kde/solid/fakehw/usb_device_4e8_5041_if0">
<property key="name">USB Mass Storage Interface</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4e8_5041</property>
</device>
<!-- SCSI Adapter -->
<device udi="/org/kde/solid/fakehw/usb_device_4e8_5041_if0_scsi_host">
<property key="name">SCSI Host Adapter</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4e8_5041_if0</property>
</device>
<!-- SCSI Device -->
<device udi="/org/kde/solid/fakehw/usb_device_4e8_5041_if0_scsi_host_scsi_device_lun0">
<property key="name">SCSI Device</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4e8_5041_if0_scsi_host</property>
</device>
<!-- We finally find the storage device, which is a portable media player... -->
<device udi="/org/kde/solid/fakehw/storage_serial_XOY4_5206">
<property key="name">XO-Y4</property>
<property key="vendor">Acme Electronics</property>
<property key="interfaces">StorageDrive,Block,PortableMediaPlayer</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4e8_5041_if0_scsi_host_scsi_device_lun0</property>
<property key="minor">0</property>
<property key="major">8</property>
<property key="device">/dev/sda</property>
<property key="bus">usb</property>
<property key="driveType">disk</property>
<property key="isRemovable">true</property>
<property key="isEjectRequired">true</property>
<property key="isHotpluggable">true</property>
<property key="isMediaCheckEnabled">true</property>
<property key="product">XO-Y4</property>
<property key="accessMethod">MassStorage</property>
<property key="outputFormats">audio/x-mp3</property>
<property key="inputFormats">audio/x-wav,audio/x-mp3,audio/vorbis</property>
<property key="playlistFormats">audio/x-mpegurl</property>
</device>
<!-- ... with a partition since it's a USB Mass Storage device -->
<device udi="/org/kde/solid/fakehw/volume_part1_size_993284096">
<property key="name">StorageVolume (vfat)</property>
<property key="interfaces">Block,StorageVolume,StorageAccess</property>
<property key="parent">/org/kde/solid/fakehw/storage_serial_XOY4_5206</property>
<property key="minor">1</property>
<property key="major">8</property>
<property key="device">/dev/sda1</property>
<property key="isIgnored">false</property>
<property key="isMounted">true</property>
<property key="mountPoint">/media/XO-Y4</property>
<property key="usage">filesystem</property>
<property key="fsType">vfat</property>
<property key="size">993284096</property>
</device>
<!-- Second USB Controller -->
<device udi="/org/kde/solid/fakehw/pci_8086_265d">
<property key="name">99021 USB UHCI #1</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- Host Controller -->
<device udi="/org/kde/solid/fakehw/usb_device_0_0_1d_2">
<property key="name">UHCI Host Controller</property>
<property key="vendor">Kernel uhci_hcd</property>
<property key="parent">/org/kde/solid/fakehw/pci_8086_265d</property>
</device>
<!-- USB Device #1 -->
<device udi="/org/kde/solid/fakehw/usb_device_4a9_30b9_noserial">
<property key="name">PowerBullet A35</property>
<property key="vendor">Firearm Inc.</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_0_0_1d_2</property>
</device>
<!-- We finally find the camera interface -->
<device udi="/org/kde/solid/fakehw/usb_device_4a9_30b9_noserial_if0">
<property key="name">USB Imaging Interface</property>
<property key="interfaces">Camera</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4a9_30b9_noserial</property>
<property key="accessMethod">ptp</property>
<property key="gphotoSupport">true</property>
</device>
<!-- USB Device #2 containing a battery -->
<device udi="/org/kde/solid/fakehw/usb_device_1267_210_noserial">
<property key="name">ZX Cordless Mouse</property>
<property key="vendor">Logi4 Inc.</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_0_0_1d_2</property>
<property key="interfaces">Battery</property>
<property key="isPresent">true</property>
<property key="isPowerSupply">false</property>
<property key="batteryType">mouse</property>
<property key="chargeLevelUnit">mWh</property>
<property key="maxLevel">432000</property>
<property key="lastFullLevel">421650</property>
<property key="currentLevel">421000</property>
<property key="warningLevel">1405500</property>
<property key="lowLevel">70275</property>
<property key="voltageUnit">mV</property>
<property key="voltage">5100</property>
<property key="isRechargeable">true</property>
<property key="chargeState">charging</property>
</device>
<!-- HID Interface -->
<device udi="/org/kde/solid/fakehw/usb_device_1267_210_noserial_if0">
<property key="name">USB HID Interface</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_1267_210_noserial</property>
</device>
<!-- We finally find the mouse device -->
<device udi="/org/kde/solid/fakehw/usb_device_1267_210_noserial_if0_logical_dev_input">
<property key="name">Logi4 Receiver</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_1267_210_noserial_if0</property>
<!-- TODO: Complete this if we get input (mouse and keyb) related interfaces -->
</device>
<!-- USB Device #3 -->
<device udi="/org/kde/solid/fakehw/usb_device_4f1_5d33_HF8459">
<property key="name">ORB 2400 series</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_0_0_1d_2</property>
</device>
<!-- USB Printer Interface -->
<device udi="/org/kde/solid/fakehw/usb_device_4f1_5d33_HF8459_if0">
<property key="name">USB Printer Interface</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4f1_5d33_HF8459</property>
</device>
<!-- We finally find the printer device -->
<device udi="/org/kde/solid/fakehw/usb_device_4f1_5d33_HF8459_if0_printer">
<property key="name">ORB 2400 series</property>
<property key="vendor">Acme</property>
<property key="parent">/org/kde/solid/fakehw/usb_device_4f1_5d33_HF8459_if0</property>
<!-- TODO: Complete this if we get printer related interfaces -->
</device>
<!-- PCI Bridge -->
<device udi="/org/kde/solid/fakehw/pci_8086_2448">
<property key="name">99021 PCI Bridge</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<!-- PCI device #1 -->
<device udi="/org/kde/solid/fakehw/pci_3452_7890">
<property key="name">Wireless 1144AH</property>
<property key="vendor">Acme Corporation</property>
<property key="parent">/org/kde/solid/fakehw/pci_8086_2448</property>
</device>
<!-- PCI device #2 -->
<device udi="/org/kde/solid/fakehw/pci_8904_5e21">
<property key="name">RC-1893</property>
<property key="vendor">ReallyChip Corporation</property>
<property key="parent">/org/kde/solid/fakehw/pci_8086_2448</property>
</device>
<!-- PCI device #3 -->
<device udi="/org/kde/solid/fakehw/pci_8843_6a11">
<property key="name">VisioTNT</property>
<property key="vendor">DigitalVid Ltd</property>
<property key="parent">/org/kde/solid/fakehw/pci_8086_2448</property>
</device>
<!-- Digital video broadcasting interface -->
<device udi="/org/kde/solid/fakehw/pci_8843_6a11_dvb1">
<property key="name">DVB Interface</property>
<property key="interfaces">DvbInterface</property>
<property key="parent">/org/kde/solid/fakehw/pci_8843_6a11</property>
<property key="device">/dev/broadcast0/demux</property>
<property key="deviceAdapter">2</property>
<property key="deviceType">demux</property>
<property key="deviceIndex">1</property>
</device>
<device udi="/org/kde/solid/fakehw/fstab">
<property key="name">Network Shares</property>
<property key="product">Network Shares</property>
<property key="vendor">KDE</property>
<property key="parent">/org/kde/solid/fakehw/computer</property>
</device>
<device udi="/org/kde/solid/fakehw/fstab/thehost/solidpath">
<property key="parent">/org/kde/solid/fstab</property>
<property key="interfaces">NetworkShare,StorageAccess</property>
<property key="vendor">/solidpath</property>
<property key="product">thehost</property>
<property key="type">nfs</property>
<property key="url">nfs://thehost/solid-path</property>
<property key="filePath">/media/nfs</property>
<property key="isIgnored">false</property>
<property key="isMounted">true</property>
<property key="mountPoint">/media/nfs</property>
</device>
</machine>
@@ -0,0 +1,305 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakedevice.h"
#include "fakedevice_p.h"
#include "fakebattery.h"
#include "fakeblock.h"
#include "fakecamera.h"
#include "fakecdrom.h"
#include "fakedeviceinterface.h"
#include "fakegenericinterface.h"
#include "fakenetworkshare.h"
#include "fakeopticaldisc.h"
#include "fakeportablemediaplayer.h"
#include "fakeprocessor.h"
#include "fakestorage.h"
#include "fakestorageaccess.h"
#include "fakevolume.h"
#include <QStringList>
#ifdef HAVE_DBUS
#include <QDBusConnection>
#endif
#include <solid/genericinterface.h>
using namespace Solid::Backends::Fake;
FakeDevice::FakeDevice(const QString &udi, const QMap<QString, QVariant> &propertyMap)
: Solid::Ifaces::Device()
, d(new Private)
{
d->udi = udi;
d->propertyMap = propertyMap;
d->interfaceList = d->propertyMap[QStringLiteral("interfaces")].toString().simplified().split(QLatin1Char(','));
d->interfaceList << QStringLiteral("GenericInterface");
d->locked = false;
d->broken = false;
#ifdef HAVE_DBUS
QDBusConnection::sessionBus().registerObject(udi, this, QDBusConnection::ExportNonScriptableSlots);
#endif
// Force instantiation of all the device interfaces
// this way they'll get exported on the bus
// that means they'll be created twice, but that won't be
// a problem for unit testing.
for (const QString &interface : std::as_const(d->interfaceList)) {
Solid::DeviceInterface::Type type = Solid::DeviceInterface::stringToType(interface);
createDeviceInterface(type);
}
connect(d.data(), SIGNAL(propertyChanged(QMap<QString, int>)), this, SIGNAL(propertyChanged(QMap<QString, int>)));
connect(d.data(), SIGNAL(conditionRaised(QString, QString)), this, SIGNAL(conditionRaised(QString, QString)));
}
FakeDevice::FakeDevice(const FakeDevice &dev)
: Solid::Ifaces::Device()
, d(dev.d)
{
connect(d.data(), SIGNAL(propertyChanged(QMap<QString, int>)), this, SIGNAL(propertyChanged(QMap<QString, int>)));
connect(d.data(), SIGNAL(conditionRaised(QString, QString)), this, SIGNAL(conditionRaised(QString, QString)));
}
FakeDevice::~FakeDevice()
{
#ifdef HAVE_DBUS
QDBusConnection::sessionBus().unregisterObject(d->udi, QDBusConnection::UnregisterTree);
#endif
}
QString FakeDevice::udi() const
{
return d->udi;
}
QString FakeDevice::parentUdi() const
{
return d->propertyMap[QStringLiteral("parent")].toString();
}
QString FakeDevice::vendor() const
{
return d->propertyMap[QStringLiteral("vendor")].toString();
}
QString FakeDevice::product() const
{
return d->propertyMap[QStringLiteral("name")].toString();
}
QString FakeDevice::icon() const
{
if (parentUdi().isEmpty()) {
return QStringLiteral("system");
} else if (queryDeviceInterface(Solid::DeviceInterface::OpticalDrive)) {
return QStringLiteral("cdrom-unmount");
} else if (queryDeviceInterface(Solid::DeviceInterface::PortableMediaPlayer)) {
return QStringLiteral("ipod-unmount");
} else if (queryDeviceInterface(Solid::DeviceInterface::Camera)) {
return QStringLiteral("camera-unmount");
} else if (queryDeviceInterface(Solid::DeviceInterface::Processor)) {
return QStringLiteral("cpu");
} else if (queryDeviceInterface(Solid::DeviceInterface::StorageDrive)) {
return QStringLiteral("hdd-unmount");
} else if (queryDeviceInterface(Solid::DeviceInterface::Block)) {
return QStringLiteral("blockdevice");
} else {
return QStringLiteral("hwinfo");
}
}
QStringList FakeDevice::emblems() const
{
if (queryDeviceInterface(Solid::DeviceInterface::StorageAccess)) {
if (property(QStringLiteral("isMounted")).toBool()) {
return {QStringLiteral("emblem-mounted")};
} else {
return {QStringLiteral("emblem-unmounted")};
}
}
return {};
}
QString FakeDevice::description() const
{
return product();
}
QVariant FakeDevice::property(const QString &key) const
{
return d->propertyMap[key];
}
QMap<QString, QVariant> FakeDevice::allProperties() const
{
return d->propertyMap;
}
bool FakeDevice::propertyExists(const QString &key) const
{
return d->propertyMap.contains(key);
}
bool FakeDevice::setProperty(const QString &key, const QVariant &value)
{
if (d->broken) {
return false;
}
Solid::GenericInterface::PropertyChange change_type = Solid::GenericInterface::PropertyModified;
if (!d->propertyMap.contains(key)) {
change_type = Solid::GenericInterface::PropertyAdded;
}
d->propertyMap[key] = value;
QMap<QString, int> change;
change[key] = change_type;
Q_EMIT d->propertyChanged(change);
return true;
}
bool FakeDevice::removeProperty(const QString &key)
{
if (d->broken || !d->propertyMap.contains(key)) {
return false;
}
d->propertyMap.remove(key);
QMap<QString, int> change;
change[key] = Solid::GenericInterface::PropertyRemoved;
Q_EMIT d->propertyChanged(change);
return true;
}
void FakeDevice::setBroken(bool broken)
{
d->broken = broken;
}
bool FakeDevice::isBroken()
{
return d->broken;
}
bool FakeDevice::lock(const QString &reason)
{
if (d->broken || d->locked) {
return false;
}
d->locked = true;
d->lockReason = reason;
return true;
}
bool FakeDevice::unlock()
{
if (d->broken || !d->locked) {
return false;
}
d->locked = false;
d->lockReason.clear();
return true;
}
bool FakeDevice::isLocked() const
{
return d->locked;
}
QString FakeDevice::lockReason() const
{
return d->lockReason;
}
void FakeDevice::raiseCondition(const QString &condition, const QString &reason)
{
Q_EMIT d->conditionRaised(condition, reason);
}
bool FakeDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const
{
return d->interfaceList.contains(Solid::DeviceInterface::typeToString(type));
}
QObject *FakeDevice::createDeviceInterface(const Solid::DeviceInterface::Type &type)
{
// Do not try to cast with a unsupported device interface.
if (!queryDeviceInterface(type)) {
return nullptr;
}
FakeDeviceInterface *iface = nullptr;
switch (type) {
case Solid::DeviceInterface::GenericInterface:
iface = new FakeGenericInterface(this);
break;
case Solid::DeviceInterface::Processor:
iface = new FakeProcessor(this);
break;
case Solid::DeviceInterface::Block:
iface = new FakeBlock(this);
break;
case Solid::DeviceInterface::StorageDrive:
iface = new FakeStorage(this);
break;
case Solid::DeviceInterface::OpticalDrive:
iface = new FakeCdrom(this);
break;
case Solid::DeviceInterface::StorageVolume:
iface = new FakeVolume(this);
break;
case Solid::DeviceInterface::OpticalDisc:
iface = new FakeOpticalDisc(this);
break;
case Solid::DeviceInterface::StorageAccess:
iface = new FakeStorageAccess(this);
break;
case Solid::DeviceInterface::Camera:
iface = new FakeCamera(this);
break;
case Solid::DeviceInterface::PortableMediaPlayer:
iface = new FakePortableMediaPlayer(this);
break;
case Solid::DeviceInterface::Battery:
iface = new FakeBattery(this);
break;
case Solid::DeviceInterface::NetworkShare:
iface = new FakeNetworkShare(this);
break;
case Solid::DeviceInterface::Unknown:
break;
case Solid::DeviceInterface::Last:
break;
}
#ifdef HAVE_DBUS
if (iface) {
QDBusConnection::sessionBus().registerObject(d->udi + QLatin1Char('/') + Solid::DeviceInterface::typeToString(type),
iface,
QDBusConnection::ExportNonScriptableSlots);
}
#endif
return iface;
}
#include "moc_fakedevice.cpp"
#include "moc_fakedevice_p.cpp"
@@ -0,0 +1,68 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEDEVICE_H
#define SOLID_BACKENDS_FAKEHW_FAKEDEVICE_H
#include <solid/devices/ifaces/device.h>
#include <QMap>
#include <QSharedPointer>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeDevice : public Solid::Ifaces::Device
{
Q_OBJECT
public:
FakeDevice(const QString &udi, const QMap<QString, QVariant> &propertyMap);
FakeDevice(const FakeDevice &dev);
~FakeDevice() override;
public Q_SLOTS:
QString udi() const override;
QString parentUdi() const override;
QString vendor() const override;
QString product() const override;
QString icon() const override;
QStringList emblems() const override;
QString description() const override;
virtual QVariant property(const QString &key) const;
virtual QMap<QString, QVariant> allProperties() const;
virtual bool propertyExists(const QString &key) const;
virtual bool setProperty(const QString &key, const QVariant &value);
virtual bool removeProperty(const QString &key);
virtual bool lock(const QString &reason);
virtual bool unlock();
virtual bool isLocked() const;
virtual QString lockReason() const;
void setBroken(bool broken);
bool isBroken();
void raiseCondition(const QString &condition, const QString &reason);
public:
bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const override;
QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) override;
Q_SIGNALS:
void propertyChanged(const QMap<QString, int> &changes);
void conditionRaised(const QString &condition, const QString &reason);
private:
class Private;
QSharedPointer<Private> d;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEDEVICE_H
@@ -0,0 +1,44 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEDEVICE_P_H
#define SOLID_BACKENDS_FAKEHW_FAKEDEVICE_P_H
#include <QMap>
#include <QObject>
#include <QString>
#include <QVariant>
#include "fakedevice.h"
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeDevice;
class FakeDevice::Private : public QObject
{
Q_OBJECT
public:
QString udi;
QMap<QString, QVariant> propertyMap;
QStringList interfaceList;
bool locked;
QString lockReason;
bool broken;
Q_SIGNALS:
void propertyChanged(const QMap<QString, int> &changes);
void conditionRaised(const QString &condition, const QString &reason);
friend class FakeDevice;
};
}
}
}
#endif
@@ -0,0 +1,20 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakedeviceinterface.h"
using namespace Solid::Backends::Fake;
FakeDeviceInterface::FakeDeviceInterface(FakeDevice *device)
: QObject(device)
, m_device(device)
{
}
FakeDeviceInterface::~FakeDeviceInterface()
{
}
#include "moc_fakedeviceinterface.cpp"
@@ -0,0 +1,45 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEDEVICEINTERFACE_H
#define SOLID_BACKENDS_FAKEHW_FAKEDEVICEINTERFACE_H
#include <QObject>
#include <solid/devices/ifaces/deviceinterface.h>
#include "fakedevice.h"
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeDeviceInterface : public QObject, virtual public Solid::Ifaces::DeviceInterface
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::DeviceInterface)
public:
explicit FakeDeviceInterface(FakeDevice *device);
~FakeDeviceInterface() override;
protected:
FakeDevice *fakeDevice() const
{
return m_device;
}
FakeDevice *fakeDevice()
{
return m_device;
}
private:
FakeDevice *m_device;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEDEVICEINTERFACE_H
@@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakegenericinterface.h"
using namespace Solid::Backends::Fake;
FakeGenericInterface::FakeGenericInterface(FakeDevice *device)
: FakeDeviceInterface(device)
{
connect(device, SIGNAL(propertyChanged(QMap<QString, int>)), this, SIGNAL(propertyChanged(QMap<QString, int>)));
connect(device, SIGNAL(conditionRaised(QString, QString)), this, SIGNAL(conditionRaised(QString, QString)));
}
FakeGenericInterface::~FakeGenericInterface()
{
}
QVariant FakeGenericInterface::property(const QString &key) const
{
return fakeDevice()->property(key);
}
QMap<QString, QVariant> FakeGenericInterface::allProperties() const
{
return fakeDevice()->allProperties();
}
bool FakeGenericInterface::propertyExists(const QString &key) const
{
return fakeDevice()->propertyExists(key);
}
#include "moc_fakegenericinterface.cpp"
@@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEGENERICINTERFACE_H
#define SOLID_BACKENDS_FAKEHW_FAKEGENERICINTERFACE_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/genericinterface.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeGenericInterface : public FakeDeviceInterface, public Solid::Ifaces::GenericInterface
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::GenericInterface)
public:
explicit FakeGenericInterface(FakeDevice *device);
~FakeGenericInterface() override;
QVariant property(const QString &key) const override;
QMap<QString, QVariant> allProperties() const override;
bool propertyExists(const QString &key) const override;
Q_SIGNALS:
void propertyChanged(const QMap<QString, int> &changes) override;
void conditionRaised(const QString &condition, const QString &reason) override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEGENERICINTERFACE_H
@@ -0,0 +1,241 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakemanager.h"
#include "fakedevice.h"
// Qt includes
#include <QDebug>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QFile>
#include <QString>
#ifdef HAVE_DBUS
#include <QDBusConnection>
#endif
using namespace Solid::Backends::Fake;
class FakeManager::Private
{
public:
QMap<QString, FakeDevice *> loadedDevices;
QMap<QString, QMap<QString, QVariant>> hiddenDevices;
QString xmlFile;
QSet<Solid::DeviceInterface::Type> supportedInterfaces;
};
FakeManager::FakeManager(QObject *parent, const QString &xmlFile)
: Solid::Ifaces::DeviceManager(parent)
, d(new Private)
{
QString machineXmlFile = xmlFile;
d->xmlFile = machineXmlFile;
#ifdef HAVE_DBUS
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/solid/fakehw"), this, QDBusConnection::ExportNonScriptableSlots);
#endif
parseMachineFile();
// clang-format off
d->supportedInterfaces << Solid::DeviceInterface::GenericInterface
<< Solid::DeviceInterface::Processor
<< Solid::DeviceInterface::Block
<< Solid::DeviceInterface::StorageAccess
<< Solid::DeviceInterface::StorageDrive
<< Solid::DeviceInterface::OpticalDrive
<< Solid::DeviceInterface::StorageVolume
<< Solid::DeviceInterface::OpticalDisc
<< Solid::DeviceInterface::Camera
<< Solid::DeviceInterface::PortableMediaPlayer
<< Solid::DeviceInterface::Battery
<< Solid::DeviceInterface::NetworkShare;
// clang-format on
}
FakeManager::~FakeManager()
{
#ifdef HAVE_DBUS
QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/solid/fakehw"), QDBusConnection::UnregisterTree);
#endif
qDeleteAll(d->loadedDevices);
delete d;
}
QString FakeManager::udiPrefix() const
{
return QStringLiteral("/org/kde/solid/fakehw");
}
QSet<Solid::DeviceInterface::Type> FakeManager::supportedInterfaces() const
{
return d->supportedInterfaces;
}
QStringList FakeManager::allDevices()
{
QStringList deviceUdiList;
for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
deviceUdiList.append(device->udi());
}
return deviceUdiList;
}
QStringList FakeManager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type)
{
if (!parentUdi.isEmpty()) {
QStringList found = findDeviceStringMatch(QStringLiteral("parent"), parentUdi);
if (type == Solid::DeviceInterface::Unknown) {
return found;
}
QStringList result;
QStringList::ConstIterator it = found.constBegin();
QStringList::ConstIterator end = found.constEnd();
for (; it != end; ++it) {
FakeDevice *device = d->loadedDevices[*it];
if (device->queryDeviceInterface(type)) {
result << *it;
}
}
return result;
} else if (type != Solid::DeviceInterface::Unknown) {
return findDeviceByDeviceInterface(type);
} else {
return allDevices();
}
}
QObject *FakeManager::createDevice(const QString &udi)
{
if (d->loadedDevices.contains(udi)) {
return new FakeDevice(*d->loadedDevices[udi]);
}
return nullptr;
}
FakeDevice *FakeManager::findDevice(const QString &udi)
{
return d->loadedDevices.value(udi);
}
QStringList FakeManager::findDeviceStringMatch(const QString &key, const QString &value)
{
QStringList result;
for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
if (device->property(key).toString() == value) {
result.append(device->udi());
}
}
return result;
}
QStringList FakeManager::findDeviceByDeviceInterface(Solid::DeviceInterface::Type type)
{
QStringList result;
for (const FakeDevice *device : std::as_const(d->loadedDevices)) {
if (device->queryDeviceInterface(type)) {
result.append(device->udi());
}
}
return result;
}
void FakeManager::plug(const QString &udi)
{
if (d->hiddenDevices.contains(udi)) {
QMap<QString, QVariant> properties = d->hiddenDevices.take(udi);
d->loadedDevices[udi] = new FakeDevice(udi, properties);
Q_EMIT deviceAdded(udi);
}
}
void FakeManager::unplug(const QString &udi)
{
if (d->loadedDevices.contains(udi)) {
FakeDevice *dev = d->loadedDevices.take(udi);
d->hiddenDevices[udi] = dev->allProperties();
Q_EMIT deviceRemoved(udi);
delete dev;
}
}
void FakeManager::parseMachineFile()
{
QFile machineFile(d->xmlFile);
if (!machineFile.open(QIODevice::ReadOnly)) {
qWarning() << Q_FUNC_INFO << "Error while opening " << d->xmlFile;
return;
}
QDomDocument fakeDocument;
if (!fakeDocument.setContent(&machineFile)) {
qWarning() << Q_FUNC_INFO << "Error while creating the QDomDocument.";
machineFile.close();
return;
}
machineFile.close();
qDebug() << Q_FUNC_INFO << "Parsing fake computer XML: " << d->xmlFile;
QDomElement mainElement = fakeDocument.documentElement();
QDomNode node = mainElement.firstChild();
while (!node.isNull()) {
QDomElement tempElement = node.toElement();
if (!tempElement.isNull() && tempElement.tagName() == QLatin1String("device")) {
FakeDevice *tempDevice = parseDeviceElement(tempElement);
if (tempDevice) {
Q_ASSERT(!d->loadedDevices.contains(tempDevice->udi()));
d->loadedDevices.insert(tempDevice->udi(), tempDevice);
Q_EMIT deviceAdded(tempDevice->udi());
}
}
node = node.nextSibling();
}
}
FakeDevice *FakeManager::parseDeviceElement(const QDomElement &deviceElement)
{
FakeDevice *device = nullptr;
QMap<QString, QVariant> propertyMap;
QString udi = deviceElement.attribute(QStringLiteral("udi"));
QDomNode propertyNode = deviceElement.firstChild();
while (!propertyNode.isNull()) {
QDomElement propertyElement = propertyNode.toElement();
if (!propertyElement.isNull() && propertyElement.tagName() == QLatin1String("property")) {
QString propertyKey;
QVariant propertyValue;
propertyKey = propertyElement.attribute(QStringLiteral("key"));
propertyValue = QVariant(propertyElement.text());
propertyMap.insert(propertyKey, propertyValue);
}
propertyNode = propertyNode.nextSibling();
}
if (!propertyMap.isEmpty()) {
device = new FakeDevice(udi, propertyMap);
}
return device;
}
#include "moc_fakemanager.cpp"
@@ -0,0 +1,77 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEMANAGER_H
#define SOLID_BACKENDS_FAKEHW_FAKEMANAGER_H
#include <solid/devices/ifaces/devicemanager.h>
class QDomElement;
using namespace Solid::Ifaces;
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeDevice;
/**
* @brief a Fake manager that read a device list from a XML file.
* This fake manager is used for unit tests and developers.
*
* @author Michaël Larouche <michael.larouche@kdemail.net>
*/
class FakeManager : public Solid::Ifaces::DeviceManager
{
Q_OBJECT
public:
FakeManager(QObject *parent, const QString &xmlFile);
~FakeManager() override;
QString udiPrefix() const override;
QSet<Solid::DeviceInterface::Type> supportedInterfaces() const override;
/**
* Return the list of UDI of all available devices.
*/
QStringList allDevices() override;
QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type) override;
QObject *createDevice(const QString &udi) override;
virtual FakeDevice *findDevice(const QString &udi);
public Q_SLOTS:
void plug(const QString &udi);
void unplug(const QString &udi);
private Q_SLOTS:
/**
* @internal
* Parse the XML file that represent the fake machine.
*/
void parseMachineFile();
/**
* @internal
* Parse a device node and the return the device.
*/
FakeDevice *parseDeviceElement(const QDomElement &element);
private:
QStringList findDeviceStringMatch(const QString &key, const QString &value);
QStringList findDeviceByDeviceInterface(Solid::DeviceInterface::Type type);
class Private;
Private *d;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEMANAGER_H
@@ -0,0 +1,41 @@
/*
SPDX-FileCopyrightText: 2011 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakenetworkshare.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeNetworkShare::FakeNetworkShare(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakeNetworkShare::~FakeNetworkShare()
{
}
Solid::NetworkShare::ShareType FakeNetworkShare::type() const
{
QString type = fakeDevice()->property(QStringLiteral("type")).toString();
if (type == QLatin1String("nfs")) {
return Solid::NetworkShare::Nfs;
} else if (type == QLatin1String("cifs")) {
return Solid::NetworkShare::Cifs;
} else if (type == QLatin1String("smb3")) {
return Solid::NetworkShare::Smb3;
} else {
return Solid::NetworkShare::Unknown;
}
}
QUrl FakeNetworkShare::url() const
{
QString url = fakeDevice()->property(QStringLiteral("url")).toString();
return QUrl(url);
}
#include "moc_fakenetworkshare.cpp"
@@ -0,0 +1,38 @@
/*
SPDX-FileCopyrightText: 2011 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKE_NETWORKSHARE_H
#define SOLID_BACKENDS_FAKE_NETWORKSHARE_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/networkshare.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeNetworkShare : public FakeDeviceInterface, public Solid::Ifaces::NetworkShare
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::NetworkShare)
public:
explicit FakeNetworkShare(FakeDevice *device);
~FakeNetworkShare() override;
Solid::NetworkShare::ShareType type() const override;
QUrl url() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKE_NETWORKSHARE_H
@@ -0,0 +1,107 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakeopticaldisc.h"
#include <QStringList>
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeOpticalDisc::FakeOpticalDisc(FakeDevice *device)
: FakeVolume(device)
{
}
FakeOpticalDisc::~FakeOpticalDisc()
{
}
Solid::OpticalDisc::ContentTypes FakeOpticalDisc::availableContent() const
{
Solid::OpticalDisc::ContentTypes content;
const QMap<QString, Solid::OpticalDisc::ContentType> map = {
{QStringLiteral("audio"), Solid::OpticalDisc::Audio},
{QStringLiteral("data"), Solid::OpticalDisc::Data},
{QStringLiteral("vcd"), Solid::OpticalDisc::VideoCd},
{QStringLiteral("svcd"), Solid::OpticalDisc::SuperVideoCd},
{QStringLiteral("videodvd"), Solid::OpticalDisc::VideoDvd},
};
const QStringList content_typelist = fakeDevice()->property(QStringLiteral("availableContent")).toString().split(QLatin1Char(','));
for (const QString &type : content_typelist) {
content |= map.value(type, Solid::OpticalDisc::NoContent);
}
return content;
}
Solid::OpticalDisc::DiscType FakeOpticalDisc::discType() const
{
QString type = fakeDevice()->property(QStringLiteral("discType")).toString();
if (type == QLatin1String("cd_rom")) {
return Solid::OpticalDisc::CdRom;
} else if (type == QLatin1String("cd_r")) {
return Solid::OpticalDisc::CdRecordable;
} else if (type == QLatin1String("cd_rw")) {
return Solid::OpticalDisc::CdRewritable;
} else if (type == QLatin1String("dvd_rom")) {
return Solid::OpticalDisc::DvdRom;
} else if (type == QLatin1String("dvd_ram")) {
return Solid::OpticalDisc::DvdRam;
} else if (type == QLatin1String("dvd_r")) {
return Solid::OpticalDisc::DvdRecordable;
} else if (type == QLatin1String("dvd_rw")) {
return Solid::OpticalDisc::DvdRewritable;
} else if (type == QLatin1String("dvd_plus_r")) {
return Solid::OpticalDisc::DvdPlusRecordable;
} else if (type == QLatin1String("dvd_plus_rw")) {
return Solid::OpticalDisc::DvdPlusRewritable;
} else if (type == QLatin1String("dvd_plus_r_dl")) {
return Solid::OpticalDisc::DvdPlusRecordableDuallayer;
} else if (type == QLatin1String("dvd_plus_rw_dl")) {
return Solid::OpticalDisc::DvdPlusRewritableDuallayer;
} else if (type == QLatin1String("bd_rom")) {
return Solid::OpticalDisc::BluRayRom;
} else if (type == QLatin1String("bd_r")) {
return Solid::OpticalDisc::BluRayRecordable;
} else if (type == QLatin1String("bd_re")) {
return Solid::OpticalDisc::BluRayRewritable;
} else if (type == QLatin1String("hddvd_rom")) {
return Solid::OpticalDisc::HdDvdRom;
} else if (type == QLatin1String("hddvd_r")) {
return Solid::OpticalDisc::HdDvdRecordable;
} else if (type == QLatin1String("hddvd_rw")) {
return Solid::OpticalDisc::HdDvdRewritable;
} else {
return Solid::OpticalDisc::UnknownDiscType;
}
}
bool FakeOpticalDisc::isAppendable() const
{
return fakeDevice()->property(QStringLiteral("isAppendable")).toBool();
}
bool FakeOpticalDisc::isBlank() const
{
return fakeDevice()->property(QStringLiteral("isBlank")).toBool();
}
bool FakeOpticalDisc::isRewritable() const
{
return fakeDevice()->property(QStringLiteral("isRewritable")).toBool();
}
qulonglong FakeOpticalDisc::capacity() const
{
return fakeDevice()->property(QStringLiteral("capacity")).toULongLong();
}
#include "moc_fakeopticaldisc.cpp"
@@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEOPTICALDISC_H
#define SOLID_BACKENDS_FAKEHW_FAKEOPTICALDISC_H
#include "fakevolume.h"
#include <solid/devices/ifaces/opticaldisc.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeOpticalDisc : public FakeVolume, virtual public Solid::Ifaces::OpticalDisc
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::OpticalDisc)
public:
explicit FakeOpticalDisc(FakeDevice *device);
~FakeOpticalDisc() override;
public Q_SLOTS:
Solid::OpticalDisc::ContentTypes availableContent() const override;
Solid::OpticalDisc::DiscType discType() const override;
bool isAppendable() const override;
bool isBlank() const override;
bool isRewritable() const override;
qulonglong capacity() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEOPTICALDISC_H
@@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-FileCopyrightText: 2007 Jeff Mitchell <kde-dev@emailgoeshere.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakeportablemediaplayer.h"
#include <QStringList>
using namespace Solid::Backends::Fake;
FakePortableMediaPlayer::FakePortableMediaPlayer(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakePortableMediaPlayer::~FakePortableMediaPlayer()
{
}
QStringList FakePortableMediaPlayer::supportedProtocols() const
{
return fakeDevice()->property(QStringLiteral("supportedProtocols")).toString().simplified().split(QLatin1Char(','));
}
QStringList FakePortableMediaPlayer::supportedDrivers(QString protocol) const
{
Q_UNUSED(protocol);
return fakeDevice()->property(QStringLiteral("supportedDrivers")).toString().simplified().split(QLatin1Char(','));
}
QVariant Solid::Backends::Fake::FakePortableMediaPlayer::driverHandle(const QString &driver) const
{
Q_UNUSED(driver);
return QVariant();
}
#include "moc_fakeportablemediaplayer.cpp"
@@ -0,0 +1,38 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-FileCopyrightText: 2007 Jeff Mitchell <kde-dev@emailgoeshere.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEPORTABLEMEDIAPLAYER_H
#define SOLID_BACKENDS_FAKEHW_FAKEPORTABLEMEDIAPLAYER_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/portablemediaplayer.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakePortableMediaPlayer : public FakeDeviceInterface, virtual public Solid::Ifaces::PortableMediaPlayer
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::PortableMediaPlayer)
public:
explicit FakePortableMediaPlayer(FakeDevice *device);
~FakePortableMediaPlayer() override;
public Q_SLOTS:
QStringList supportedProtocols() const override;
QStringList supportedDrivers(QString protocol) const override;
QVariant driverHandle(const QString &driver) const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEPORTABLEMEDIAPLAYER_H
@@ -0,0 +1,64 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakeprocessor.h"
#include <QStringList>
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeProcessor::FakeProcessor(FakeDevice *device)
: FakeDeviceInterface(device)
{
}
FakeProcessor::~FakeProcessor()
{
}
int FakeProcessor::number() const
{
return fakeDevice()->property(QStringLiteral("number")).toInt();
}
int FakeProcessor::maxSpeed() const
{
return fakeDevice()->property(QStringLiteral("maxSpeed")).toInt();
}
bool FakeProcessor::canChangeFrequency() const
{
return fakeDevice()->property(QStringLiteral("canChangeFrequency")).toBool();
}
Solid::Processor::InstructionSets FakeProcessor::instructionSets() const
{
Solid::Processor::InstructionSets result;
const QStringList extension_list = fakeDevice()->property(QStringLiteral("instructionSets")).toString().split(QLatin1Char(','));
for (const QString &extension_str : extension_list) {
if (extension_str == QLatin1String("mmx")) {
result |= Solid::Processor::IntelMmx;
} else if (extension_str == QLatin1String("sse")) {
result |= Solid::Processor::IntelSse;
} else if (extension_str == QLatin1String("sse2")) {
result |= Solid::Processor::IntelSse2;
} else if (extension_str == QLatin1String("sse3")) {
result |= Solid::Processor::IntelSse3;
} else if (extension_str == QLatin1String("sse4")) {
result |= Solid::Processor::IntelSse4;
} else if (extension_str == QLatin1String("3dnow")) {
result |= Solid::Processor::Amd3DNow;
} else if (extension_str == QLatin1String("altivec")) {
result |= Solid::Processor::AltiVec;
}
}
return result;
}
#include "moc_fakeprocessor.cpp"
@@ -0,0 +1,38 @@
/*
SPDX-FileCopyrightText: 2006 Michaël Larouche <michael.larouche@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEPROCESSOR_H
#define SOLID_BACKENDS_FAKEHW_FAKEPROCESSOR_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/processor.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeProcessor : public FakeDeviceInterface, public Solid::Ifaces::Processor
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Processor)
public:
explicit FakeProcessor(FakeDevice *device);
~FakeProcessor() override;
public Q_SLOTS:
int number() const override;
int maxSpeed() const override;
bool canChangeFrequency() const override;
Solid::Processor::InstructionSets instructionSets() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEPROCESSOR_H
@@ -0,0 +1,90 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakestorage.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeStorage::FakeStorage(FakeDevice *device)
: FakeBlock(device)
{
}
FakeStorage::~FakeStorage()
{
}
Solid::StorageDrive::Bus FakeStorage::bus() const
{
QString bus = fakeDevice()->property(QStringLiteral("bus")).toString();
if (bus == QLatin1String("ide")) {
return Solid::StorageDrive::Ide;
} else if (bus == QLatin1String("usb")) {
return Solid::StorageDrive::Usb;
} else if (bus == QLatin1String("ieee1394")) {
return Solid::StorageDrive::Ieee1394;
} else if (bus == QLatin1String("scsi")) {
return Solid::StorageDrive::Scsi;
} else if (bus == QLatin1String("sata")) {
return Solid::StorageDrive::Sata;
} else {
return Solid::StorageDrive::Platform;
}
}
Solid::StorageDrive::DriveType FakeStorage::driveType() const
{
QString type = fakeDevice()->property(QStringLiteral("major")).toString();
if (type == QLatin1String("disk")) {
return Solid::StorageDrive::HardDisk;
} else if (type == QLatin1String("cdrom")) {
return Solid::StorageDrive::CdromDrive;
} else if (type == QLatin1String("floppy")) {
return Solid::StorageDrive::Floppy;
} else if (type == QLatin1String("tape")) {
return Solid::StorageDrive::Tape;
} else if (type == QLatin1String("compact_flash")) {
return Solid::StorageDrive::CompactFlash;
} else if (type == QLatin1String("memory_stick")) {
return Solid::StorageDrive::MemoryStick;
} else if (type == QLatin1String("smart_media")) {
return Solid::StorageDrive::SmartMedia;
} else if (type == QLatin1String("sd_mmc")) {
return Solid::StorageDrive::SdMmc;
} else {
return Solid::StorageDrive::HardDisk;
}
}
bool FakeStorage::isRemovable() const
{
return fakeDevice()->property(QStringLiteral("isRemovable")).toBool();
}
bool FakeStorage::isHotpluggable() const
{
return fakeDevice()->property(QStringLiteral("isHotpluggable")).toBool();
}
qulonglong FakeStorage::size() const
{
return fakeDevice()->property(QStringLiteral("size")).toULongLong();
}
QDateTime FakeStorage::timeDetected() const
{
return fakeDevice()->property(QStringLiteral("timeDetected")).toDateTime();
}
QDateTime FakeStorage::timeMediaDetected() const
{
return fakeDevice()->property(QStringLiteral("timeMediaDetected")).toDateTime();
}
#include "moc_fakestorage.cpp"
@@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKESTORAGE_H
#define SOLID_BACKENDS_FAKEHW_FAKESTORAGE_H
#include "fakeblock.h"
#include <solid/devices/ifaces/storagedrive.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeStorage : public FakeBlock, virtual public Solid::Ifaces::StorageDrive
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageDrive)
public:
explicit FakeStorage(FakeDevice *device);
~FakeStorage() override;
public Q_SLOTS:
Solid::StorageDrive::Bus bus() const override;
Solid::StorageDrive::DriveType driveType() const override;
bool isRemovable() const override;
bool isHotpluggable() const override;
qulonglong size() const override;
QDateTime timeDetected() const override;
QDateTime timeMediaDetected() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKESTORAGE_H
@@ -0,0 +1,70 @@
/*
SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakestorageaccess.h"
using namespace Solid::Backends::Fake;
FakeStorageAccess::FakeStorageAccess(FakeDevice *device)
: FakeDeviceInterface(device)
{
connect(device, SIGNAL(propertyChanged(QMap<QString, int>)), this, SLOT(onPropertyChanged(QMap<QString, int>)));
}
FakeStorageAccess::~FakeStorageAccess()
{
}
bool FakeStorageAccess::isAccessible() const
{
return fakeDevice()->property(QStringLiteral("isMounted")).toBool();
}
QString FakeStorageAccess::filePath() const
{
return fakeDevice()->property(QStringLiteral("mountPoint")).toString();
}
bool FakeStorageAccess::isIgnored() const
{
return fakeDevice()->property(QStringLiteral("isIgnored")).toBool();
}
bool FakeStorageAccess::isEncrypted() const
{
return fakeDevice()->property(QStringLiteral("isEncrypted")).toBool();
}
bool FakeStorageAccess::setup()
{
if (fakeDevice()->isBroken() || isAccessible()) {
return false;
} else {
fakeDevice()->setProperty(QStringLiteral("isMounted"), true);
return true;
}
}
bool FakeStorageAccess::teardown()
{
if (fakeDevice()->isBroken() || !isAccessible()) {
return false;
} else {
fakeDevice()->setProperty(QStringLiteral("isMounted"), false);
return true;
}
}
void Solid::Backends::Fake::FakeStorageAccess::onPropertyChanged(const QMap<QString, int> &changes)
{
for (auto it = changes.cbegin(); it != changes.cend(); ++it) {
if (it.key() == QLatin1String(QLatin1String("isMounted"))) {
Q_EMIT accessibilityChanged(fakeDevice()->property(QStringLiteral("isMounted")).toBool(), fakeDevice()->udi());
}
}
}
#include "moc_fakestorageaccess.cpp"
@@ -0,0 +1,50 @@
/*
SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKESTORAGEACCESS_H
#define SOLID_BACKENDS_FAKEHW_FAKESTORAGEACCESS_H
#include "fakedeviceinterface.h"
#include <solid/devices/ifaces/storageaccess.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeStorageAccess : public FakeDeviceInterface, virtual public Solid::Ifaces::StorageAccess
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageAccess)
public:
FakeStorageAccess(FakeDevice *device);
~FakeStorageAccess() override;
bool isAccessible() const override;
QString filePath() const override;
bool isIgnored() const override;
bool isEncrypted() const override;
public Q_SLOTS:
bool setup() override;
bool teardown() override;
Q_SIGNALS:
void accessibilityChanged(bool accessible, const QString &udi) override;
void setupDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
void teardownDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
void setupRequested(const QString &udi) override;
void teardownRequested(const QString &udi) override;
private Q_SLOTS:
void onPropertyChanged(const QMap<QString, int> &changes);
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKESTORAGEACCESS_H
@@ -0,0 +1,70 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fakevolume.h"
#include <QVariant>
using namespace Solid::Backends::Fake;
FakeVolume::FakeVolume(FakeDevice *device)
: FakeBlock(device)
{
}
FakeVolume::~FakeVolume()
{
}
bool FakeVolume::isIgnored() const
{
return fakeDevice()->property(QStringLiteral("isIgnored")).toBool();
}
Solid::StorageVolume::UsageType FakeVolume::usage() const
{
QString usage = fakeDevice()->property(QStringLiteral("usage")).toString();
if (usage == QLatin1String("filesystem")) {
return Solid::StorageVolume::FileSystem;
} else if (usage == QLatin1String("partitiontable")) {
return Solid::StorageVolume::PartitionTable;
} else if (usage == QLatin1String("raid")) {
return Solid::StorageVolume::Raid;
} else if (usage == QLatin1String("unused")) {
return Solid::StorageVolume::Unused;
} else if (usage == QLatin1String("encrypted")) {
return Solid::StorageVolume::Encrypted;
} else {
return Solid::StorageVolume::Other;
}
}
QString FakeVolume::fsType() const
{
return fakeDevice()->property(QStringLiteral("fsType")).toString();
}
QString FakeVolume::label() const
{
return fakeDevice()->property(QStringLiteral("label")).toString();
}
QString FakeVolume::uuid() const
{
return fakeDevice()->property(QStringLiteral("uuid")).toString();
}
qulonglong FakeVolume::size() const
{
return fakeDevice()->property(QStringLiteral("size")).toULongLong();
}
QString Solid::Backends::Fake::FakeVolume::encryptedContainerUdi() const
{
return QString();
}
#include "moc_fakevolume.cpp"
@@ -0,0 +1,41 @@
/*
SPDX-FileCopyrightText: 2006 Davide Bettio <davide.bettio@kdemail.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FAKEHW_FAKEVOLUME_H
#define SOLID_BACKENDS_FAKEHW_FAKEVOLUME_H
#include "fakeblock.h"
#include <solid/devices/ifaces/storagevolume.h>
namespace Solid
{
namespace Backends
{
namespace Fake
{
class FakeVolume : public FakeBlock, virtual public Solid::Ifaces::StorageVolume
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageVolume)
public:
explicit FakeVolume(FakeDevice *device);
~FakeVolume() override;
public Q_SLOTS:
bool isIgnored() const override;
Solid::StorageVolume::UsageType usage() const override;
QString fsType() const override;
QString label() const override;
QString uuid() const override;
qulonglong size() const override;
QString encryptedContainerUdi() const override;
};
}
}
}
#endif // SOLID_BACKENDS_FAKEHW_FAKEVOLUME_H
@@ -0,0 +1,18 @@
set(backend_sources
fstabmanager.cpp
fstabdevice.cpp
fstabnetworkshare.cpp
fstabstorageaccess.cpp
fstabhandling.cpp
fstabwatcher.cpp
)
ecm_qt_declare_logging_category(backend_sources
HEADER fstab_debug.h
IDENTIFIER Solid::Backends::Fstab::FSTAB_LOG
DEFAULT_SEVERITY Warning
CATEGORY_NAME kf.solid.backends.fstab
OLD_CATEGORY_NAMES org.kde.solid.fstab
DESCRIPTION "Fstab (Solid)"
EXPORT SOLID
)
@@ -0,0 +1,188 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabdevice.h"
#include "fstab_debug.h"
#include "fstabhandling.h"
#include "fstabnetworkshare.h"
#include "fstabservice.h"
#include <QCoreApplication>
#include <QDir>
#include <QUrl>
using namespace Solid::Backends::Fstab;
FstabDevice::FstabDevice(QString uid)
: Solid::Ifaces::Device()
, m_uid(uid)
{
m_device = m_uid.mid(parentUdi().length() + 1);
const QString &fstype = FstabHandling::fstype(m_device);
qCDebug(FSTAB_LOG) << "Adding " << m_device << "type:" << fstype;
if (m_device.startsWith(QLatin1String("//"))) {
m_vendor = m_device.mid(2, m_device.indexOf(QLatin1String("/"), 2) - 2);
m_product = m_device.mid(m_device.indexOf(QLatin1String("/"), 2) + 1);
m_storageType = StorageType::NetworkShare;
} else if (fstype.startsWith(QLatin1String("nfs"))) {
m_vendor = m_device.left(m_device.indexOf(QLatin1String(":/")));
m_product = m_device.mid(m_device.indexOf(QLatin1String(":/")) + 1);
m_storageType = StorageType::NetworkShare;
} else if (fstype.startsWith(QLatin1String("fuse.")) || fstype == QLatin1String("overlay")) {
m_vendor = fstype;
m_product = m_device.mid(m_device.indexOf(fstype) + fstype.length());
QString home = QDir::homePath();
if (m_product.startsWith(home)) {
m_product = QStringLiteral("~") + m_product.mid(home.length());
}
if ((fstype == QLatin1String("fuse.encfs")) || (fstype == QLatin1String("fuse.cryfs")) || (fstype == QLatin1String("fuse.gocryptfs"))) {
m_storageType = StorageType::Encrypted;
} else if (fstype == QLatin1String("fuse.sshfs") || fstype == QLatin1String("fuse.rclone")) {
m_storageType = StorageType::NetworkShare;
}
}
const auto &options = FstabHandling::options(m_device);
const auto gvfsName = options.value(QLatin1String("x-gvfs-name"));
if (!gvfsName.isEmpty()) {
m_displayName = QUrl::fromPercentEncoding(gvfsName.toUtf8());
}
const auto gvfsIcon = options.value(QLatin1String("x-gvfs-icon"));
if (!gvfsIcon.isEmpty()) {
m_iconName = QUrl::fromPercentEncoding(gvfsIcon.toUtf8());
}
if (m_storageType == StorageType::NetworkShare) {
m_description = QCoreApplication::translate("", "%1 on %2", "%1 is sharename, %2 is servername").arg(m_product, m_vendor);
} else {
m_description = QCoreApplication::translate("", "%1 (%2)", "%1 is mountpoint, %2 is fs type").arg(m_product, m_vendor);
}
if (m_displayName.isEmpty()) {
const QStringList currentMountPoints = FstabHandling::currentMountPoints(m_device);
if (currentMountPoints.isEmpty()) {
const QStringList mountPoints = FstabHandling::mountPoints(m_device);
m_displayName = mountPoints.isEmpty() ? m_description : mountPoints.first();
} else {
m_displayName = currentMountPoints.first();
}
}
if (m_iconName.isEmpty()) {
if (m_storageType == StorageType::NetworkShare) {
m_iconName = QStringLiteral("network-server");
} else if (m_storageType == StorageType::Encrypted) {
m_iconName = QStringLiteral("folder-decrypted");
} else {
const QStringList &mountPoints = FstabHandling::mountPoints(m_device);
const QString home = QDir::homePath();
if (mountPoints.contains(QLatin1String("/"))) {
m_iconName = QStringLiteral("drive-harddisk-root");
} else if (mountPoints.contains(home)) {
m_iconName = QStringLiteral("user-home");
} else {
m_iconName = QStringLiteral("folder");
}
}
}
}
FstabDevice::~FstabDevice()
{
}
QString FstabDevice::udi() const
{
return m_uid;
}
QString FstabDevice::parentUdi() const
{
return QString::fromLatin1(FSTAB_UDI_PREFIX);
}
QString FstabDevice::vendor() const
{
return m_vendor;
}
QString FstabDevice::product() const
{
return m_product;
}
QString FstabDevice::icon() const
{
return m_iconName;
}
QStringList FstabDevice::emblems() const
{
if (!m_storageAccess) {
FstabDevice *d = const_cast<FstabDevice *>(this);
d->m_storageAccess = new FstabStorageAccess(d);
}
if (m_storageAccess->isAccessible()) {
return {QStringLiteral("emblem-mounted")};
} else {
return {QStringLiteral("emblem-unmounted")};
}
}
QString FstabDevice::displayName() const
{
return m_displayName;
}
QString FstabDevice::description() const
{
return m_description;
}
bool FstabDevice::isEncrypted() const
{
return m_storageType == FstabDevice::StorageType::Encrypted;
}
bool FstabDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &interfaceType) const
{
if (interfaceType == Solid::DeviceInterface::StorageAccess) {
return true;
}
if ((m_storageType == StorageType::NetworkShare) && (interfaceType == Solid::DeviceInterface::NetworkShare)) {
return true;
}
return false;
}
QObject *FstabDevice::createDeviceInterface(const Solid::DeviceInterface::Type &interfaceType)
{
if (interfaceType == Solid::DeviceInterface::StorageAccess) {
if (!m_storageAccess) {
m_storageAccess = new FstabStorageAccess(this);
}
return m_storageAccess;
} else if ((m_storageType == StorageType::NetworkShare) && (interfaceType == Solid::DeviceInterface::NetworkShare)) {
return new FstabNetworkShare(this);
}
return nullptr;
}
QString FstabDevice::device() const
{
return m_device;
}
void FstabDevice::onMtabChanged(const QString &device)
{
if (m_device == device) {
Q_EMIT mtabChanged(device);
}
}
#include "moc_fstabdevice.cpp"
@@ -0,0 +1,80 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_FSTAB_DEVICE_H
#define SOLID_BACKENDS_FSTAB_FSTAB_DEVICE_H
#include "fstabstorageaccess.h"
#include <QPointer>
#include <QString>
#include <solid/devices/ifaces/device.h>
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class FstabDevice : public Solid::Ifaces::Device
{
Q_OBJECT
public:
FstabDevice(QString uid);
~FstabDevice() override;
QString udi() const override;
QString parentUdi() const override;
QString vendor() const override;
QString product() const override;
QString icon() const override;
QStringList emblems() const override;
QString displayName() const override;
QString description() const override;
bool isEncrypted() const;
bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const override;
QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) override;
QString device() const;
Q_SIGNALS:
void mtabChanged(const QString &device);
public Q_SLOTS:
void onMtabChanged(const QString &device);
private:
QString m_uid;
QString m_device;
QString m_product;
QString m_vendor;
QString m_displayName;
QString m_description;
QString m_iconName;
QPointer<FstabStorageAccess> m_storageAccess;
enum class StorageType : uint8_t {
Other = 0,
NetworkShare,
Encrypted,
};
StorageType m_storageType = StorageType::Other;
};
}
}
}
#endif // SOLID_BACKENDS_FSTAB_FSTAB_DEVICE_H
@@ -0,0 +1,397 @@
/*
SPDX-FileCopyrightText: 2006-2010 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabhandling.h"
#include "fstab_debug.h"
#include <QFile>
#include <QObject>
#include <QProcess>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QTextStream>
#include <QThreadStorage>
#include <solid/devices/soliddefs_p.h>
#include <solid/config-solid.h>
#include <stdlib.h>
#if HAVE_LIBMOUNT
#include <libmount.h>
#endif
// This is the *BSD branch
#if HAVE_SYS_MOUNT_H
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <sys/mount.h>
#endif
#define FSTAB "/etc/fstab"
// There are currently two APIs implemented:
// libmount for linux
// getmntinfo + struct statfs&flags (BSD 4.4 and friends)
Q_GLOBAL_STATIC(QThreadStorage<Solid::Backends::Fstab::FstabHandling>, globalFstabCache)
Solid::Backends::Fstab::FstabHandling::FstabHandling()
: m_fstabCacheValid(false)
, m_mtabCacheValid(false)
{
}
bool _k_isFstabNetworkFileSystem(const QString &fstype, const QString &devName)
{
if (fstype == QLatin1String("nfs") //
|| fstype == QLatin1String("nfs4") //
|| fstype == QLatin1String("smbfs") //
|| fstype == QLatin1String("cifs") //
|| fstype == QLatin1String("smb3") //
|| fstype == QLatin1String("fuse.sshfs") //
|| fstype == QLatin1String("fuse.rclone") //
|| devName.startsWith(QLatin1String("//"))) {
return true;
}
return false;
}
bool _k_isFstabSupportedLocalFileSystem(const QString &fstype)
{
if (fstype == QLatin1String("fuse.encfs") //
|| fstype == QLatin1String("fuse.cryfs") //
|| fstype == QLatin1String("fuse.gocryptfs") //
|| fstype == QLatin1String("overlay")) {
return true;
}
return false;
}
QString _k_mntFstype(const QString &orig)
{
if (orig == QLatin1String("sshfs") || orig == QLatin1String("rclone")) {
return QStringLiteral("fuse.%1").arg(orig);
}
return orig;
}
QString _k_deviceNameForMountpoint(const QString &source, const QString &fstype, const QString &mountpoint)
{
if (fstype.startsWith(QLatin1String("fuse.")) || fstype == QLatin1String("overlay")) {
return fstype + mountpoint;
}
// A source may be mounted several times, e.g. with different
// options, often a network share with different credentials
// for different users. Make sure it is unique by appending the
// mountpoint (which is unique).
auto _mountpoint = mountpoint;
if (fstype == QLatin1String("nfs") || fstype == QLatin1String("nfs4")) {
if (!mountpoint.startsWith(QLatin1Char('/'))) {
// making sure mount point starts with /
_mountpoint.prepend(QLatin1Char('/'));
}
}
return source + QLatin1Char(':') + _mountpoint;
}
void Solid::Backends::Fstab::FstabHandling::_k_updateFstabMountPointsCache()
{
if (globalFstabCache->localData().m_fstabCacheValid) {
return;
}
globalFstabCache->localData().m_fstabCache.clear();
globalFstabCache->localData().m_fstabOptionsCache.clear();
#if HAVE_LIBMOUNT
struct libmnt_table *table = mnt_new_table();
if (!table) {
return;
}
if (mnt_table_parse_fstab(table, NULL) != 0) {
mnt_free_table(table);
return;
}
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
struct libmnt_fs *fs;
while (mnt_table_next_fs(table, itr, &fs) == 0) {
const QString fstype = _k_mntFstype(QFile::decodeName(mnt_fs_get_fstype(fs)));
const QString fsname = QFile::decodeName(mnt_fs_get_srcpath(fs));
if (_k_isFstabNetworkFileSystem(fstype, fsname) || _k_isFstabSupportedLocalFileSystem(fstype)) {
const QString mountpoint = QFile::decodeName(mnt_fs_get_target(fs));
const QString device = _k_deviceNameForMountpoint(fsname, fstype, mountpoint);
char *name = mnt_fs_strdup_options(fs);
const QStringList options = QFile::decodeName(name).split(QLatin1Char(','));
free(name);
globalFstabCache->localData().m_fstabCache.insert(device, mountpoint);
globalFstabCache->localData().m_fstabFstypeCache.insert(device, fstype);
for (const auto &optionLine : options) {
const auto split = optionLine.split(QLatin1Char('='));
const auto optionName = split[0];
const auto optionValue = split.size() > 1 ? split[1] : QString{};
globalFstabCache->localData().m_fstabOptionsCache[device].insert(optionName, optionValue);
}
}
}
mnt_free_iter(itr);
mnt_free_table(table);
#else
QFile fstab(QStringLiteral(FSTAB));
if (!fstab.open(QIODevice::ReadOnly)) {
return;
}
QTextStream stream(&fstab);
QString line;
while (!stream.atEnd()) {
line = stream.readLine().simplified();
if (line.isEmpty() || line.startsWith(QLatin1Char('#'))) {
continue;
}
// not empty or commented out by '#'
const QStringList items = line.split(QLatin1Char(' '));
if (items.count() < 4) {
continue;
}
const QString device = items.at(0);
const QString fstype = _k_mntFstype(items.at(2));
// prevent accessing a blocking directory
if (_k_isFstabNetworkFileSystem(fstype, device) || _k_isFstabSupportedLocalFileSystem(fstype)) {
QString mountpoint = items.at(1);
if (fstype == QLatin1String("nfs") || fstype == QLatin1String("nfs4")) {
if (!mountpoint.startsWith(QLatin1Char('/'))) {
// making sure mount point starts with /
mountpoint.prepend(QLatin1Char('/'));
}
}
globalFstabCache->localData().m_fstabCache.insert(device, mountpoint);
}
}
fstab.close();
#endif
globalFstabCache->localData().m_fstabCacheValid = true;
}
QStringList Solid::Backends::Fstab::FstabHandling::deviceList()
{
_k_updateFstabMountPointsCache();
_k_updateMtabMountPointsCache();
QStringList devices = globalFstabCache->localData().m_mtabCache.keys();
// Ensure that regardless an fstab device ends with a slash
// it will match its eventual mounted device regardless whether or not its path
// ends with a slash
for (auto it = globalFstabCache->localData().m_fstabCache.constBegin(), end = globalFstabCache->localData().m_fstabCache.constEnd(); it != end; ++it) {
auto device = it.key();
// the device is already known
if (devices.contains(device)) {
continue;
}
// deviceName will or won't end with / depending if device ended with one
QString deviceName = device;
if (deviceName.endsWith(QLatin1Char('/'))) {
deviceName.chop(1);
} else {
deviceName.append(QLatin1Char('/'));
}
if (!devices.contains(deviceName)) {
devices.append(device);
}
}
return devices;
}
QStringList Solid::Backends::Fstab::FstabHandling::mountPoints(const QString &device)
{
_k_updateFstabMountPointsCache();
_k_updateMtabMountPointsCache();
QStringList mountpoints = globalFstabCache->localData().m_fstabCache.values(device);
mountpoints += globalFstabCache->localData().m_mtabCache.values(device);
mountpoints.removeDuplicates();
return mountpoints;
}
QHash<QString, QString> Solid::Backends::Fstab::FstabHandling::options(const QString &device)
{
_k_updateFstabMountPointsCache();
_k_updateMtabMountPointsCache();
auto options = globalFstabCache->localData().m_mtabOptionsCache.value(device);
const auto optionsFstab = globalFstabCache->localData().m_fstabOptionsCache.value(device);
for (const auto &it : optionsFstab.asKeyValueRange()) {
if (!options.contains(it.first)) {
options.insert(it.first, it.second);
}
}
return options;
}
QString Solid::Backends::Fstab::FstabHandling::fstype(const QString &device)
{
_k_updateFstabMountPointsCache();
return globalFstabCache->localData().m_fstabFstypeCache.value(device);
}
bool Solid::Backends::Fstab::FstabHandling::callSystemCommand(const QString &commandName,
const QStringList &args,
const QObject *receiver,
std::function<void(QProcess *)> callback)
{
static const QStringList searchPaths{QStringLiteral("/sbin"), QStringLiteral("/bin"), QStringLiteral("/usr/sbin"), QStringLiteral("/usr/bin")};
static const QString joinedPaths = searchPaths.join(QLatin1Char(':'));
const QString exec = QStandardPaths::findExecutable(commandName, searchPaths);
if (exec.isEmpty()) {
qCWarning(FSTAB_LOG) << "Couldn't find executable" << commandName << "in" << joinedPaths;
return false;
}
QProcess *process = new QProcess();
QObject::connect(process,
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
receiver,
[process, callback](int exitCode, QProcess::ExitStatus exitStatus) {
Q_UNUSED(exitCode);
Q_UNUSED(exitStatus);
callback(process);
process->deleteLater();
});
static const QRegularExpression re(QStringLiteral("^PATH=.*"), QRegularExpression::CaseInsensitiveOption);
QStringList env = QProcess::systemEnvironment();
env.replaceInStrings(re, QLatin1String("PATH=") + joinedPaths);
process->setEnvironment(env);
process->start(exec, args);
if (process->waitForStarted()) {
return true;
}
delete process;
return false;
}
void Solid::Backends::Fstab::FstabHandling::_k_updateMtabMountPointsCache()
{
if (globalFstabCache->localData().m_mtabCacheValid) {
return;
}
globalFstabCache->localData().m_mtabCache.clear();
globalFstabCache->localData().m_mtabOptionsCache.clear();
#if HAVE_GETMNTINFO
#if GETMNTINFO_USES_STATVFS
struct statvfs *mounted;
#else
struct statfs *mounted;
#endif
int num_fs = getmntinfo(&mounted, MNT_NOWAIT);
for (int i = 0; i < num_fs; i++) {
QString type = _k_mntFstype(QFile::decodeName(mounted[i].f_fstypename));
if (_k_isFstabNetworkFileSystem(type, QString()) || _k_isFstabSupportedLocalFileSystem(type)) {
const QString fsname = QFile::decodeName(mounted[i].f_mntfromname);
const QString mountpoint = QFile::decodeName(mounted[i].f_mntonname);
const QString device = _k_deviceNameForMountpoint(fsname, type, mountpoint);
globalFstabCache->localData().m_mtabCache.insert(device, mountpoint);
globalFstabCache->localData().m_fstabFstypeCache.insert(device, type);
}
}
#elif HAVE_LIBMOUNT
struct libmnt_table *table = mnt_new_table();
if (!table) {
return;
}
if (mnt_table_parse_mtab(table, NULL) != 0) {
mnt_free_table(table);
return;
}
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
struct libmnt_fs *fs;
while (mnt_table_next_fs(table, itr, &fs) == 0) {
const QString fstype = _k_mntFstype(QFile::decodeName(mnt_fs_get_fstype(fs)));
if (_k_isFstabNetworkFileSystem(fstype, QString{}) || _k_isFstabSupportedLocalFileSystem(fstype)) {
const QString mountpoint = QFile::decodeName(mnt_fs_get_target(fs));
const QString fsname = QFile::decodeName(mnt_fs_get_srcpath(fs));
const QString device = _k_deviceNameForMountpoint(fsname, fstype, mountpoint);
char *name = mnt_fs_strdup_options(fs);
const QStringList options = QFile::decodeName(name).split(QLatin1Char(','));
free(name);
globalFstabCache->localData().m_mtabCache.insert(device, mountpoint);
globalFstabCache->localData().m_fstabFstypeCache.insert(device, fstype);
for (const auto &optionLine : options) {
const auto split = optionLine.split(QLatin1Char('='));
const auto optionName = split[0];
const auto optionValue = split.size() > 1 ? split[1] : QString{};
globalFstabCache->localData().m_mtabOptionsCache[device].insert(optionName, optionValue);
}
}
}
mnt_free_iter(itr);
mnt_free_table(table);
#endif
globalFstabCache->localData().m_mtabCacheValid = true;
}
QStringList Solid::Backends::Fstab::FstabHandling::currentMountPoints(const QString &device)
{
_k_updateMtabMountPointsCache();
return globalFstabCache->localData().m_mtabCache.values(device);
}
void Solid::Backends::Fstab::FstabHandling::flushMtabCache()
{
globalFstabCache->localData().m_mtabCacheValid = false;
}
void Solid::Backends::Fstab::FstabHandling::flushFstabCache()
{
globalFstabCache->localData().m_fstabCacheValid = false;
}
@@ -0,0 +1,58 @@
/*
SPDX-FileCopyrightText: 2006-2010 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_FSTABHANDLING_H
#define SOLID_BACKENDS_FSTAB_FSTABHANDLING_H
#include <QMultiHash>
#include <QString>
#include <functional>
class QProcess;
class QObject;
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class FstabHandling
{
public:
FstabHandling();
static QStringList deviceList();
static QStringList currentMountPoints(const QString &device);
static QStringList mountPoints(const QString &device);
static QHash<QString, QString> options(const QString &device);
static QString fstype(const QString &device);
static bool callSystemCommand(const QString &commandName, const QStringList &args, const QObject *recvr, std::function<void(QProcess *)> callback);
static void flushMtabCache();
static void flushFstabCache();
private:
static void _k_updateMtabMountPointsCache();
static void _k_updateFstabMountPointsCache();
typedef QMultiHash<QString, QString> QStringMultiHash;
QStringMultiHash m_mtabCache;
QStringMultiHash m_fstabCache;
QHash<QString, QHash<QString, QString>> m_fstabOptionsCache;
QHash<QString, QHash<QString, QString>> m_mtabOptionsCache;
QHash<QString, QString> m_fstabFstypeCache;
bool m_fstabCacheValid;
bool m_mtabCacheValid;
};
}
}
}
#endif
@@ -0,0 +1,144 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabmanager.h"
#include "../shared/rootdevice.h"
#include "fstab_debug.h"
#include "fstabdevice.h"
#include "fstabhandling.h"
#include "fstabservice.h"
#include "fstabwatcher.h"
using namespace Solid::Backends::Fstab;
using namespace Solid::Backends::Shared;
FstabManager::FstabManager(QObject *parent)
: Solid::Ifaces::DeviceManager(parent)
, m_deviceList(FstabHandling::deviceList())
{
m_supportedInterfaces << Solid::DeviceInterface::StorageAccess;
m_supportedInterfaces << Solid::DeviceInterface::NetworkShare;
connect(FstabWatcher::instance(), &FstabWatcher::fstabChanged, this, &FstabManager::onFstabChanged);
connect(FstabWatcher::instance(), &FstabWatcher::mtabChanged, this, &FstabManager::onMtabChanged);
}
QString FstabManager::udiPrefix() const
{
return QStringLiteral(FSTAB_UDI_PREFIX);
}
QSet<Solid::DeviceInterface::Type> FstabManager::supportedInterfaces() const
{
return m_supportedInterfaces;
}
QStringList FstabManager::allDevices()
{
QStringList result;
result << udiPrefix();
for (const QString &device : std::as_const(m_deviceList)) {
result << udiPrefix() + QStringLiteral("/") + device;
}
return result;
}
QStringList FstabManager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type)
{
if ((parentUdi == udiPrefix()) || parentUdi.isEmpty()) {
QStringList result;
if (type == Solid::DeviceInterface::StorageAccess) {
for (const QString &device : std::as_const(m_deviceList)) {
result << udiPrefix() + QStringLiteral("/") + device;
}
return result;
} else if (type == Solid::DeviceInterface::NetworkShare) {
for (const QString &device : std::as_const(m_deviceList)) {
result << udiPrefix() + QStringLiteral("/") + device;
}
return result;
}
} else {
if (type == Solid::DeviceInterface::StorageAccess || type == Solid::DeviceInterface::NetworkShare) {
return QStringList{parentUdi};
}
}
return QStringList();
}
QObject *FstabManager::createDevice(const QString &udi)
{
if (udi == udiPrefix()) {
RootDevice *root = new RootDevice(udi);
root->setProduct(tr("Filesystem Volumes"));
root->setDescription(tr("Mountable filesystems declared in your system"));
root->setIcon(QStringLiteral("folder"));
return root;
} else {
// global device manager makes sure udi starts with udi prefix + '/'
QString internalName = udi.mid(udiPrefix().length() + 1, -1);
if (!m_deviceList.contains(internalName)) {
return nullptr;
}
FstabDevice *device = new FstabDevice(udi);
connect(this, &FstabManager::mtabChanged, device, &FstabDevice::onMtabChanged);
return device;
}
}
void FstabManager::onFstabChanged()
{
FstabHandling::flushFstabCache();
_k_updateDeviceList();
}
void FstabManager::_k_updateDeviceList()
{
const QStringList deviceList = FstabHandling::deviceList();
const QSet<QString> newlist(deviceList.begin(), deviceList.end());
const QSet<QString> oldlist(m_deviceList.begin(), m_deviceList.end());
m_deviceList = deviceList;
qCDebug(FSTAB_LOG) << oldlist << "->" << newlist;
for (const QString &device : newlist) {
if (!oldlist.contains(device)) {
Q_EMIT deviceAdded(udiPrefix() + QStringLiteral("/") + device);
}
}
for (const QString &device : oldlist) {
if (!newlist.contains(device)) {
Q_EMIT deviceRemoved(udiPrefix() + QStringLiteral("/") + device);
}
}
}
void FstabManager::onMtabChanged()
{
FstabHandling::flushMtabCache();
_k_updateDeviceList(); // devicelist is union of mtab and fstab
for (const QString &device : std::as_const(m_deviceList)) {
// notify storageaccess objects via device ...
Q_EMIT mtabChanged(device);
}
}
FstabManager::~FstabManager()
{
}
#include "moc_fstabmanager.cpp"
@@ -0,0 +1,54 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_FSTABMANAGER_H
#define SOLID_BACKENDS_FSTAB_FSTABMANAGER_H
#include <QSet>
#include <QStringList>
#include <solid/deviceinterface.h>
#include <solid/devices/ifaces/devicemanager.h>
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class AbstractDeviceFactory;
class FstabManager : public Solid::Ifaces::DeviceManager
{
Q_OBJECT
public:
explicit FstabManager(QObject *parent);
~FstabManager() override;
QString udiPrefix() const override;
QSet<Solid::DeviceInterface::Type> supportedInterfaces() const override;
QStringList allDevices() override;
QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type) override;
QObject *createDevice(const QString &udi) override;
Q_SIGNALS:
void mtabChanged(const QString &device);
private Q_SLOTS:
void onFstabChanged();
void onMtabChanged();
private:
QSet<Solid::DeviceInterface::Type> m_supportedInterfaces;
QStringList m_deviceList;
void _k_updateDeviceList();
};
}
}
}
#endif
@@ -0,0 +1,54 @@
/*
SPDX-FileCopyrightText: 2011 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabnetworkshare.h"
#include "fstabhandling.h"
#include <solid/devices/backends/fstab/fstabdevice.h>
using namespace Solid::Backends::Fstab;
FstabNetworkShare::FstabNetworkShare(Solid::Backends::Fstab::FstabDevice *device)
: QObject(device)
, m_fstabDevice(device)
{
QString url;
if (m_fstabDevice->device().startsWith(QLatin1String("//"))) {
QString fsType = FstabHandling::fstype(m_fstabDevice->device());
if (fsType == QLatin1String("cifs")) {
m_type = Solid::NetworkShare::Cifs;
} else if (fsType == QLatin1String("smb3")) {
m_type = Solid::NetworkShare::Smb3;
}
url = QStringLiteral("smb:%1").arg(m_fstabDevice->device());
} else if (m_fstabDevice->device().contains(QLatin1String(":/"))) {
m_type = Solid::NetworkShare::Nfs;
url = QStringLiteral("nfs://%1/%2").arg(m_fstabDevice->vendor(), m_fstabDevice->product());
} else {
m_type = Solid::NetworkShare::Unknown;
}
m_url = QUrl(url);
}
FstabNetworkShare::~FstabNetworkShare()
{
}
Solid::NetworkShare::ShareType FstabNetworkShare::type() const
{
return m_type;
}
QUrl FstabNetworkShare::url() const
{
return m_url;
}
const Solid::Backends::Fstab::FstabDevice *FstabNetworkShare::fstabDevice() const
{
return m_fstabDevice;
}
#include "moc_fstabnetworkshare.cpp"
@@ -0,0 +1,48 @@
/*
SPDX-FileCopyrightText: 2011 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_NETWORKSHARE_H
#define SOLID_BACKENDS_FSTAB_NETWORKSHARE_H
#include <solid/devices/ifaces/networkshare.h>
#include <QObject>
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class FstabDevice;
class FstabNetworkShare : public QObject, public Solid::Ifaces::NetworkShare
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::NetworkShare)
public:
explicit FstabNetworkShare(Solid::Backends::Fstab::FstabDevice *device);
~FstabNetworkShare() override;
Solid::NetworkShare::ShareType type() const override;
QUrl url() const override;
public:
const Solid::Backends::Fstab::FstabDevice *fstabDevice() const;
private:
Solid::Backends::Fstab::FstabDevice *m_fstabDevice;
Solid::NetworkShare::ShareType m_type;
QUrl m_url;
};
}
}
}
#endif // SOLID_BACKENDS_FSTAB_NETWORKSHARE_H
@@ -0,0 +1,13 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_SERVICE_H
#define SOLID_BACKENDS_FSTAB_SERVICE_H
/* FStab */
#define FSTAB_UDI_PREFIX "/org/kde/fstab"
#endif // SOLID_BACKENDS_FSTAB_H
@@ -0,0 +1,166 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabstorageaccess.h"
#include "fstabwatcher.h"
#include <QStringList>
#include <solid/devices/backends/fstab/fstabdevice.h>
#include <solid/devices/backends/fstab/fstabhandling.h>
#include <solid/devices/backends/fstab/fstabservice.h>
#include <QDir>
#include <QProcess>
#include <QTimer>
#include <errno.h>
using namespace Solid::Backends::Fstab;
FstabStorageAccess::FstabStorageAccess(Solid::Backends::Fstab::FstabDevice *device)
: QObject(device)
, m_fstabDevice(device)
{
QStringList currentMountPoints = FstabHandling::currentMountPoints(device->device());
if (currentMountPoints.isEmpty()) {
QStringList mountPoints = FstabHandling::mountPoints(device->device());
m_filePath = mountPoints.isEmpty() ? QString() : mountPoints.first();
m_isAccessible = false;
} else {
m_filePath = currentMountPoints.first();
m_isAccessible = true;
}
const bool inUserPath =
m_filePath.startsWith(QLatin1String("/media/")) || m_filePath.startsWith(QLatin1String("/run/media/")) || m_filePath.startsWith(QDir::homePath());
const bool gvfsHidden = FstabHandling::options(device->device()).contains(QLatin1String("x-gvfs-hide"));
const bool fsIsOverlay = FstabHandling::fstype(device->device()) == QLatin1String("overlay");
m_isIgnored = gvfsHidden ||
// ignore overlay fs not pointing to / or seemingly mounted by user
(fsIsOverlay && m_filePath != QLatin1String("/") && !inUserPath);
connect(device, &FstabDevice::mtabChanged, this, &FstabStorageAccess::onMtabChanged);
QTimer::singleShot(0, this, SLOT(connectDBusSignals()));
}
FstabStorageAccess::~FstabStorageAccess()
{
}
void FstabStorageAccess::connectDBusSignals()
{
m_fstabDevice->registerAction(QStringLiteral("setup"), this, SLOT(slotSetupRequested()), SLOT(slotSetupDone(int, QString)));
m_fstabDevice->registerAction(QStringLiteral("teardown"), this, SLOT(slotTeardownRequested()), SLOT(slotTeardownDone(int, QString)));
}
const Solid::Backends::Fstab::FstabDevice *FstabStorageAccess::fstabDevice() const
{
return m_fstabDevice;
}
bool FstabStorageAccess::isAccessible() const
{
return m_isAccessible;
}
QString FstabStorageAccess::filePath() const
{
return m_filePath;
}
bool FstabStorageAccess::isIgnored() const
{
return m_isIgnored;
}
bool FstabStorageAccess::isEncrypted() const
{
return m_fstabDevice->isEncrypted();
}
bool FstabStorageAccess::setup()
{
if (filePath().isEmpty()) {
return false;
}
m_fstabDevice->broadcastActionRequested(QStringLiteral("setup"));
return FstabHandling::callSystemCommand(QStringLiteral("mount"), {filePath()}, this, [this](QProcess *process) {
if (process->exitCode() == 0) {
m_fstabDevice->broadcastActionDone(QStringLiteral("setup"), Solid::NoError, QString());
} else {
m_fstabDevice->broadcastActionDone(QStringLiteral("setup"),
Solid::UnauthorizedOperation,
QString::fromUtf8(process->readAllStandardError().trimmed()));
}
});
}
void FstabStorageAccess::slotSetupRequested()
{
Q_EMIT setupRequested(m_fstabDevice->udi());
}
bool FstabStorageAccess::teardown()
{
if (filePath().isEmpty()) {
return false;
}
m_fstabDevice->broadcastActionRequested(QStringLiteral("teardown"));
return FstabHandling::callSystemCommand(QStringLiteral("umount"), {filePath()}, this, [this](QProcess *process) {
if (process->exitCode() == 0) {
m_fstabDevice->broadcastActionDone(QStringLiteral("teardown"), Solid::NoError);
} else if (process->exitCode() == EBUSY) {
m_fstabDevice->broadcastActionDone(QStringLiteral("teardown"), Solid::DeviceBusy);
} else if (process->exitCode() == EPERM) {
m_fstabDevice->broadcastActionDone(QStringLiteral("teardown"),
Solid::UnauthorizedOperation,
QString::fromUtf8(process->readAllStandardError().trimmed()));
} else {
m_fstabDevice->broadcastActionDone(QStringLiteral("teardown"),
Solid::OperationFailed,
QString::fromUtf8(process->readAllStandardError().trimmed()));
}
});
}
void FstabStorageAccess::slotTeardownRequested()
{
Q_EMIT teardownRequested(m_fstabDevice->udi());
}
void FstabStorageAccess::slotSetupDone(int error, const QString &errorString)
{
Q_EMIT setupDone(static_cast<Solid::ErrorType>(error), errorString, m_fstabDevice->udi());
}
void FstabStorageAccess::slotTeardownDone(int error, const QString &errorString)
{
Q_EMIT teardownDone(static_cast<Solid::ErrorType>(error), errorString, m_fstabDevice->udi());
}
void FstabStorageAccess::onMtabChanged(const QString &device)
{
QStringList currentMountPoints = FstabHandling::currentMountPoints(device);
if (currentMountPoints.isEmpty()) {
// device umounted
m_filePath = FstabHandling::mountPoints(device).first();
if (m_isAccessible) {
m_isAccessible = false;
Q_EMIT accessibilityChanged(false, QStringLiteral(FSTAB_UDI_PREFIX "/%1").arg(device));
}
} else {
// device added
m_filePath = currentMountPoints.first();
if (!m_isAccessible) {
m_isAccessible = true;
Q_EMIT accessibilityChanged(true, QStringLiteral(FSTAB_UDI_PREFIX "/%1").arg(device));
}
}
}
#include "moc_fstabstorageaccess.cpp"
@@ -0,0 +1,81 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_STORAGEACCESS_H
#define SOLID_BACKENDS_FSTAB_STORAGEACCESS_H
#include <solid/devices/ifaces/storageaccess.h>
#include <QObject>
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class FstabDevice;
class FstabStorageAccess : public QObject, public Solid::Ifaces::StorageAccess
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageAccess)
public:
explicit FstabStorageAccess(Solid::Backends::Fstab::FstabDevice *device);
~FstabStorageAccess() override;
bool isAccessible() const override;
QString filePath() const override;
bool isIgnored() const override;
bool isEncrypted() const override;
bool setup() override;
bool teardown() override;
public:
const Solid::Backends::Fstab::FstabDevice *fstabDevice() const;
Q_SIGNALS:
void accessibilityChanged(bool accessible, const QString &udi) override;
void setupDone(Solid::ErrorType error, QVariant data, const QString &udi) override;
void teardownDone(Solid::ErrorType error, QVariant data, const QString &udi) override;
void setupRequested(const QString &udi) override;
void teardownRequested(const QString &udi) override;
void repairRequested(const QString &udi) override;
void repairDone(Solid::ErrorType error, QVariant resultData, const QString &udi) override;
private Q_SLOTS:
void onMtabChanged(const QString &device);
void connectDBusSignals();
void slotSetupRequested();
void slotSetupDone(int error, const QString &errorString);
void slotTeardownRequested();
void slotTeardownDone(int error, const QString &errorString);
private:
Solid::Backends::Fstab::FstabDevice *m_fstabDevice;
QString m_filePath;
bool m_isAccessible;
bool m_isIgnored;
};
}
}
}
#endif // SOLID_BACKENDS_FSTAB_DEVICE_INTERFACE_H
@@ -0,0 +1,172 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "fstabwatcher.h"
#include "fstab_debug.h"
#include "soliddefs_p.h"
#include <QCoreApplication>
#include <QFile>
#include <QFileSystemWatcher>
#include <QSocketNotifier>
namespace Solid
{
namespace Backends
{
namespace Fstab
{
Q_GLOBAL_STATIC(FstabWatcher, globalFstabWatcher)
static const QString s_mtabFile = QStringLiteral("/etc/mtab");
static const QString s_fstabFile = QStringLiteral("/etc/fstab");
static const QString s_fstabPath = QStringLiteral("/etc");
FstabWatcher::FstabWatcher()
{
#ifdef Q_OS_LINUX
auto mountMonitor = mnt_new_monitor();
if (!mountMonitor) {
qCritical(FSTAB_LOG) << "could not start mount monitor";
return;
}
m_mountMonitor = mountMonitor;
auto r = mnt_monitor_enable_kernel(m_mountMonitor, true);
if (r < 0) {
mnt_unref_monitor(m_mountMonitor);
qCritical(FSTAB_LOG) << "Failed to enable watching of kernel mount events:" << strerror(errno);
}
r = mnt_monitor_enable_userspace(m_mountMonitor, true, NULL);
if (r < 0) {
mnt_unref_monitor(m_mountMonitor);
qCritical(FSTAB_LOG) << "Failed to enable watching of userspace mount events:" << strerror(errno);
}
auto fd = mnt_monitor_get_fd(m_mountMonitor);
if (fd < 0) {
mnt_unref_monitor(m_mountMonitor);
qCritical(FSTAB_LOG) << "Failed to acquire watch file descriptor" << strerror(errno);
return;
}
m_socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(m_socketNotifier, &QSocketNotifier::activated, this, &FstabWatcher::onMountChanged);
if (qApp) {
connect(qApp, &QCoreApplication::aboutToQuit, this, &FstabWatcher::onQuit);
}
#else
m_isRoutineInstalled = false;
m_fileSystemWatcher = new QFileSystemWatcher(this);
m_mtabFile = new QFile(s_mtabFile, this);
if (m_mtabFile && m_mtabFile->symLinkTarget().startsWith(QLatin1String("/proc/")) && m_mtabFile->open(QIODevice::ReadOnly)) {
m_socketNotifier = new QSocketNotifier(m_mtabFile->handle(), QSocketNotifier::Exception, this);
connect(m_socketNotifier, &QSocketNotifier::activated, this, &FstabWatcher::mtabChanged);
} else {
m_fileSystemWatcher->addPath(s_mtabFile);
}
m_fileSystemWatcher->addPath(s_fstabPath);
connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) {
if (!m_isFstabWatched) {
m_isFstabWatched = m_fileSystemWatcher->addPath(s_fstabFile);
if (m_isFstabWatched) {
qCDebug(FSTAB_LOG) << "Re-added" << s_fstabFile;
Q_EMIT onFileChanged(s_fstabFile);
}
}
});
m_isFstabWatched = m_fileSystemWatcher->addPath(s_fstabFile);
connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &FstabWatcher::onFileChanged);
#endif
}
FstabWatcher::~FstabWatcher()
{
#ifdef Q_OS_LINUX
mnt_unref_monitor(m_mountMonitor);
#else
// The QFileSystemWatcher doesn't work correctly in a singleton
// The solution so far was to destroy the QFileSystemWatcher when the application quits
// But we have some crash with this solution.
// For the moment to workaround the problem, we detach the QFileSystemWatcher from the parent
// effectively leaking it on purpose.
m_fileSystemWatcher->setParent(nullptr);
#endif
}
void FstabWatcher::onQuit()
{
#ifndef Q_OS_LINUX
m_fileSystemWatcher->setParent(nullptr);
#endif
}
FstabWatcher *FstabWatcher::instance()
{
#if 0
FstabWatcher *fstabWatcher = globalFstabWatcher;
if (fstabWatcher && !fstabWatcher->m_isRoutineInstalled) {
qAddPostRoutine(globalFstabWatcher.destroy);
fstabWatcher->m_isRoutineInstalled = true;
}
return fstabWatcher;
#else
return globalFstabWatcher;
#endif
}
#ifdef Q_OS_LINUX
void FstabWatcher::onMountChanged()
{
auto mtab = false;
auto fstab = false;
const char *filename;
while (mnt_monitor_next_change(m_mountMonitor, &filename, NULL) == 0) {
if (!mtab && ((strcmp(filename, "/proc/self/mountinfo") == 0) || (strcmp(filename, "/run/mount/utab") == 0))) {
mtab = true;
}
if (!fstab && (strcmp(filename, "/etc/fstab") == 0)) {
fstab = true;
}
}
if (mtab) {
Q_EMIT mtabChanged();
}
if (fstab) {
Q_EMIT fstabChanged();
}
}
#else
void FstabWatcher::onFileChanged(const QString &path)
{
if (path == s_mtabFile) {
Q_EMIT mtabChanged();
if (!m_fileSystemWatcher->files().contains(s_mtabFile)) {
m_fileSystemWatcher->addPath(s_mtabFile);
}
}
if (path == s_fstabFile) {
Q_EMIT fstabChanged();
if (!m_fileSystemWatcher->files().contains(s_fstabFile)) {
m_isFstabWatched = m_fileSystemWatcher->addPath(s_fstabFile);
qCDebug(FSTAB_LOG) << "Fstab removed, re-added:" << m_isFstabWatched;
}
}
}
#endif
}
}
} // namespace Solid:Backends::Fstab
#include "moc_fstabwatcher.cpp"
@@ -0,0 +1,61 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_FSTAB_WATCHER_H
#define SOLID_BACKENDS_FSTAB_WATCHER_H
#include <QObject>
#ifdef Q_OS_LINUX
#include <libmount.h>
#endif
class QFileSystemWatcher;
class QFile;
class QSocketNotifier;
namespace Solid
{
namespace Backends
{
namespace Fstab
{
class FstabWatcher : public QObject
{
Q_OBJECT
public:
FstabWatcher();
~FstabWatcher() override;
static FstabWatcher *instance();
Q_SIGNALS:
void mtabChanged();
void fstabChanged();
private Q_SLOTS:
#ifdef Q_OS_LINUX
void onMountChanged();
#else
void onFileChanged(const QString &path);
#endif
void onQuit();
private:
QSocketNotifier *m_socketNotifier;
#ifdef Q_OS_LINUX
libmnt_monitor *m_mountMonitor;
#else
bool m_isRoutineInstalled;
QFileSystemWatcher *m_fileSystemWatcher;
QFile *m_mtabFile;
bool m_isFstabWatched;
#endif
};
}
}
}
#endif // SOLID_BACKENDS_FSTAB_WATCHER_H
@@ -0,0 +1,17 @@
set(backend_sources
imobile.cpp
imobiledevice.cpp
imobilemanager.cpp
imobiledeviceinterface.cpp
imobileportablemediaplayer.cpp
)
set(backend_libs IMobileDevice::IMobileDevice PList::PList)
ecm_qt_declare_logging_category(backend_sources
HEADER imobile_debug.h
IDENTIFIER Solid::Backends::IMobile::IMOBILE
DEFAULT_SEVERITY Warning
CATEGORY_NAME kf.solid.backends.imobile
DESCRIPTION "IMobileDevice (Solid)"
EXPORT SOLID
)
@@ -0,0 +1,13 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "imobile.h"
QString Solid::Backends::IMobile::udiPrefix()
{
return QStringLiteral("/org/kde/solid/imobile");
}
@@ -0,0 +1,25 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IMOBILE_H
#define SOLID_BACKENDS_IMOBILE_H
#include <QString>
namespace Solid
{
namespace Backends
{
namespace IMobile
{
QString udiPrefix();
} // namespace IMobile
} // namespace Backends
} // namespace Solid
#endif // SOLID_BACKENDS_IMOBILE_H
@@ -0,0 +1,153 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "imobiledevice.h"
#include <QCoreApplication>
#include <QScopeGuard>
#include "imobile_debug.h"
#include "imobile.h"
#include "imobileportablemediaplayer.h"
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
using namespace Solid::Backends::IMobile;
IMobileDevice::IMobileDevice(const QString &udi)
: Solid::Ifaces::Device()
, m_udi(udi)
{
const QString deviceId = udi.mid(udiPrefix().length() + 1);
idevice_t device;
auto ret = idevice_new(&device, deviceId.toUtf8().constData());
if (ret != IDEVICE_E_SUCCESS) {
qCWarning(IMOBILE) << "Failed to create device instance for" << deviceId << ret;
return;
}
auto deviceCleanup = qScopeGuard([device] {
idevice_free(device);
});
lockdownd_client_t lockdowndClient = nullptr;
auto lockdownRet = lockdownd_client_new(device, &lockdowndClient, "kde_solid_imobile");
if (lockdownRet != LOCKDOWN_E_SUCCESS || !lockdowndClient) {
qCWarning(IMOBILE) << "Failed to create lockdownd client for" << deviceId;
return;
}
auto lockdowndClientCleanup = qScopeGuard([lockdowndClient] {
lockdownd_client_free(lockdowndClient);
});
char *name = nullptr;
lockdownRet = lockdownd_get_device_name(lockdowndClient, &name);
if (lockdownRet != LOCKDOWN_E_SUCCESS) {
qCWarning(IMOBILE) << "Failed to get device name for" << deviceId << lockdownRet;
} else if (name) {
m_name = QString::fromUtf8(name);
free(name);
}
plist_t deviceClassEntry = nullptr;
lockdownRet = lockdownd_get_value(lockdowndClient, nullptr /*global domain*/, "DeviceClass", &deviceClassEntry);
if (lockdownRet != LOCKDOWN_E_SUCCESS) {
qCWarning(IMOBILE) << "Failed to get device class for" << deviceId << lockdownRet;
} else {
char *deviceClass = nullptr;
plist_get_string_val(deviceClassEntry, &deviceClass);
if (deviceClass) {
m_deviceClass = QString::fromUtf8(deviceClass);
free(deviceClass);
}
}
}
IMobileDevice::~IMobileDevice()
{
}
QString IMobileDevice::udi() const
{
return m_udi;
}
QString IMobileDevice::parentUdi() const
{
return udiPrefix();
}
QString IMobileDevice::vendor() const
{
return QCoreApplication::translate("imobiledevice", "Apple", "Company name");
}
QString IMobileDevice::product() const
{
// TODO would be nice to use actual product names, e.g. "iPhone 5S"
// but accessing device type requires doing a handshake with the device,
// which will fail if locked or not paired, and also would require us
// to maintain a giant mapping table
return m_deviceClass;
}
QString IMobileDevice::icon() const
{
if (m_deviceClass.contains(QLatin1String("iPod"))) {
return QStringLiteral("multimedia-player-apple-ipod-touch");
} else if (m_deviceClass.contains(QLatin1String("iPad"))) {
return QStringLiteral("computer-apple-ipad");
} else {
return QStringLiteral("phone-apple-iphone");
}
}
QStringList IMobileDevice::emblems() const
{
return {};
}
QString IMobileDevice::description() const
{
return m_name;
}
bool IMobileDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const
{
switch (type) {
// TODO would be cool to support GenericInterface for reading
// arbitrary plist configuration, cf. what ideviceinfo tool does
case Solid::DeviceInterface::PortableMediaPlayer:
return true;
default:
return false;
}
}
QObject *IMobileDevice::createDeviceInterface(const Solid::DeviceInterface::Type &type)
{
if (!queryDeviceInterface(type)) {
return nullptr;
}
switch (type) {
case Solid::DeviceInterface::PortableMediaPlayer:
return new PortableMediaPlayer(this);
default:
Q_UNREACHABLE();
return nullptr;
}
}
#include "moc_imobiledevice.cpp"
@@ -0,0 +1,52 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IMOBILE_IMOBILEDEVICE_H
#define SOLID_BACKENDS_IMOBILE_IMOBILEDEVICE_H
#include <QStringList>
#include <solid/devices/ifaces/device.h>
namespace Solid
{
namespace Backends
{
namespace IMobile
{
class IMobileDevice : public Solid::Ifaces::Device
{
Q_OBJECT
public:
explicit IMobileDevice(const QString &udi);
~IMobileDevice() override;
QString udi() const override;
QString parentUdi() const override;
QString vendor() const override;
QString product() const override;
QString icon() const override;
QStringList emblems() const override;
QString description() const override;
bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const override;
QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) override;
private:
QString m_udi;
QString m_name;
QString m_deviceClass;
};
} // namespace IMobile
} // namespace Backends
} // namespace Solid
#endif // SOLID_BACKENDS_IMOBILE_IMOBILEDEVICE_H
@@ -0,0 +1,22 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "imobiledeviceinterface.h"
#include "imobiledevice.h"
using namespace Solid::Backends::IMobile;
DeviceInterface::DeviceInterface(IMobileDevice *device)
: QObject(device)
, m_device(device)
{
}
DeviceInterface::~DeviceInterface() = default;
#include "moc_imobiledeviceinterface.cpp"
@@ -0,0 +1,41 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IMOBILE_IMOBILEDEVICEINTERFACE_H
#define SOLID_BACKENDS_IMOBILE_IMOBILEDEVICEINTERFACE_H
#include <solid/devices/ifaces/deviceinterface.h>
//#include "udevdevice.h"
#include <QObject>
namespace Solid
{
namespace Backends
{
namespace IMobile
{
class IMobileDevice;
class DeviceInterface : public QObject, virtual public Solid::Ifaces::DeviceInterface
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::DeviceInterface)
public:
explicit DeviceInterface(IMobileDevice *device);
~DeviceInterface() override;
protected:
IMobileDevice *m_device;
};
}
}
}
#endif // SOLID_BACKENDS_IMOBILE_IMOBILEDEVICEINTERFACE_H
@@ -0,0 +1,181 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "imobilemanager.h"
#include <QFile>
#include <QFileSystemWatcher>
#include "imobile_debug.h"
#include "../shared/rootdevice.h"
#include "imobile.h"
#include "imobiledevice.h"
using namespace Solid::Backends::IMobile;
using namespace Solid::Backends::Shared;
using namespace Qt::StringLiterals;
namespace
{
constexpr auto VAR_RUN = "/var/run/"_L1;
constexpr auto MUXD_SOCKET = "/var/run/usbmuxd"_L1;
} // namespace
Manager::Manager(QObject *parent)
: Solid::Ifaces::DeviceManager(parent)
, m_watcher(new QFileSystemWatcher)
{
// Lazy initialize. If usbmuxd isn't running we don't need to do anything yet.
// This is in part to prevent libusbmuxd from setting up extra inotifies and polling when
// we know that it won't find anything yet. Works around a bunch of whoopsies.
// https://github.com/libimobiledevice/libusbmuxd/pull/133
// https://github.com/libimobiledevice/libusbmuxd/issues/135
connect(m_watcher.get(), &QFileSystemWatcher::directoryChanged, this, [this](const QString &) {
if (QFile::exists(MUXD_SOCKET)) {
spinUp();
}
});
m_watcher->addPath(VAR_RUN);
if (QFile::exists(MUXD_SOCKET)) {
spinUp();
}
}
Manager::~Manager()
{
if (m_spunUp) {
idevice_event_unsubscribe();
}
}
void Manager::spinUp()
{
if (m_spunUp) {
return;
}
m_spunUp = true;
// Handing over watching to libusbmuxd. Don't need our watcher anymore.
// Deleting later because this function gets called by a signal from m_watcher so we mustn't delete it just now.
m_watcher.release()->deleteLater();
auto ret = idevice_event_subscribe(
[](const idevice_event_t *event, void *user_data) {
// NOTE this is called from a different thread.
static_cast<Manager *>(user_data)->onDeviceEvent(event);
},
this);
if (ret != IDEVICE_E_SUCCESS) {
qCWarning(IMOBILE) << "Failed to subscribe to device events";
}
char **devices = nullptr;
int count = 0;
ret = idevice_get_device_list(&devices, &count);
if (ret != IDEVICE_E_SUCCESS && ret != IDEVICE_E_NO_DEVICE) {
qCWarning(IMOBILE) << "Failed to get list of iOS devices" << ret;
return;
}
m_deviceUdis.reserve(count);
for (int i = 0; i < count; ++i) {
m_deviceUdis.append(Solid::Backends::IMobile::udiPrefix() + QLatin1Char('/') + QString::fromLatin1(devices[i]));
}
if (devices) {
idevice_device_list_free(devices);
}
}
QObject *Manager::createDevice(const QString &udi)
{
if (udi == udiPrefix()) {
RootDevice *root = new RootDevice(udi);
root->setProduct(tr("iDevice"));
root->setDescription(tr("iOS devices"));
root->setIcon(QStringLiteral("phone-apple-iphone"));
return root;
}
if (m_deviceUdis.contains(udi)) {
return new IMobileDevice(udi);
}
return nullptr;
}
QStringList Manager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type)
{
QStringList devices;
if (!parentUdi.isEmpty() || type != Solid::DeviceInterface::Unknown) {
for (const QString &udi : m_deviceUdis) {
IMobileDevice device(udi);
if (!device.queryDeviceInterface(type)) {
continue;
}
if (!parentUdi.isEmpty() && device.parentUdi() != parentUdi) {
continue;
}
devices << udi;
}
}
return devices;
}
QStringList Manager::allDevices()
{
return m_deviceUdis;
}
QSet<Solid::DeviceInterface::Type> Manager::supportedInterfaces() const
{
return {Solid::DeviceInterface::PortableMediaPlayer};
}
QString Manager::udiPrefix() const
{
return Solid::Backends::IMobile::udiPrefix();
}
void Manager::onDeviceEvent(const idevice_event_t *event)
{
const QString udi = Solid::Backends::IMobile::udiPrefix() + QLatin1Char('/') + QString::fromLatin1(event->udid);
switch (event->event) {
case IDEVICE_DEVICE_ADD:
// Post it to the right thread.
QMetaObject::invokeMethod(this, [this, udi] {
if (!m_deviceUdis.contains(udi)) {
m_deviceUdis.append(udi);
Q_EMIT deviceAdded(udi);
}
});
return;
case IDEVICE_DEVICE_REMOVE:
QMetaObject::invokeMethod(this, [this, udi] {
if (m_deviceUdis.removeOne(udi)) {
Q_EMIT deviceRemoved(udi);
}
});
return;
#if IMOBILEDEVICE_API >= QT_VERSION_CHECK(1, 3, 0)
case IDEVICE_DEVICE_PAIRED:
return;
#endif
}
qCDebug(IMOBILE) << "Unhandled device event" << event->event << "for" << event->udid;
}
#include "moc_imobilemanager.cpp"
@@ -0,0 +1,51 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IMOBILE_IMOBILEMANAGER_H
#define SOLID_BACKENDS_IMOBILE_IMOBILEMANAGER_H
#include <solid/devices/ifaces/devicemanager.h>
#include <libimobiledevice/libimobiledevice.h>
class QFileSystemWatcher;
namespace Solid
{
namespace Backends
{
namespace IMobile
{
class Manager : public Solid::Ifaces::DeviceManager
{
Q_OBJECT
public:
explicit Manager(QObject *parent);
~Manager() override;
QObject *createDevice(const QString &udi) override;
QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type) override;
QStringList allDevices() override;
QSet<Solid::DeviceInterface::Type> supportedInterfaces() const override;
QString udiPrefix() const override;
void onDeviceEvent(const idevice_event_t *event);
private:
void spinUp();
bool m_spunUp = false;
QStringList m_deviceUdis;
std::unique_ptr<QFileSystemWatcher> m_watcher;
};
} // namespace IMobile
} // namespace Backends
} // namespace Solid
#endif // SOLID_BACKENDS_IMOBILE_IMOBILEMANAGER_H
@@ -0,0 +1,47 @@
/*
SPDX-FileCopyrightText: 2020 MBition GmbH
SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "imobileportablemediaplayer.h"
#include "imobile.h"
#include "imobiledevice.h"
using namespace Solid::Backends::IMobile;
PortableMediaPlayer::PortableMediaPlayer(IMobileDevice *device)
: DeviceInterface(device)
{
}
PortableMediaPlayer::~PortableMediaPlayer()
{
}
QStringList PortableMediaPlayer::supportedProtocols() const
{
return {QStringLiteral("afc")};
}
QStringList PortableMediaPlayer::supportedDrivers(QString protocol) const
{
Q_UNUSED(protocol)
return {// libimobiledevice goes via usbmuxd
QStringLiteral("usbmux")};
}
QVariant PortableMediaPlayer::driverHandle(const QString &driver) const
{
if (driver == QLatin1String("usbmux")) {
// as per docs "usbmux" should return the device UDID
// which we use as part of our UDI
return m_device->udi().mid(udiPrefix().length() + 1);
}
return {};
}
#include "moc_imobileportablemediaplayer.cpp"
@@ -0,0 +1,42 @@
/*
SPDX-FileCopyrightText: 2010 Rafael Fernández López <ereslibre@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IMOBILE_IMOBILEPORTABLEMEDIAPLAYER_H
#define SOLID_BACKENDS_IMOBILE_IMOBILEPORTABLEMEDIAPLAYER_H
#include <solid/devices/ifaces/portablemediaplayer.h>
#include <QStringList>
#include "imobiledeviceinterface.h"
namespace Solid
{
namespace Backends
{
namespace IMobile
{
class IMobileDevice;
class PortableMediaPlayer : public DeviceInterface, virtual public Solid::Ifaces::PortableMediaPlayer
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::PortableMediaPlayer)
public:
PortableMediaPlayer(IMobileDevice *device);
~PortableMediaPlayer() override;
QStringList supportedProtocols() const override;
QStringList supportedDrivers(QString protocol = QString()) const override;
QVariant driverHandle(const QString &driver) const override;
};
} // namespace IMobile
} // namespace Backends
} // namespace Solid
#endif // SOLID_BACKENDS_IMOBILE_IMOBILEPORTABLEMEDIAPLAYER_H
@@ -0,0 +1,17 @@
set(backend_sources
iokitmanager.cpp
iokitdevice.cpp
cfhelper.cpp
dadictionary.cpp
iokitdeviceinterface.cpp
iokitgenericinterface.cpp
iokitprocessor.cpp
iokitbattery.cpp
iokitblock.cpp
iokitstorage.cpp
iokitvolume.cpp
iokitstorageaccess.cpp
iokitopticaldrive.cpp
iokitopticaldisc.cpp
)
set(backend_libs ${IOKIT_LIBRARY} "-framework DiskArbitration")
@@ -0,0 +1,178 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include <qdatetime.h>
#include <qdebug.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qvariant.h>
#include <qvarlengtharray.h>
#include <CoreFoundation/CoreFoundation.h>
#include <sys/sysctl.h>
/* helper classes to convert from CF types to Qt */
static QString q_toString(const CFStringRef &str)
{
CFIndex length = CFStringGetLength(str);
QVarLengthArray<UniChar> buffer(length);
CFRange range = {0, length};
CFStringGetCharacters(str, range, buffer.data());
return QString(reinterpret_cast<const QChar *>(buffer.data()), length);
}
template<typename T>
static inline T convertCFNumber(const CFNumberRef &num, CFNumberType type)
{
T n;
CFNumberGetValue(num, type, &n);
return n;
}
static QVariant q_toVariant(const CFTypeRef &obj)
{
const CFTypeID typeId = CFGetTypeID(obj);
if (typeId == CFStringGetTypeID()) {
return QVariant(q_toString(static_cast<const CFStringRef>(obj)));
}
if (typeId == CFNumberGetTypeID()) {
const CFNumberRef num = static_cast<const CFNumberRef>(obj);
const CFNumberType type = CFNumberGetType(num);
switch (type) {
case kCFNumberSInt8Type:
return QVariant::fromValue(convertCFNumber<char>(num, type));
case kCFNumberSInt16Type:
return QVariant::fromValue(convertCFNumber<qint16>(num, type));
case kCFNumberSInt32Type:
return QVariant::fromValue(convertCFNumber<qint32>(num, type));
case kCFNumberSInt64Type:
return QVariant::fromValue(convertCFNumber<qint64>(num, type));
case kCFNumberCharType:
return QVariant::fromValue(convertCFNumber<uchar>(num, type));
case kCFNumberShortType:
return QVariant::fromValue(convertCFNumber<short>(num, type));
case kCFNumberIntType:
return QVariant::fromValue(convertCFNumber<int>(num, type));
case kCFNumberLongType:
return QVariant::fromValue(convertCFNumber<long>(num, type));
case kCFNumberLongLongType:
return QVariant::fromValue(convertCFNumber<long long>(num, type));
case kCFNumberFloatType:
return QVariant::fromValue(convertCFNumber<float>(num, type));
case kCFNumberDoubleType:
return QVariant::fromValue(convertCFNumber<double>(num, type));
default:
if (CFNumberIsFloatType(num)) {
return QVariant::fromValue(convertCFNumber<double>(num, kCFNumberDoubleType));
}
return QVariant::fromValue(convertCFNumber<quint64>(num, kCFNumberLongLongType));
}
}
if (typeId == CFDateGetTypeID()) {
QDateTime dt;
dt.setSecsSinceEpoch(qint64(kCFAbsoluteTimeIntervalSince1970));
return dt.addSecs(int(CFDateGetAbsoluteTime(static_cast<const CFDateRef>(obj))));
}
if (typeId == CFDataGetTypeID()) {
const CFDataRef cfdata = static_cast<const CFDataRef>(obj);
return QByteArray(reinterpret_cast<const char *>(CFDataGetBytePtr(cfdata)), CFDataGetLength(cfdata));
}
if (typeId == CFBooleanGetTypeID()) {
return QVariant(bool(CFBooleanGetValue(static_cast<const CFBooleanRef>(obj))));
}
if (typeId == CFArrayGetTypeID()) {
const CFArrayRef cfarray = static_cast<const CFArrayRef>(obj);
QList<QVariant> list;
CFIndex size = CFArrayGetCount(cfarray);
bool metNonString = false;
for (CFIndex i = 0; i < size; ++i) {
QVariant value = q_toVariant(CFArrayGetValueAtIndex(cfarray, i));
if (value.userType() != QMetaType::QString) {
metNonString = true;
}
list << value;
}
if (metNonString) {
return list;
} else {
return QVariant(list).toStringList();
}
}
if (typeId == CFDictionaryGetTypeID()) {
const CFDictionaryRef cfdict = static_cast<const CFDictionaryRef>(obj);
const CFTypeID arrayTypeId = CFArrayGetTypeID();
int size = int(CFDictionaryGetCount(cfdict));
QVarLengthArray<CFPropertyListRef> keys(size);
QVarLengthArray<CFPropertyListRef> values(size);
CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data());
QMultiMap<QString, QVariant> map;
for (int i = 0; i < size; ++i) {
QString key = q_toString(static_cast<const CFStringRef>(keys[i]));
if (CFGetTypeID(values[i]) == arrayTypeId) {
const CFArrayRef cfarray = static_cast<const CFArrayRef>(values[i]);
CFIndex arraySize = CFArrayGetCount(cfarray);
for (CFIndex j = arraySize - 1; j >= 0; --j) {
map.insert(key, q_toVariant(CFArrayGetValueAtIndex(cfarray, j)));
}
} else {
map.insert(key, q_toVariant(values[i]));
}
}
return QVariant::fromValue(map);
}
return QVariant();
}
QMap<QString, QVariant> q_toVariantMap(const CFMutableDictionaryRef &dict)
{
Q_ASSERT(dict);
QMap<QString, QVariant> result;
const int count = CFDictionaryGetCount(dict);
QVarLengthArray<void *> keys(count);
QVarLengthArray<void *> values(count);
CFDictionaryGetKeysAndValues(dict, const_cast<const void **>(keys.data()), const_cast<const void **>(values.data()));
for (int i = 0; i < count; ++i) {
const QString key = q_toString((CFStringRef)keys[i]);
const QVariant value = q_toVariant((CFTypeRef)values[i]);
result[key] = value;
}
return result;
}
bool q_sysctlbyname(const char *name, QString &result)
{
char *property = nullptr;
size_t size = 0;
int error = 0;
if (name && sysctlbyname(name, nullptr, &size, nullptr, 0) == 0 && size > 0) {
property = new char[size];
error = sysctlbyname(name, property, &size, nullptr, 0);
if (!error) {
result = QLatin1String(property);
}
delete[] property;
}
return !error;
}
@@ -0,0 +1,88 @@
/*
SPDX-FileCopyrightText: 2018 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "dadictionary_p.h"
using namespace Solid::Backends::IOKit;
DADictionary::DADictionary(const IOKitDevice *device)
: device(device)
, daSession(DASessionCreate(kCFAllocatorDefault))
, daDict(nullptr)
{
if (daSession) {
const QString devName = device->property(QStringLiteral("BSD Name")).toString();
daRef = DADiskCreateFromBSDName(kCFAllocatorDefault, daSession, devName.toStdString().c_str());
} else {
daRef = nullptr;
}
}
DADictionary::~DADictionary()
{
releaseDict();
if (daRef) {
CFRelease(daRef);
daRef = nullptr;
}
if (daSession) {
CFRelease(daSession);
daSession = nullptr;
}
}
bool DADictionary::getDict()
{
// daDict may cache the latest disk description dict;
// we will refresh it now.
releaseDict();
if (daRef) {
daDict = DADiskCopyDescription(daRef);
}
return daDict != nullptr;
}
void DADictionary::releaseDict()
{
if (daDict) {
CFRelease(daDict);
daDict = nullptr;
}
}
const QString DADictionary::stringForKey(const CFStringRef key)
{
QString ret;
if (getDict()) {
ret = QString::fromCFString((const CFStringRef)CFDictionaryGetValue(daDict, key));
releaseDict();
}
return ret;
}
CFURLRef DADictionary::cfUrLRefForKey(const CFStringRef key)
{
CFURLRef ret = nullptr;
if (getDict()) {
ret = (const CFURLRef)CFDictionaryGetValue(daDict, key);
}
// we cannot release the dictionary here, or else we'd need to
// copy the CFURLRef and oblige our caller to release the return value.
return ret;
}
bool DADictionary::boolForKey(const CFStringRef key, bool &value)
{
if (getDict()) {
const CFBooleanRef boolRef = (const CFBooleanRef)CFDictionaryGetValue(daDict, key);
if (boolRef) {
value = CFBooleanGetValue(boolRef);
}
releaseDict();
return boolRef != nullptr;
}
return false;
}
@@ -0,0 +1,67 @@
/*
SPDX-FileCopyrightText: 2018 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_DADICTIONARY_P_H
#define SOLID_BACKENDS_IOKIT_DADICTIONARY_P_H
#include <QString>
#include "iokitdevice.h"
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class DADictionary
{
public:
DADictionary(const IOKitDevice *device);
virtual ~DADictionary();
/**
* get a fresh copy of the DA disk description dict;
* the result is stored in daRef (after releasing any
* dict it may currently point to).
*/
bool getDict();
/**
* release the DA disk description dict and reset daRef.
*/
void releaseDict();
/**
* fetch the value of @p key as a string, from the current
* disk description (calls getDict() and releaseDict()).
*/
const QString stringForKey(const CFStringRef key);
/**
* fetch the value of @p key as a CFURLRef, from the current
* disk description. Calls getDict() but not releaseDict().
*The contents of the CFURLRef must be retrieved before
* calling releaseDict() (and thus getDict()).
*/
CFURLRef cfUrLRefForKey(const CFStringRef key);
/**
* fetch the value of @p key as a boolean, from the current
* disk description (calls getDict() and releaseDict()).
*/
bool boolForKey(const CFStringRef key, bool &value);
const IOKitDevice *device;
DASessionRef daSession;
DADiskRef daRef;
CFDictionaryRef daDict;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_DADICTIONARY_P_H
@@ -0,0 +1,164 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitbattery.h"
#include "iokitdevice.h"
// TODO - emit the signals
using namespace Solid::Backends::IOKit;
Battery::Battery(IOKitDevice *device)
: DeviceInterface(device)
{
}
Battery::~Battery()
{
}
// properties: QMap(("AdapterInfo", QVariant(int, 0))
// ("Amperage", QVariant(int, 0))
// ("AvgTimeToEmpty", QVariant(int, 65535))
// ("AvgTimeToFull", QVariant(int, 65535))
// ("BatteryInstalled", QVariant(bool, true))
// ("BatteryInvalidWakeSeconds", QVariant(int, 30))
// ("BatterySerialNumber", QVariant(QString, "W01286PEED3BA"))
// ("BootPathUpdated", QVariant(int, 1501532930))
// ("CellVoltage", QVariant(QVariantList, (QVariant(int, 4136), QVariant(int, 4134), QVariant(int, 4134), QVariant(int, 0))))
// ("CurrentCapacity", QVariant(int, 5552))
// ("CycleCount", QVariant(int, 16))
// ("DesignCapacity", QVariant(int, 5770))
// ("DesignCycleCount", QVariant(int, 1000))
// ("DeviceName", QVariant(QString, "bq20z451"))
// ("ExternalChargeCapable", QVariant(bool, true))
// ("ExternalConnected", QVariant(bool, true))
// ("FirmwareSerialNumber", QVariant(int, 48))
// ("FullPathUpdated", QVariant(int, 1502790621))
// ("FullyCharged", QVariant(bool, true))
// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable"))
// ("InstantAmperage", QVariant(int, 0))
// ("InstantTimeToEmpty", QVariant(int, 65535))
// ("IsCharging", QVariant(bool, false))
// ("LegacyBatteryInfo", QVariant(QVariantMap, QMap(("Amperage", QVariant(int, 0))
// ("Capacity", QVariant(int, 5814))
// ("Current", QVariant(int, 5552))
// ("Cycle Count", QVariant(int, 16))
// ("Flags", QVariant(int, 5))
// ("Voltage", QVariant(int, 12403)))))
// ("Location", QVariant(int, 0))
// ("ManufactureDate", QVariant(int, 16106))
// ("Manufacturer", QVariant(QString, "SMP"))
// ("ManufacturerData", QVariant(QByteArray, "\x00\x00\x00\x00\x02\x01\x00\n\x01X\x00\x00\x02K6c\x03""00A\x03""ATL\x00\x12\x00\x00"))
// ("MaxCapacity", QVariant(int, 5814))
// ("MaxErr", QVariant(int, 1))
// ("OperationStatus", QVariant(int, 58435))
// ("PackReserve", QVariant(int, 200))
// ("PermanentFailureStatus", QVariant(int, 0))
// ("PostChargeWaitSeconds", QVariant(int, 120))
// ("PostDischargeWaitSeconds", QVariant(int, 120))
// ("Temperature", QVariant(int, 2965))
// ("TimeRemaining", QVariant(int, 0))
// ("UserVisiblePathUpdated", QVariant(int, 1502790679))
// ("Voltage", QVariant(int, 12403))
// ("className", QVariant(QString, "AppleSmartBattery")))
qlonglong Battery::timeToEmpty() const
{
if (chargeState() != Solid::Battery::Charging) {
int t = m_device->property(QStringLiteral("AvgTimeToEmpty")).toInt();
return t == 65535 ? -1 : t * 60;
}
return -1;
}
qlonglong Battery::timeToFull() const
{
if (chargeState() == Solid::Battery::Charging) {
int t = m_device->property(QStringLiteral("AvgTimeToFull")).toInt();
return t == 65535 ? -1 : t * 60;
}
return -1;
}
double Battery::voltage() const
{
return m_device->property(QStringLiteral("Voltage")).toInt() / 1000.0;
}
double Battery::temperature() const
{
return m_device->property(QStringLiteral("Temperature")).toInt() / 100.0;
}
QString Battery::serial() const
{
return m_device->property(QStringLiteral("BatterySerialNumber")).toString();
}
bool Battery::isPresent() const
{
return m_device->property(QStringLiteral("ExternalConnected")).toBool();
}
Solid::Battery::BatteryType Battery::type() const
{
// TODO - how to figure that one out? Just presume we're
// only called with the main battery.
return Solid::Battery::PrimaryBattery;
}
int Battery::chargePercent() const
{
// always calculate since FullyCharged remains true down to 92% or so.
int maxCapacity = m_device->property(QStringLiteral("MaxCapacity")).toInt();
if (maxCapacity == 0) {
return 0; // prevent divide by 0
}
return int(m_device->property(QStringLiteral("CurrentCapacity")).toInt() * 100.0 / maxCapacity + 0.5);
}
int Battery::capacity() const
{
if (m_device->iOKitPropertyExists(QStringLiteral("PermanentFailureStatus")) //
&& m_device->property(QStringLiteral("PermanentFailureStatus")).toInt()) {
return 0;
}
return 100;
}
int Battery::cycleCount() const
{
return m_device->property(QStringLiteral("CycleCount")).toInt();
}
bool Battery::isRechargeable() const
{
return m_device->property(QStringLiteral("CycleCount")).toInt() > 1;
}
bool Battery::isPowerSupply() const
{
/* clang-format off */
return m_device->iOKitPropertyExists(QStringLiteral("BatteryInstalled"))
? m_device->property(QStringLiteral("BatteryInstalled")).toBool()
: true;
/* clang-format on */
}
Solid::Battery::ChargeState Battery::chargeState() const
{
if (m_device->property(QStringLiteral("IsCharging")).toBool()) {
return Solid::Battery::Charging;
}
if (m_device->property(QStringLiteral("FullyCharged")).toBool()) {
return Solid::Battery::FullyCharged;
}
return Solid::Battery::Discharging;
}
#include "moc_iokitbattery.cpp"
@@ -0,0 +1,80 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_BATTERY_H
#define SOLID_BACKENDS_IOKIT_BATTERY_H
#include "iokitdeviceinterface.h"
#include <solid/devices/ifaces/battery.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitDevice;
class Battery : public DeviceInterface, virtual public Solid::Ifaces::Battery
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Battery)
public:
Battery(IOKitDevice *device);
virtual ~Battery();
bool isPresent() const override;
Solid::Battery::BatteryType type() const override;
int chargePercent() const override;
int capacity() const override;
int cycleCount() const override;
bool isRechargeable() const override;
bool isPowerSupply() const override;
Solid::Battery::ChargeState chargeState() const override;
qlonglong timeToEmpty() const override;
qlonglong timeToFull() const override;
double voltage() const override;
double temperature() const override;
QString serial() const override;
// ### the ones below are TODO
// clang-format off
Solid::Battery::Technology technology() const override { return Solid::Battery::UnknownTechnology; }
double energy() const override { return 0.0; }
double energyFull() const override { return 0.0; }
double energyFullDesign() const override { return 0.0; }
double energyRate() const override { return 0.0; }
qlonglong remainingTime() const override { return -1; }
// clang-format on
Q_SIGNALS:
void energyChanged(double energy, const QString &udi) override;
void energyFullChanged(double energyFull, const QString &udi) override;
void energyFullDesignChanged(double energyFullDesign, const QString &udi) override;
void energyRateChanged(double energyRate, const QString &udi) override;
void chargePercentChanged(int value, const QString &udi) override;
void capacityChanged(int value, const QString &udi) override;
void cycleCountChanged(int value, const QString &udi) override;
void chargeStateChanged(int newState, const QString &udi) override;
void presentStateChanged(bool newState, const QString &udi) override;
void powerSupplyStateChanged(bool newState, const QString &udi) override;
void timeToEmptyChanged(qlonglong time, const QString &udi) override;
void timeToFullChanged(qlonglong time, const QString &udi) override;
void temperatureChanged(double temperature, const QString &udi) override;
void voltageChanged(double voltage, const QString &udi) override;
void remainingTimeChanged(qlonglong time, const QString &udi) override;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_BATTERY_H
@@ -0,0 +1,45 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitblock.h"
#include "iokitdevice.h"
using namespace Solid::Backends::IOKit;
Block::Block(IOKitDevice *device)
: DeviceInterface(device)
{
}
Block::Block(const IOKitDevice *device)
: DeviceInterface(device)
{
}
Block::~Block()
{
}
int Block::deviceMajor() const
{
return m_device->property(QLatin1String("BSD Major")).toInt();
}
int Block::deviceMinor() const
{
return m_device->property(QLatin1String("BSD Minor")).toInt();
}
QString Block::device() const
{
if (m_device->iOKitPropertyExists(QStringLiteral("BSD Name"))) {
return QStringLiteral("/dev/") + m_device->property(QLatin1String("BSD Name")).toString();
}
return QString();
}
#include "moc_iokitblock.cpp"
@@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_BLOCK_H
#define SOLID_BACKENDS_IOKIT_BLOCK_H
#include "iokitdeviceinterface.h"
#include <solid/devices/ifaces/block.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class Block : public DeviceInterface, virtual public Solid::Ifaces::Block
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Block)
public:
Block(IOKitDevice *device);
Block(const IOKitDevice *device);
virtual ~Block();
int deviceMajor() const override;
int deviceMinor() const override;
QString device() const override;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_BLOCK_H
@@ -0,0 +1,520 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitdevice.h"
#include "iokitbattery.h"
#include "iokitgenericinterface.h"
#include "iokitopticaldisc.h"
#include "iokitopticaldrive.h"
#include "iokitprocessor.h"
#include "iokitstorage.h"
#include "iokitstorageaccess.h"
#include "iokitvolume.h"
#include <QDebug>
#include <QSet>
#include <QUrl>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/usb/IOUSBLib.h>
#include <CoreFoundation/CoreFoundation.h>
// from cfhelper.cpp
extern QMap<QString, QVariant> q_toVariantMap(const CFMutableDictionaryRef &dict);
extern bool q_sysctlbyname(const char *name, QString &result);
typedef QSet<Solid::DeviceInterface::Type> DeviceInterfaceTypes;
namespace Solid
{
namespace Backends
{
namespace IOKit
{
// returns a solid type from an entry and its properties
static DeviceInterfaceTypes typesFromEntry(const io_registry_entry_t &entry, const QMap<QString, QVariant> &properties, Solid::DeviceInterface::Type &mainType)
{
DeviceInterfaceTypes types;
mainType = Solid::DeviceInterface::Unknown;
if (IOObjectConformsTo(entry, "AppleACPICPU")) {
mainType = Solid::DeviceInterface::Processor;
types << mainType;
}
if (IOObjectConformsTo(entry, "AppleSmartBattery")) {
mainType = Solid::DeviceInterface::Battery;
types << mainType;
}
const QString bsdName = QStringLiteral("BSD Name");
const QString leaf = QStringLiteral("Leaf");
if (IOObjectConformsTo(entry, "IOCDMedia") //
|| IOObjectConformsTo(entry, "IODVDMedia") //
|| IOObjectConformsTo(entry, "IOBDMedia")) {
mainType = Solid::DeviceInterface::OpticalDrive;
types << mainType << Solid::DeviceInterface::OpticalDisc;
}
if (properties.contains(bsdName) && properties.value(bsdName).toString().startsWith(QStringLiteral("disk"))) {
if ((properties.contains(leaf) && properties.value(leaf).toBool() == false) //
|| mainType == Solid::DeviceInterface::OpticalDrive) {
if (mainType == Solid::DeviceInterface::Unknown) {
mainType = Solid::DeviceInterface::StorageDrive;
}
types << Solid::DeviceInterface::StorageDrive;
} else if (mainType == Solid::DeviceInterface::Unknown) {
mainType = Solid::DeviceInterface::StorageVolume;
}
types << Solid::DeviceInterface::StorageVolume;
}
if (types.isEmpty()) {
types << mainType;
// qWarning() << "unsupported entry" << entry << "with properties" << properties;
}
return types;
}
// gets all properties from an entry into a QMap
static QMap<QString, QVariant> getProperties(const io_registry_entry_t &entry)
{
CFMutableDictionaryRef propertyDict = 0;
if (IORegistryEntryCreateCFProperties(entry, &propertyDict, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) {
return QMap<QString, QVariant>();
}
QMap<QString, QVariant> result = q_toVariantMap(propertyDict);
CFRelease(propertyDict);
io_name_t className;
IOObjectGetClass(entry, className);
result[QStringLiteral("className")] = QString::fromUtf8(className);
return result;
}
// gets the parent's Udi from an entry
static QString getParentDeviceUdi(const io_registry_entry_t &entry)
{
io_registry_entry_t parent = 0;
kern_return_t ret = IORegistryEntryGetParentEntry(entry, kIOServicePlane, &parent);
if (ret != KERN_SUCCESS) {
// don't release parent here - docs say only on success
return QString();
}
CFStringRef path = IORegistryEntryCopyPath(parent, kIOServicePlane);
QString result = QString::fromCFString(path);
CFRelease(path);
// now we can release the parent
IOObjectRelease(parent);
return result;
}
static const QString computerModel()
{
QString qModel;
q_sysctlbyname("hw.model", qModel);
return qModel;
}
class IOKitDevicePrivate
{
public:
inline IOKitDevicePrivate()
: type({Solid::DeviceInterface::Unknown})
, parentDevice(nullptr)
{
}
~IOKitDevicePrivate()
{
if (parentDevice) {
delete parentDevice;
parentDevice = nullptr;
}
}
void init(const QString &udiString, const io_registry_entry_t &entry);
IOKitDevice *getParentDevice();
QString udi;
QString parentUdi;
QMap<QString, QVariant> properties;
DeviceInterfaceTypes type;
Solid::DeviceInterface::Type mainType;
IOKitDevice *parentDevice;
};
void IOKitDevicePrivate::init(const QString &udiString, const io_registry_entry_t &entry)
{
Q_ASSERT(entry != MACH_PORT_NULL);
udi = udiString;
properties = getProperties(entry);
parentUdi = getParentDeviceUdi(entry);
type = typesFromEntry(entry, properties, mainType);
if (udi.contains(QStringLiteral("IOBD")) || udi.contains(QStringLiteral("BD PX"))) {
qWarning() << "Solid: BlueRay entry" << entry << "mainType=" << mainType << "typeList:" << type << "with properties" << properties;
}
if (mainType != Solid::DeviceInterface::Unknown) { }
IOObjectRelease(entry);
}
IOKitDevice *IOKitDevicePrivate::getParentDevice()
{
if (!parentDevice) {
parentDevice = new IOKitDevice(parentUdi);
}
return parentDevice;
}
IOKitDevice::IOKitDevice(const QString &udi, const io_registry_entry_t &entry)
: d(new IOKitDevicePrivate)
{
d->init(udi, entry);
}
IOKitDevice::IOKitDevice(const QString &udi)
: d(new IOKitDevicePrivate)
{
if (udi.isEmpty()) {
qWarning() << Q_FUNC_INFO << "Tried to create Device from empty UDI";
return;
}
CFStringRef path = udi.toCFString();
io_registry_entry_t entry = IORegistryEntryCopyFromPath(kIOMasterPortDefault, path);
CFRelease(path);
if (entry == MACH_PORT_NULL) {
qWarning() << Q_FUNC_INFO << "Tried to create Device from invalid UDI" << udi;
return;
}
d->init(udi, entry);
}
IOKitDevice::IOKitDevice(const IOKitDevice &device)
: d(new IOKitDevicePrivate)
{
if (device.udi().isEmpty()) {
qWarning() << Q_FUNC_INFO << "Tried to create Device from empty UDI";
return;
}
CFStringRef path = device.udi().toCFString();
io_registry_entry_t entry = IORegistryEntryCopyFromPath(kIOMasterPortDefault, path);
CFRelease(path);
if (entry == MACH_PORT_NULL) {
qWarning() << Q_FUNC_INFO << "Tried to create Device from invalid UDI" << device.udi();
return;
}
d->init(device.udi(), entry);
}
IOKitDevice::~IOKitDevice()
{
delete d;
}
bool IOKitDevice::conformsToIOKitClass(const QString &className) const
{
bool conforms = false;
if (!className.isEmpty()) {
CFStringRef path = udi().toCFString();
io_registry_entry_t entry = IORegistryEntryCopyFromPath(kIOMasterPortDefault, path);
CFRelease(path);
if (entry != MACH_PORT_NULL) {
conforms = IOObjectConformsTo(entry, className.toLocal8Bit().constData());
IOObjectRelease(entry);
}
}
return conforms;
}
QString IOKitDevice::udi() const
{
return d->udi;
}
QString IOKitDevice::parentUdi() const
{
return d->parentUdi;
}
QString IOKitDevice::vendor() const
{
if (parentUdi().isEmpty()) {
return QStringLiteral("Apple");
}
switch (d->mainType) {
case Solid::DeviceInterface::Processor:
return Processor::vendor();
break;
case Solid::DeviceInterface::Battery:
return property(QStringLiteral("Manufacturer")).toString();
break;
case Solid::DeviceInterface::StorageDrive:
case Solid::DeviceInterface::OpticalDrive:
case Solid::DeviceInterface::OpticalDisc:
return IOKitStorage(this).vendor();
break;
case Solid::DeviceInterface::StorageVolume:
return IOKitVolume(this).vendor();
break;
default:
return QString();
break;
}
return QString();
}
QString IOKitDevice::product() const
{
if (parentUdi().isEmpty()) {
return computerModel();
}
switch (d->mainType) {
case Solid::DeviceInterface::Processor:
return Processor::product();
break;
case Solid::DeviceInterface::Battery:
return property(QStringLiteral("DeviceName")).toString();
break;
case Solid::DeviceInterface::StorageDrive:
case Solid::DeviceInterface::OpticalDrive:
case Solid::DeviceInterface::OpticalDisc:
return IOKitStorage(this).product();
break;
case Solid::DeviceInterface::StorageVolume:
return IOKitVolume(this).product();
break;
}
return QString(); // TODO
}
QString IOKitDevice::description() const
{
switch (d->mainType) {
case Solid::DeviceInterface::Processor:
return QStringLiteral("Processor");
break;
case Solid::DeviceInterface::Battery:
return QStringLiteral("Apple Smart Battery");
break;
case Solid::DeviceInterface::StorageDrive:
case Solid::DeviceInterface::OpticalDrive:
case Solid::DeviceInterface::OpticalDisc:
return IOKitStorage(this).description();
break;
case Solid::DeviceInterface::StorageVolume: {
const QString volLabel = IOKitVolume(this).description();
const QString mountPoint = IOKitStorageAccess(this).filePath();
if (volLabel.isEmpty()) {
return QUrl::fromLocalFile(mountPoint).fileName();
} else if (mountPoint.startsWith(QStringLiteral("/Volumes/"))) {
// Mac users will expect to see the name under which the volume is mounted here.
return QString(QStringLiteral("%1 (%2)")).arg(QUrl::fromLocalFile(mountPoint).fileName()).arg(volLabel);
}
return volLabel;
break;
}
}
return product(); // TODO
}
QString IOKitDevice::icon() const
{
// adapted from HalDevice::icon()
if (parentUdi().isEmpty()) {
if (computerModel().contains(QStringLiteral("MacBook"))) {
return QStringLiteral("computer-laptop");
} else {
return QStringLiteral("computer");
}
} else if (d->type.contains(Solid::DeviceInterface::StorageDrive)) {
IOKitStorage drive(this);
Solid::StorageDrive::DriveType driveType = drive.driveType();
switch (driveType) {
case Solid::StorageDrive::Floppy:
// why not :)
return QStringLiteral("media-floppy");
break;
case Solid::StorageDrive::CdromDrive: {
const IOKitOpticalDisc disc(this);
if (disc.availableContent() == Solid::OpticalDisc::Audio) {
return QStringLiteral("media-optical-audio");
} else
switch (disc.discType()) {
case Solid::OpticalDisc::CdRom:
return QStringLiteral("media-optical-data");
break;
case Solid::OpticalDisc::CdRecordable:
case Solid::OpticalDisc::CdRewritable:
return QStringLiteral("media-optical-recordable");
break;
case Solid::OpticalDisc::BluRayRom:
case Solid::OpticalDisc::BluRayRecordable:
case Solid::OpticalDisc::BluRayRewritable:
return QStringLiteral("media-optical-blu-ray");
break;
}
break;
}
case Solid::StorageDrive::SdMmc:
return QStringLiteral("media-flash-sd-mmc");
break;
case Solid::StorageDrive::CompactFlash:
return QStringLiteral("media-flash-cf");
break;
}
if (drive.bus() == Solid::StorageDrive::Usb) {
return QStringLiteral("drive-removable-media-usb");
}
if (drive.isRemovable()) {
return QStringLiteral("drive-removable-media");
}
return QStringLiteral("drive-harddisk");
} else if (d->mainType == Solid::DeviceInterface::StorageVolume) {
} else if (d->mainType == Solid::DeviceInterface::Battery) {
return QStringLiteral("battery");
} else if (d->mainType == Solid::DeviceInterface::Processor) {
return QStringLiteral("cpu"); // FIXME: Doesn't follow icon spec
} else {
QString iconName = d->getParentDevice()->icon();
if (!iconName.isEmpty()) {
return iconName;
}
return QStringLiteral("drive-harddisk");
}
return QString();
}
QStringList IOKitDevice::emblems() const
{
return QStringList(); // TODO
}
QVariant IOKitDevice::property(const QString &key) const
{
if (!d->properties.contains(key)) {
return QObject::property(key.toUtf8().constData());
}
return d->properties.value(key);
}
QMap<QString, QVariant> IOKitDevice::allProperties() const
{
return d->properties;
}
bool IOKitDevice::iOKitPropertyExists(const QString &key) const
{
return d->properties.contains(key);
}
bool IOKitDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const
{
switch (type) {
case Solid::DeviceInterface::GenericInterface:
return true;
break;
case Solid::DeviceInterface::StorageAccess:
if (d->type.contains(Solid::DeviceInterface::StorageDrive) //
|| d->type.contains(Solid::DeviceInterface::StorageVolume)) {
return true;
}
break;
default:
return d->type.contains(type);
break;
}
return false;
}
QObject *IOKitDevice::createDeviceInterface(const Solid::DeviceInterface::Type &type)
{
QObject *iface = nullptr;
switch (type) {
case Solid::DeviceInterface::GenericInterface:
iface = new GenericInterface(this);
break;
case Solid::DeviceInterface::Processor:
if (d->type.contains(Solid::DeviceInterface::Processor)) {
iface = new Processor(this);
}
break;
case Solid::DeviceInterface::Battery:
if (d->type.contains(Solid::DeviceInterface::Battery)) {
iface = new Battery(this);
}
break;
case Solid::DeviceInterface::OpticalDrive:
if (d->type.contains(Solid::DeviceInterface::OpticalDrive)) {
iface = new IOKitOpticalDrive(this);
}
break;
case Solid::DeviceInterface::OpticalDisc:
if (d->type.contains(Solid::DeviceInterface::OpticalDisc)) {
iface = new IOKitOpticalDisc(this);
}
break;
case Solid::DeviceInterface::StorageDrive:
if (d->type.contains(Solid::DeviceInterface::StorageDrive)) {
iface = new IOKitStorage(this);
}
break;
case Solid::DeviceInterface::Block:
if (d->type.contains(Solid::DeviceInterface::OpticalDisc)) {
iface = new IOKitOpticalDisc(this);
} else if (d->type.contains(Solid::DeviceInterface::OpticalDrive)) {
iface = new IOKitOpticalDrive(this);
} else if (d->type.contains(Solid::DeviceInterface::StorageVolume)) {
iface = new IOKitVolume(this);
} else if (d->type.contains(Solid::DeviceInterface::StorageDrive)) {
iface = new IOKitStorage(this);
}
break;
case Solid::DeviceInterface::StorageVolume:
if (d->type.contains(Solid::DeviceInterface::StorageVolume)) {
iface = new IOKitVolume(this);
}
break;
case Solid::DeviceInterface::StorageAccess:
if (d->type.contains(Solid::DeviceInterface::StorageDrive) //
|| d->type.contains(Solid::DeviceInterface::StorageVolume)) {
iface = new IOKitStorageAccess(this);
}
break;
// the rest is TODO
}
return iface;
}
}
}
} // namespaces
#include "moc_iokitdevice.cpp"
@@ -0,0 +1,64 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_IOKITDEVICE_H
#define SOLID_BACKENDS_IOKIT_IOKITDEVICE_H
#include <IOKit/IOKitLib.h>
#include <solid/devices/ifaces/device.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitDevicePrivate;
class IOKitManager;
class IOKitDevice : public Solid::Ifaces::Device
{
Q_OBJECT
public:
IOKitDevice(const QString &udi);
IOKitDevice(const IOKitDevice &device);
virtual ~IOKitDevice();
QString udi() const override;
QString parentUdi() const override;
QString vendor() const override;
QString product() const override;
QString icon() const override;
QStringList emblems() const override;
QString description() const override;
virtual QVariant property(const QString &key) const;
virtual QMap<QString, QVariant> allProperties() const;
virtual bool iOKitPropertyExists(const QString &key) const;
bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const override;
QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) override;
bool conformsToIOKitClass(const QString &className) const;
Q_SIGNALS:
void propertyChanged(const QMap<QString, int> &changes);
void conditionRaised(const QString &condition, const QString &reason);
private:
friend class IOKitManager;
IOKitDevice(const QString &udi, const io_registry_entry_t &entry);
IOKitDevicePrivate *const d;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_IOKITDEVICE_H
@@ -0,0 +1,34 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitdeviceinterface.h"
using namespace Solid::Backends::IOKit;
DeviceInterface::DeviceInterface(IOKitDevice *device)
: QObject(device)
, m_device(device)
, m_deviceCopy(nullptr)
{
}
DeviceInterface::DeviceInterface(const IOKitDevice *device)
: QObject(device->parent())
, m_deviceCopy(new IOKitDevice(*device))
{
m_device = m_deviceCopy;
}
DeviceInterface::~DeviceInterface()
{
if (m_deviceCopy) {
delete m_deviceCopy;
m_deviceCopy = nullptr;
}
}
#include "moc_iokitdeviceinterface.cpp"
@@ -0,0 +1,42 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H
#define SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H
#include "iokitdevice.h"
#include <solid/devices/ifaces/deviceinterface.h>
#include <QObject>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class DeviceInterface : public QObject, virtual public Solid::Ifaces::DeviceInterface
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::DeviceInterface)
public:
DeviceInterface(IOKitDevice *device);
// the ctor taking a const device* argument makes a deep
// copy of the IOKitDevice; any property changes made via
// the resulting instance will not affect the original device.
DeviceInterface(const IOKitDevice *device);
virtual ~DeviceInterface();
protected:
IOKitDevice *m_device;
IOKitDevice *m_deviceCopy;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H
@@ -0,0 +1,37 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitgenericinterface.h"
#include "iokitdevice.h"
using namespace Solid::Backends::IOKit;
GenericInterface::GenericInterface(IOKitDevice *device)
: DeviceInterface(device)
{
}
GenericInterface::~GenericInterface()
{
}
QVariant GenericInterface::property(const QString &key) const
{
return m_device->property(key);
}
QMap<QString, QVariant> GenericInterface::allProperties() const
{
return m_device->allProperties();
}
bool GenericInterface::propertyExists(const QString &key) const
{
return m_device->iOKitPropertyExists(key);
}
#include "moc_iokitgenericinterface.cpp"
@@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_GENERICINTERFACE_H
#define SOLID_BACKENDS_IOKIT_GENERICINTERFACE_H
#include "iokitdeviceinterface.h"
#include <solid/devices/ifaces/genericinterface.h>
#include <solid/genericinterface.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitDevice;
class GenericInterface : public DeviceInterface, virtual public Solid::Ifaces::GenericInterface
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::GenericInterface)
public:
GenericInterface(IOKitDevice *device);
virtual ~GenericInterface();
virtual QVariant property(const QString &key) const;
virtual QMap<QString, QVariant> allProperties() const;
virtual bool propertyExists(const QString &key) const;
Q_SIGNALS:
void propertyChanged(const QMap<QString, int> &changes);
void conditionRaised(const QString &condition, const QString &reason);
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_GENERICINTERFACE_H
@@ -0,0 +1,227 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitmanager.h"
#include "iokitdevice.h"
#include <qdebug.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/usb/IOUSBLib.h>
#include <CoreFoundation/CoreFoundation.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitManagerPrivate
{
public:
inline IOKitManagerPrivate()
: port(nullptr)
, source(nullptr)
{
}
IONotificationPortRef port;
CFRunLoopSourceRef source;
static const char *typeToName(Solid::DeviceInterface::Type type);
static QStringList devicesFromRegistry(io_iterator_t it);
QSet<Solid::DeviceInterface::Type> supportedInterfaces;
};
// gets all registry paths from an iterator
QStringList IOKitManagerPrivate::devicesFromRegistry(io_iterator_t it)
{
QStringList result;
io_object_t obj;
while ((obj = IOIteratorNext(it))) {
CFStringRef pathRef = IORegistryEntryCopyPath(obj, kIOServicePlane);
const QString path = QString::fromCFString(pathRef);
CFRelease(pathRef);
if (path.isEmpty()) {
qWarning() << Q_FUNC_INFO << "IORegistryEntryCopyPath failed";
continue;
}
result += path;
const kern_return_t ret = IOObjectRelease(obj);
if (ret != KERN_SUCCESS) {
// very unlikely to happen - keep it a qDebug just in case.
// compiler will nuke this code in release builds.
qDebug() << Q_FUNC_INFO << "Unable to release object reference";
}
}
IOObjectRelease(it);
return result;
}
const char *IOKitManagerPrivate::typeToName(Solid::DeviceInterface::Type type)
{
switch (type) {
case Solid::DeviceInterface::Unknown:
return 0;
case Solid::DeviceInterface::Processor:
return "AppleACPICPU";
case Solid::DeviceInterface::Battery:
return "AppleSmartBattery";
// Solid::DeviceInterface::GenericInterface:
// Solid::DeviceInterface::Block:
case Solid::DeviceInterface::StorageAccess:
case Solid::DeviceInterface::StorageDrive:
case Solid::DeviceInterface::StorageVolume:
return "IOMedia";
case Solid::DeviceInterface::OpticalDrive:
case Solid::DeviceInterface::OpticalDisc:
return "IOCDMedia";
// Solid::DeviceInterface::Camera:
// Solid::DeviceInterface::PortableMediaPlayer:
}
return 0;
}
IOKitManager::IOKitManager(QObject *parent)
: Solid::Ifaces::DeviceManager(parent)
, d(new IOKitManagerPrivate)
{
d->port = IONotificationPortCreate(kIOMasterPortDefault);
if (!d->port) {
qWarning() << Q_FUNC_INFO << "Unable to create notification port";
return;
}
d->source = IONotificationPortGetRunLoopSource(d->port);
if (!d->source) {
qWarning() << Q_FUNC_INFO << "Unable to create notification source";
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), d->source, kCFRunLoopDefaultMode);
// clang-format off
d->supportedInterfaces << Solid::DeviceInterface::GenericInterface
<< Solid::DeviceInterface::Processor
<< Solid::DeviceInterface::Block
<< Solid::DeviceInterface::StorageAccess
<< Solid::DeviceInterface::StorageDrive
<< Solid::DeviceInterface::OpticalDrive
<< Solid::DeviceInterface::StorageVolume
<< Solid::DeviceInterface::OpticalDisc
<< Solid::DeviceInterface::Camera
<< Solid::DeviceInterface::PortableMediaPlayer
<< Solid::DeviceInterface::Battery;
// clang-format on
}
IOKitManager::~IOKitManager()
{
if (d->source) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), d->source, kCFRunLoopDefaultMode);
}
if (d->port) {
IONotificationPortDestroy(d->port);
}
delete d;
}
QString IOKitManager::udiPrefix() const
{
return QString(); // FIXME: We should probably use a prefix there... has to be tested on Mac
}
QSet<Solid::DeviceInterface::Type> IOKitManager::supportedInterfaces() const
{
return d->supportedInterfaces;
}
QStringList IOKitManager::allDevices()
{
// use an IORegistry Iterator to iterate over all devices in the service plane
io_iterator_t it;
kern_return_t ret = IORegistryCreateIterator(kIOMasterPortDefault, kIOServicePlane, kIORegistryIterateRecursively, &it);
if (ret != KERN_SUCCESS) {
qWarning() << Q_FUNC_INFO << "unable to create iterator";
return QStringList();
}
return IOKitManagerPrivate::devicesFromRegistry(it);
}
QStringList IOKitManager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type)
{
QStringList result;
if (type == Solid::DeviceInterface::Unknown) {
// match all device interfaces
result = allDevices();
} else {
const char *deviceClassName = IOKitManagerPrivate::typeToName(type);
if (!deviceClassName) {
return QStringList();
}
CFMutableDictionaryRef matchingDict = IOServiceMatching(deviceClassName);
if (!matchingDict) {
return QStringList();
}
io_iterator_t it = 0;
// note - IOServiceGetMatchingServices dereferences the dict
kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &it);
result = IOKitManagerPrivate::devicesFromRegistry(it);
}
// if the parentUdi is an empty string, return all matches
if (parentUdi.isEmpty()) {
return result;
}
// return only matches that start with the parent's UDI
QStringList filtered;
for (const QString &udi : std::as_const(result)) {
if (udi.startsWith(parentUdi)) {
filtered += udi;
}
}
return filtered;
}
QObject *IOKitManager::createDevice(const QString &udi)
{
CFStringRef path = udi.toCFString();
io_registry_entry_t entry = IORegistryEntryCopyFromPath(kIOMasterPortDefault, path);
CFRelease(path);
// we have to do IOObjectConformsTo - comparing the class names is not good enough
// if (IOObjectConformsTo(entry, kIOEthernetInterfaceClass)) {
//}
if (entry == MACH_PORT_NULL) {
return 0;
}
return new IOKitDevice(udi, entry);
}
}
}
} // namespaces
#include "moc_iokitmanager.cpp"
@@ -0,0 +1,45 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_IOKITMANAGER_H
#define SOLID_BACKENDS_IOKIT_IOKITMANAGER_H
#include <solid/deviceinterface.h>
#include <solid/devices/ifaces/devicemanager.h>
#include <QStringList>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitManagerPrivate;
class IOKitManager : public Solid::Ifaces::DeviceManager
{
Q_OBJECT
public:
IOKitManager(QObject *parent);
virtual ~IOKitManager();
virtual QString udiPrefix() const;
virtual QSet<Solid::DeviceInterface::Type> supportedInterfaces() const;
virtual QStringList allDevices();
virtual QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type);
virtual QObject *createDevice(const QString &udi);
private:
IOKitManagerPrivate *d;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_IOKITMANAGER_H
@@ -0,0 +1,106 @@
/*
SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitopticaldisc.h"
#include <CoreFoundation/CoreFoundation.h>
using namespace Solid::Backends::IOKit;
IOKitOpticalDisc::IOKitOpticalDisc(IOKitDevice *device)
: IOKitVolume(device)
{
}
IOKitOpticalDisc::IOKitOpticalDisc(const IOKitDevice *device)
: IOKitVolume(device)
{
}
IOKitOpticalDisc::~IOKitOpticalDisc()
{
}
QString IOKitOpticalDisc::device() const
{
const QString devName = m_device->property(QLatin1String("BSD Name")).toString();
if (devName.startsWith(QLatin1Char('r'))) {
return QStringLiteral("/dev/") + devName;
} else {
return QStringLiteral("/dev/r") + devName;
}
}
Solid::OpticalDisc::ContentTypes IOKitOpticalDisc::availableContent() const
{
if (fsType() == QStringLiteral("cddafs")) {
return Solid::OpticalDisc::Audio;
}
return Solid::OpticalDisc::Data;
}
Solid::OpticalDisc::DiscType IOKitOpticalDisc::discType() const
{
QString type = m_device->property(QStringLiteral("Type")).toString();
if (type == QLatin1String("CD-ROM")) {
return Solid::OpticalDisc::CdRom;
} else if (type == QLatin1String("CD-R")) {
return Solid::OpticalDisc::CdRecordable;
} else if (type == QLatin1String("CD-RW")) {
return Solid::OpticalDisc::CdRewritable;
} else if (type == QLatin1String("DVD-ROM")) {
return Solid::OpticalDisc::DvdRom;
} else if (type == QLatin1String("DVD-RAM")) {
return Solid::OpticalDisc::DvdRam;
} else if (type == QLatin1String("DVD-R")) {
return Solid::OpticalDisc::DvdRecordable;
} else if (type == QLatin1String("DVD-RW")) {
return Solid::OpticalDisc::DvdRewritable;
} else if (type == QLatin1String("DVD+R")) {
return Solid::OpticalDisc::DvdPlusRecordable;
} else if (type == QLatin1String("DVD+RW")) {
return Solid::OpticalDisc::DvdPlusRewritable;
} else if (type == QLatin1String("BD-ROM")) {
return Solid::OpticalDisc::BluRayRom;
} else if (type == QLatin1String("BD-R")) {
return Solid::OpticalDisc::BluRayRecordable;
} else if (type == QLatin1String("BD-RE")) {
return Solid::OpticalDisc::BluRayRewritable;
} else if (type == QLatin1String("HD DVD-ROM")) {
return Solid::OpticalDisc::HdDvdRom;
} else if (type == QLatin1String("HD DVD-R")) {
return Solid::OpticalDisc::HdDvdRecordable;
} else if (type == QLatin1String("HD DVD-RW")) {
return Solid::OpticalDisc::HdDvdRewritable;
} else {
return Solid::OpticalDisc::UnknownDiscType;
}
}
bool IOKitOpticalDisc::isAppendable() const
{
// TODO!
return isRewritable();
}
bool IOKitOpticalDisc::isBlank() const
{
// TODO!
return isRewritable();
}
bool IOKitOpticalDisc::isRewritable() const
{
return m_device->property(QStringLiteral("Writable")).toBool();
}
qulonglong IOKitOpticalDisc::capacity() const
{
return size();
}
#include "moc_iokitopticaldisc.cpp"
@@ -0,0 +1,44 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_OPTICALDISC_H
#define SOLID_BACKENDS_IOKIT_OPTICALDISC_H
#include "iokitvolume.h"
#include <solid/devices/ifaces/opticaldisc.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitOpticalDisc : public IOKitVolume, virtual public Solid::Ifaces::OpticalDisc
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::OpticalDisc)
public:
IOKitOpticalDisc(IOKitDevice *device);
IOKitOpticalDisc(const IOKitDevice *device);
virtual ~IOKitOpticalDisc();
// overridden from IOKit::Block because optical discs must
// be accessed through the raw device.
QString device() const override;
Solid::OpticalDisc::ContentTypes availableContent() const override;
Solid::OpticalDisc::DiscType discType() const override;
bool isAppendable() const override;
bool isBlank() const override;
bool isRewritable() const override;
qulonglong capacity() const override;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_OPTICALDISC_H
@@ -0,0 +1,343 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitopticaldrive.h"
#include <QDebug>
#include <QProcess>
#ifdef EJECT_USING_DISKARBITRATION
// for QCFType:
#include <private/qcore_mac_p.h>
#else
#include <QStandardPaths>
#endif
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
#include <IOKit/scsi/IOSCSIMultimediaCommandsDevice.h>
using namespace Solid::Backends::IOKit;
class IOKitOpticalDrive::Private
{
public:
Private(const IOKitDevice *device, const QVariantMap &devCharMap)
: m_device(device)
, m_deviceCharacteristics(devCharMap)
{
}
virtual ~Private()
{
}
QVariant property(const QString &key) const
{
return m_deviceCharacteristics.value(key);
}
const IOKitDevice *m_device;
const QVariantMap m_deviceCharacteristics;
static const QMap<Solid::OpticalDrive::MediumType, uint32_t> cdTypeMap;
static const QMap<Solid::OpticalDrive::MediumType, uint32_t> dvdTypeMap;
static const QMap<Solid::OpticalDrive::MediumType, uint32_t> bdTypeMap;
#ifdef EJECT_USING_DISKARBITRATION
// DiskArbitration-based ejection based on the implementation in libcdio's osx.c
// in turn based on VideoLAN (VLC) code.
// Not activated by default ATM because I have only been able to test it with the
// solid-hardware6 utility and that one remains stuck after a successful return
// from IOKitOpticalDrive::eject(). It does so too when using the hdiutil external
// utility which cannot be due to using QProcess (to the best of my knowledge).
// NB: the full-fledged approach using a cancel sourc ref (cancel_signal) etc. may
// well be too complicated.
typedef struct DAContext {
const IOKitDevice *device;
int success;
bool completed;
DASessionRef session;
CFRunLoopRef runloop;
CFRunLoopSourceRef cancel_signal;
} DAContext;
static void cancelEjectRunloop(void *){};
static void daEjectCallback(DADiskRef disk, DADissenterRef dissenter, void *context)
{
Q_UNUSED(disk);
DAContext *daContext = static_cast<DAContext *>(context);
if (dissenter) {
CFStringRef status = DADissenterGetStatusString(dissenter);
if (status) {
qWarning() << "Warning while ejecting" << daContext->device->property("BSD Name").toString() << ":" << QString::fromCFString(status);
CFRelease(status);
}
}
daContext->success = dissenter ? false : true;
daContext->completed = TRUE;
CFRunLoopSourceSignal(daContext->cancel_signal);
CFRunLoopWakeUp(daContext->runloop);
}
static void daUnmountCallback(DADiskRef disk, DADissenterRef dissenter, void *context)
{
DAContext *daContext = (DAContext *)context;
if (!dissenter) {
DADiskEject(disk, kDADiskEjectOptionDefault, daEjectCallback, context);
daContext->success = (daContext->success == -1 ? true : daContext->success);
} else {
daContext->success = false;
daContext->completed = true;
CFRunLoopSourceSignal(daContext->cancel_signal);
CFRunLoopWakeUp(daContext->runloop);
}
}
bool eject(double timeoutSeconds)
{
CFDictionaryRef description = nullptr;
CFRunLoopSourceContext cancelRunLoopSourceContext = {.perform = cancelEjectRunloop};
DAContext daContext = {m_device, -1, false, 0, CFRunLoopGetCurrent(), 0};
QCFType<CFRunLoopSourceRef> cancel = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cancelRunLoopSourceContext);
if (!(daContext.cancel_signal = cancel)) {
qWarning() << Q_FUNC_INFO << "failed to create cancel runloop source";
return false;
}
QCFType<DASessionRef> session = DASessionCreate(kCFAllocatorDefault);
if (!(daContext.session = session)) {
qWarning() << Q_FUNC_INFO << "failed to create DiskArbitration session";
return false;
}
const QString devName = m_device->property(QStringLiteral("BSD Name")).toString();
QCFType<DADiskRef> daRef = DADiskCreateFromBSDName(kCFAllocatorDefault, daContext.session, devName.toStdString().c_str());
if (!daRef) {
qWarning() << Q_FUNC_INFO << "failed to create DiskArbitration reference for" << devName;
return false;
}
description = DADiskCopyDescription(daRef);
if (description) {
DASessionScheduleWithRunLoop(daContext.session, daContext.runloop, kCFRunLoopDefaultMode);
CFRunLoopAddSource(daContext.runloop, daContext.cancel_signal, kCFRunLoopDefaultMode);
if (CFDictionaryGetValueIfPresent(description, kDADiskDescriptionVolumePathKey, nullptr)) {
DADiskUnmount(daRef, kDADiskUnmountOptionWhole, daUnmountCallback, &daContext);
}
DADiskEject(daRef, kDADiskEjectOptionDefault, daEjectCallback, &daContext);
daContext.success = (daContext.success == -1 ? true : daContext.success);
while (!daContext.completed) {
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeoutSeconds, true) == kCFRunLoopRunTimedOut) {
break;
}
}
if (daContext.completed) {
qWarning() << Q_FUNC_INFO << "ejected" << devName;
} else {
qWarning() << Q_FUNC_INFO << "timeout ejecting" << devName;
}
CFRunLoopRemoveSource(daContext.runloop, daContext.cancel_signal, kCFRunLoopDefaultMode);
DASessionSetDispatchQueue(daContext.session, 0);
DASessionUnscheduleFromRunLoop(daContext.session, daContext.runloop, kCFRunLoopDefaultMode);
CFRelease(description);
} else {
qWarning() << Q_FUNC_INFO << "failed to fetch DiskArbitration description for" << devName;
}
return daContext.success == -1 ? false : daContext.success;
}
#endif // EJECT_USING_DISKARBITRATION
};
const QMap<Solid::OpticalDrive::MediumType, uint32_t> IOKitOpticalDrive::Private::cdTypeMap = {
{Solid::OpticalDrive::Cdr, kCDFeaturesWriteOnceMask},
{Solid::OpticalDrive::Cdrw, kCDFeaturesReWriteableMask},
};
const QMap<Solid::OpticalDrive::MediumType, uint32_t> IOKitOpticalDrive::Private::dvdTypeMap = {
{Solid::OpticalDrive::Dvd, kDVDFeaturesReadStructuresMask},
{Solid::OpticalDrive::Dvdr, kDVDFeaturesWriteOnceMask},
{Solid::OpticalDrive::Dvdrw, kDVDFeaturesReWriteableMask},
{Solid::OpticalDrive::Dvdram, kDVDFeaturesRandomWriteableMask},
{Solid::OpticalDrive::Dvdplusr, kDVDFeaturesPlusRMask},
{Solid::OpticalDrive::Dvdplusrw, kDVDFeaturesPlusRWMask},
// not supported:
// {Solid::OpticalDrive::Dvdplusdl, "dvdplusrdl"}
// {Solid::OpticalDrive::Dvdplusdlrw, "dvdplusrwdl"}
{Solid::OpticalDrive::HdDvd, kDVDFeaturesHDReadMask},
{Solid::OpticalDrive::HdDvdr, kDVDFeaturesHDRMask},
{Solid::OpticalDrive::HdDvdrw, kDVDFeaturesHDRWMask},
};
const QMap<Solid::OpticalDrive::MediumType, uint32_t> IOKitOpticalDrive::Private::bdTypeMap = {
{Solid::OpticalDrive::Bd, kBDFeaturesReadMask},
{Solid::OpticalDrive::Bdr, kBDFeaturesWriteMask},
}; // also Solid::OpticalDrive::Bdre
IOKitOpticalDrive::IOKitOpticalDrive(IOKitDevice *device)
: IOKitStorage(device)
{
// walk up the IOKit chain to find the parent that has the "Device Characteristics" property
// In the examples I've seen this is always the 2nd parent but if ever that turns out
// to be non-guaranteed we'll need to do a true walk.
IOKitDevice ioDVDServices(IOKitDevice(device->parentUdi()).parentUdi());
QVariantMap devCharMap;
if (!ioDVDServices.iOKitPropertyExists(QStringLiteral("Device Characteristics"))) {
qWarning() << Q_FUNC_INFO << "Grandparent of" << m_device->udi() << "doesn't have the \"Device Characteristics\" but is" << ioDVDServices.udi();
} else {
const QVariant devCharVar = ioDVDServices.property(QStringLiteral("Device Characteristics"));
devCharMap = devCharVar.toMap();
}
d = new Private(device, devCharMap);
}
IOKitOpticalDrive::~IOKitOpticalDrive()
{
}
/* clang-format off */
// // Example properties: QMap(("BSD Major", QVariant(int, 1))
// ("BSD Minor", QVariant(int, 12))
// ("BSD Name", QVariant(QString, "disk3"))
// ("BSD Unit", QVariant(int, 3))
// ("Content", QVariant(QString, "CD_partition_scheme"))
// ("Content Hint", QVariant(QString, ""))
// ("Ejectable", QVariant(bool, true))
// ("IOBusyInterest", QVariant(QString, "IOCommand is not serializable"))
// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable"))
// ("IOMediaIcon", QVariant(QVariantMap, QMap(("CFBundleIdentifier", QVariant(QString, "com.apple.iokit.IOCDStorageFamily"))
// ("IOBundleResourceFile", QVariant(QString, "CD.icns")))))
// ("Leaf", QVariant(bool, false))
// ("Open", QVariant(bool, true))
// ("Preferred Block Size", QVariant(qlonglong, 2352))
// ("Removable", QVariant(bool, true))
// ("Size", QVariant(qlonglong, 750932448))
// ("TOC", QVariant(QByteArray, "\x00\xA7\x01\x01\x01\x10\x00\xA0\x00\x00\x00\x00\x01\x00\x00\x01\x12\x00\xA1\x00\x00\x00\x00\f\x00\x00\x01\x12\x00\xA2\x00\x00\x00\x00""F:J\x01\x12\x00\x01\x00\x00\x00\x00\x00\x02\x00\x01\x12\x00\x02\x00\x00\x00\x00\x07/\b\x01\x12\x00\x03\x00\x00\x00\x00\x12\b\x0E\x01\x12\x00\x04\x00\x00\x00\x00\x17\x12""0\x01\x12\x00\x05\x00\x00\x00\x00\x1B+ \x01\x12\x00\x06\x00\x00\x00\x00 \x11\n\x01\x12\x00\x07\x00\x00\x00\x00!-\n\x01\x12\x00\b\x00\x00\x00\x00'\f\x1F\x01\x12\x00\t\x00\x00\x00\x00-\x13;\x01\x12\x00\n\x00\x00\x00\x00""4%\x1E\x01\x12\x00\x0B\x00\x00\x00\x00""62 \x01\x12\x00\f\x00\x00\x00\x00""C\x06""E"))
// ("Type", QVariant(QString, "CD-ROM"))
// ("Whole", QVariant(bool, true))
// ("Writable", QVariant(bool, false))
// ("className", QVariant(QString, "IOCDMedia")))
// // related useful entry: QMap(("Device Characteristics", QVariant(QVariantMap, QMap(("Async Notification", QVariant(bool, false))
// ("BD Features", QVariant(int, 0))
// ("CD Features", QVariant(int, 2047))
// ("DVD Features", QVariant(int, 503))
// ("Fast Spindown", QVariant(bool, true))
// ("Loading Mechanism", QVariant(QString, "Slot"))
// ("Low Power Polling", QVariant(bool, false))
// ("Power Off", QVariant(bool, true))
// ("Product Name", QVariant(QString, "DVD-R UJ-8A8"))
// ("Product Revision Level", QVariant(QString, "HA13"))
// ("Vendor Name", QVariant(QString, "MATSHITA")))))
// ("IOCFPlugInTypes", QVariant(QVariantMap, QMap(("97ABCF2C-23CC-11D5-A0E8-003065704866", QVariant(QString, "IOSCSIArchitectureModelFamily.kext/Contents/PlugIns/SCSITaskUserClient.kext/Contents/PlugIns/SCSITaskLib.plugin")))))
// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable"))
// ("IOMatchCategory", QVariant(QString, "SCSITaskUserClientIniter"))
// ("IOMinimumSegmentAlignmentByteCount", QVariant(qlonglong, 4))
// ("IOUserClientClass", QVariant(QString, "SCSITaskUserClient"))
// ("Protocol Characteristics", QVariant(QVariantMap, QMap(("AHCI Port Number", QVariant(qlonglong, 0))
// ("ATAPI", QVariant(bool, true))
// ("Physical Interconnect", QVariant(QString, "SATA"))
// ("Physical Interconnect Location", QVariant(QString, "Internal"))
// ("Port Speed", QVariant(QString, "1.5 Gigabit"))
// ("Read Time Out Duration", QVariant(qlonglong, 15000))
// ("Retry Count", QVariant(qlonglong, 1))
// ("Write Time Out Duration", QVariant(qlonglong, 15000)))))
// ("SCSITaskDeviceCategory", QVariant(QString, "SCSITaskAuthoringDevice"))
// ("SCSITaskUserClient GUID", QVariant(QByteArray, "\x00]\x0F""F\x80\xFF\xFF\xFFg\xB6\xAB\x1B\x00\x00\x00\x00"))
// ("className", QVariant(QString, "IODVDServices"))
// ("device-type", QVariant(QString, "DVD")))
// // QMap(("CFBundleIdentifier", QVariant(QString, "com.apple.iokit.IODVDStorageFamily"))
// ("IOClass", QVariant(QString, "IODVDBlockStorageDriver"))
// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable"))
// ("IOMatchCategory", QVariant(QString, "IODefaultMatchCategory"))
// ("IOProbeScore", QVariant(int, 0))
// ("IOPropertyMatch", QVariant(QVariantMap, QMap(("device-type", QVariant(QString, "DVD")))))
// ("IOProviderClass", QVariant(QString, "IODVDBlockStorageDevice"))
// ("Statistics", QVariant(QVariantMap, QMap(("Bytes (Read)", QVariant(qlonglong, 578020608))
// ("Bytes (Write)", QVariant(qlonglong, 0))
// ("Errors (Read)", QVariant(qlonglong, 0))
// ("Errors (Write)", QVariant(qlonglong, 0))
// ("Latency Time (Read)", QVariant(qlonglong, 0))
// ("Latency Time (Write)", QVariant(qlonglong, 0))
// ("Operations (Read)", QVariant(qlonglong, 18475))
// ("Operations (Write)", QVariant(qlonglong, 0))
// ("Retries (Read)", QVariant(qlonglong, 0))
// ("Retries (Write)", QVariant(qlonglong, 0))
// ("Total Time (Read)", QVariant(qlonglong, 219944025102))
// ("Total Time (Write)", QVariant(qlonglong, 0)))))
// ("className", QVariant(QString, "IODVDBlockStorageDriver")))
/* clang-format on */
Solid::OpticalDrive::MediumTypes IOKitOpticalDrive::supportedMedia() const
{
Solid::OpticalDrive::MediumTypes supported;
uint32_t cdFeatures = d->property(QStringLiteral("CD Features")).toInt();
uint32_t dvdFeatures = d->property(QStringLiteral("DVD Features")).toInt();
uint32_t bdFeatures = d->property(QStringLiteral("BD Features")).toInt();
qDebug() << Q_FUNC_INFO << "cdFeatures" << cdFeatures << "dvdFeatures" << dvdFeatures << "bdFeatures" << bdFeatures;
for (auto it = d->cdTypeMap.cbegin(); it != d->cdTypeMap.cend(); ++it) {
if (cdFeatures & it.value()) {
supported |= it.key();
}
}
for (auto it = d->dvdTypeMap.cbegin(); it != d->dvdTypeMap.cend(); ++it) {
if (dvdFeatures & it.value()) {
supported |= it.key();
}
}
for (auto it = d->bdTypeMap.cbegin(); it != d->bdTypeMap.cend(); ++it) {
const uint32_t value = it.value();
if (bdFeatures & value) {
supported |= it.key();
if (value == kBDFeaturesWriteMask) {
supported |= Solid::OpticalDrive::Bdre;
}
}
}
return supported;
}
int IOKitOpticalDrive::readSpeed() const
{
return 0;
}
int IOKitOpticalDrive::writeSpeed() const
{
return 0;
}
QList<int> IOKitOpticalDrive::writeSpeeds() const
{
return {};
}
bool IOKitOpticalDrive::eject()
{
#ifdef EJECT_USING_DISKARBITRATION
// give the devices 30 seconds to eject
int error = !d->eject(30.0);
#else
QProcess ejectJob;
int error = ejectJob.execute(
QStandardPaths::findExecutable(QStringLiteral("hdiutil")), //
{QStringLiteral("detach"), QStringLiteral("-verbose"), QStringLiteral("/dev/") + m_device->property(QStringLiteral("BSD Name")).toString()});
if (error) {
qWarning() << "hdiutil returned" << error << "trying to eject" << m_device->product();
}
#endif // EJECT_USING_DISKARBITRATION
if (error) {
Q_EMIT ejectDone(Solid::ErrorType::OperationFailed, QVariant(), m_device->udi());
return false;
} else {
Q_EMIT ejectDone(Solid::ErrorType::NoError, QVariant(), m_device->udi());
return true;
}
}
#include "moc_iokitopticaldrive.cpp"
@@ -0,0 +1,48 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H
#define SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H
#include "iokitstorage.h"
#include <solid/devices/ifaces/opticaldrive.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitOpticalDrive : public IOKitStorage, virtual public Solid::Ifaces::OpticalDrive
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::OpticalDrive)
public:
explicit IOKitOpticalDrive(IOKitDevice *device);
virtual ~IOKitOpticalDrive();
public Q_SLOTS:
Solid::OpticalDrive::MediumTypes supportedMedia() const override;
int readSpeed() const override;
int writeSpeed() const override;
QList<int> writeSpeeds() const override;
bool eject() override;
Q_SIGNALS:
void ejectPressed(const QString &udi) override;
void ejectDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
void ejectRequested(const QString &udi);
private:
class Private;
Private *d;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H
@@ -0,0 +1,86 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitprocessor.h"
#include "iokitdevice.h"
#include <qdebug.h>
#include <errno.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include "../shared/cpufeatures.h"
// from cfhelper.cpp
extern bool q_sysctlbyname(const char *name, QString &result);
using namespace Solid::Backends::IOKit;
Processor::Processor(IOKitDevice *device)
: DeviceInterface(device)
{
// IOKitDevice parent(device->parentUdi());
}
Processor::~Processor()
{
}
int Processor::number() const
{
return m_device->property(QLatin1String("IOCPUNumber")).toInt();
}
int Processor::maxSpeed() const
{
uint64_t freq = 0;
size_t size = sizeof(freq);
if (sysctlbyname("hw.cpufrequency", &freq, &size, nullptr, 0) < 0) {
qWarning() << "sysctl error reading hw.cpufrequency:" << strerror(errno);
return 0;
} else {
return int(freq / 1000000);
}
}
bool Processor::canChangeFrequency() const
{
uint64_t minFreq = 0, maxFreq = 0;
size_t size = sizeof(uint64_t);
if (sysctlbyname("hw.cpufrequency_min", &minFreq, &size, nullptr, 0) == 0 //
&& sysctlbyname("hw.cpufrequency_max", &maxFreq, &size, nullptr, 0) == 0) {
return maxFreq > minFreq;
}
return false;
}
Solid::Processor::InstructionSets Processor::instructionSets() const
{
// use sysctlbyname() and "machdep.cpu.features" + "machdep.cpu.extfeatures"
static Solid::Processor::InstructionSets cpuextensions = Solid::Backends::Shared::cpuFeatures();
return cpuextensions;
}
QString Processor::vendor()
{
QString qVendor;
q_sysctlbyname("machdep.cpu.vendor", qVendor);
return qVendor;
}
QString Processor::product()
{
QString product;
q_sysctlbyname("machdep.cpu.brand_string", product);
return product;
}
#include "moc_iokitprocessor.cpp"
@@ -0,0 +1,41 @@
/*
SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_PROCESSOR_H
#define SOLID_BACKENDS_IOKIT_PROCESSOR_H
#include "iokitdeviceinterface.h"
#include <solid/devices/ifaces/processor.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitDevice;
class Processor : public DeviceInterface, virtual public Solid::Ifaces::Processor
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::Processor)
public:
Processor(IOKitDevice *device);
virtual ~Processor();
int number() const override;
int maxSpeed() const override;
bool canChangeFrequency() const override;
Solid::Processor::InstructionSets instructionSets() const override;
static QString vendor();
static QString product();
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_PROCESSOR_H
@@ -0,0 +1,106 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitstorage.h"
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
using namespace Solid::Backends::IOKit;
IOKitStorage::IOKitStorage(IOKitDevice *device)
: Block(device)
, daDict(new DADictionary(device))
{
}
IOKitStorage::IOKitStorage(const IOKitDevice *device)
: Block(device)
, daDict(new DADictionary(device))
{
}
IOKitStorage::~IOKitStorage()
{
delete daDict;
}
Solid::StorageDrive::Bus IOKitStorage::bus() const
{
const QString udi = m_device->udi();
// TODO: figure out how to return something useful here.
if (udi.contains(QStringLiteral("/SATA@"))) {
return Solid::StorageDrive::Sata;
}
if (udi.contains(QStringLiteral("/SDXC@"))) {
// TODO: return something finer grained; the built-in card reader
// is NOT connected via USB on Macs, for instance (but there's no PCI option)
return Solid::StorageDrive::Usb;
}
if (udi.contains(QStringLiteral("/IOUSBInterface@"))) {
return Solid::StorageDrive::Usb;
}
if (daDict->stringForKey(kDADiskDescriptionDeviceProtocolKey) == QStringLiteral("USB")) {
return Solid::StorageDrive::Usb;
}
return Solid::StorageDrive::Platform;
}
Solid::StorageDrive::DriveType IOKitStorage::driveType() const
{
const QString udi = m_device->udi();
const QString type = m_device->property(QLatin1String("className")).toString();
if (type == QStringLiteral("IOCDMedia") //
|| type == QStringLiteral("IOBDMedia") //
|| type == QStringLiteral("IODVDMedia")) {
return Solid::StorageDrive::CdromDrive;
}
if (udi.contains(QStringLiteral("/SDXC@"))) {
return Solid::StorageDrive::SdMmc;
}
if (daDict->stringForKey(kDADiskDescriptionDeviceModelKey) == QStringLiteral("Compact Flash")) {
return Solid::StorageDrive::CompactFlash;
}
return Solid::StorageDrive::HardDisk;
}
bool IOKitStorage::isRemovable() const
{
bool isInternal = false;
daDict->boolForKey(kDADiskDescriptionDeviceInternalKey, isInternal);
return !isInternal || m_device->property(QLatin1String("Removable")).toBool();
}
bool IOKitStorage::isHotpluggable() const
{
const Solid::StorageDrive::DriveType type = driveType();
return bus() == Solid::StorageDrive::Usb //
|| type == Solid::StorageDrive::CdromDrive //
|| type == Solid::StorageDrive::SdMmc;
}
qulonglong IOKitStorage::size() const
{
return m_device->property(QLatin1String("Size")).toULongLong();
}
QString IOKitStorage::vendor() const
{
return daDict->stringForKey(kDADiskDescriptionDeviceVendorKey);
}
QString IOKitStorage::product() const
{
return daDict->stringForKey(kDADiskDescriptionDeviceModelKey);
}
QString IOKitStorage::description() const
{
return daDict->stringForKey(kDADiskDescriptionMediaNameKey);
}
#include "moc_iokitstorage.cpp"
@@ -0,0 +1,50 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H
#define SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H
#include "dadictionary_p.h"
#include "iokitblock.h"
#include <solid/devices/ifaces/storagedrive.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitStorage : public Block, virtual public Solid::Ifaces::StorageDrive
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageDrive)
public:
explicit IOKitStorage(IOKitDevice *device);
explicit IOKitStorage(const IOKitDevice *device);
~IOKitStorage();
QString vendor() const;
QString product() const;
QString description() const;
public Q_SLOTS:
Solid::StorageDrive::Bus bus() const override;
Solid::StorageDrive::DriveType driveType() const override;
bool isRemovable() const override;
bool isHotpluggable() const override;
qulonglong size() const override;
private:
DADictionary *daDict;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H
@@ -0,0 +1,99 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitstorageaccess.h"
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
using namespace Solid::Backends::IOKit;
IOKitStorageAccess::IOKitStorageAccess(IOKitDevice *device)
: DeviceInterface(device)
, daDict(new DADictionary(device))
{
connect(device, SIGNAL(propertyChanged(QMap<QString, int>)), this, SLOT(onPropertyChanged(QMap<QString, int>)));
}
IOKitStorageAccess::IOKitStorageAccess(const IOKitDevice *device)
: DeviceInterface(device)
, daDict(new DADictionary(device))
{
connect(device, SIGNAL(propertyChanged(QMap<QString, int>)), this, SLOT(onPropertyChanged(QMap<QString, int>)));
}
IOKitStorageAccess::~IOKitStorageAccess()
{
delete daDict;
}
bool IOKitStorageAccess::isAccessible() const
{
filePath();
const QVariant isMounted = m_device->property(QStringLiteral("isMounted"));
return isMounted.isValid() && isMounted.toBool();
}
QString IOKitStorageAccess::filePath() const
{
// mount points can change (but can they between invocations of filePath()?)
QString mountPoint;
if (const CFURLRef urlRef = daDict->cfUrLRefForKey(kDADiskDescriptionVolumePathKey)) {
const CFStringRef mpRef = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
mountPoint = QString::fromCFString(mpRef);
CFRelease(mpRef);
m_device->setProperty("mountPoint", QVariant(mountPoint));
bool isMounted = !mountPoint.isEmpty();
const QString isMountedKey = QStringLiteral("isMounted");
const QVariant wasMounted = m_device->property(isMountedKey);
if (wasMounted.isValid() && wasMounted.toBool() != isMounted) {
IOKitStorageAccess(m_device).onPropertyChanged(QMap<QString, int>{{isMountedKey, isMounted}});
}
m_device->setProperty("isMounted", QVariant(isMounted));
}
return mountPoint;
}
bool IOKitStorageAccess::isIgnored() const
{
if (m_device->iOKitPropertyExists(QStringLiteral("Open"))) {
// ignore storage volumes that aren't mounted
bool isIgnored = m_device->property(QStringLiteral("Open")).toBool() == false;
m_device->setProperty("isIgnored", QVariant(isIgnored));
return isIgnored;
}
const QVariant isIgnored = m_device->property(QStringLiteral("isIgnored"));
return isIgnored.isValid() && isIgnored.toBool();
}
bool IOKitStorageAccess::isEncrypted() const
{
// TODO: Implementation left for IOKit developer
return false;
}
bool IOKitStorageAccess::setup()
{
// TODO?
return false;
}
bool IOKitStorageAccess::teardown()
{
// TODO?
return false;
}
void IOKitStorageAccess::onPropertyChanged(const QMap<QString, int> &changes)
{
for (auto it = changes.cbegin(); it != changes.cend(); ++it) {
if (it.key() == QLatin1String("isMounted")) {
Q_EMIT accessibilityChanged(m_device->property(QStringLiteral("isMounted")).toBool(), m_device->udi());
}
}
}
#include "moc_iokitstorageaccess.cpp"
@@ -0,0 +1,55 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_STORAGEACCESS_H
#define SOLID_BACKENDS_IOKIT_STORAGEACCESS_H
#include "dadictionary_p.h"
#include "iokitdeviceinterface.h"
#include <solid/devices/ifaces/storageaccess.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitStorageAccess : public DeviceInterface, virtual public Solid::Ifaces::StorageAccess
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageAccess)
public:
IOKitStorageAccess(IOKitDevice *device);
IOKitStorageAccess(const IOKitDevice *device);
virtual ~IOKitStorageAccess();
bool isAccessible() const override;
QString filePath() const override;
bool isIgnored() const override;
bool isEncrypted() const override;
public Q_SLOTS:
bool setup() override;
bool teardown() override;
Q_SIGNALS:
void accessibilityChanged(bool accessible, const QString &udi) override;
void setupDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
void teardownDone(Solid::ErrorType error, QVariant errorData, const QString &udi) override;
void setupRequested(const QString &udi) override;
void teardownRequested(const QString &udi) override;
private Q_SLOTS:
void onPropertyChanged(const QMap<QString, int> &changes);
private:
DADictionary *daDict;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_STORAGEACCESS_H
@@ -0,0 +1,98 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "iokitvolume.h"
#include "iokitgenericinterface.h"
#include <CoreFoundation/CoreFoundation.h>
using namespace Solid::Backends::IOKit;
IOKitVolume::IOKitVolume(IOKitDevice *device)
: Block(device)
, daDict(new DADictionary(device))
{
}
IOKitVolume::IOKitVolume(const IOKitDevice *device)
: Block(device)
, daDict(new DADictionary(device))
{
}
IOKitVolume::~IOKitVolume()
{
delete daDict;
}
bool IOKitVolume::isIgnored() const
{
// ignore storage volumes that aren't mounted
bool isIgnored = m_device->property(QStringLiteral("Open")).toBool() == false;
m_device->setProperty("isIgnored", isIgnored);
m_device->setProperty("isMounted", !isIgnored);
return isIgnored;
}
Solid::StorageVolume::UsageType IOKitVolume::usage() const
{
const QString content = m_device->property(QStringLiteral("Content")).toString();
if (content == QStringLiteral("CD_DA")) {
// this is (probably) a CD track
return Solid::StorageVolume::Other;
}
if (content.contains(QStringLiteral("partition_scheme"))) {
return Solid::StorageVolume::PartitionTable;
}
return Solid::StorageVolume::FileSystem;
}
QString IOKitVolume::fsType() const
{
return daDict->stringForKey(kDADiskDescriptionVolumeKindKey);
}
QString IOKitVolume::label() const
{
return daDict->stringForKey(kDADiskDescriptionVolumeNameKey);
}
QString IOKitVolume::uuid() const
{
return m_device->property(QStringLiteral("UUID")).toString();
}
qulonglong IOKitVolume::size() const
{
return m_device->property(QStringLiteral("Size")).toULongLong();
}
QString IOKitVolume::encryptedContainerUdi() const
{
return QString();
}
QString IOKitVolume::vendor() const
{
return daDict->stringForKey(kDADiskDescriptionDeviceVendorKey);
}
QString IOKitVolume::product() const
{
return daDict->stringForKey(kDADiskDescriptionDeviceModelKey);
}
QString IOKitVolume::description() const
{
return daDict->stringForKey(kDADiskDescriptionMediaNameKey);
}
DADiskRef IOKitVolume::daRef() const
{
return daDict->daRef;
}
#include "moc_iokitvolume.cpp"
@@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_IOKIT_VOLUME_H
#define SOLID_BACKENDS_IOKIT_VOLUME_H
#include "dadictionary_p.h"
#include "iokitblock.h"
#include <solid/devices/ifaces/storagevolume.h>
#include <DiskArbitration/DiskArbitration.h>
namespace Solid
{
namespace Backends
{
namespace IOKit
{
class IOKitVolume : public Block, virtual public Solid::Ifaces::StorageVolume
{
Q_OBJECT
Q_INTERFACES(Solid::Ifaces::StorageVolume)
public:
IOKitVolume(IOKitDevice *device);
IOKitVolume(const IOKitDevice *device);
virtual ~IOKitVolume();
bool isIgnored() const override;
Solid::StorageVolume::UsageType usage() const override;
QString fsType() const override;
QString label() const override;
QString uuid() const override;
qulonglong size() const override;
QString encryptedContainerUdi() const override;
QString vendor() const;
QString product() const;
QString description() const;
DADiskRef daRef() const;
private:
DADictionary *daDict;
};
}
}
}
#endif // SOLID_BACKENDS_IOKIT_VOLUME_H
@@ -0,0 +1,228 @@
/*
SPDX-FileCopyrightText: 2010 Kevin Ottens <ervin@kde.org>
SPDX-FileCopyrightText: 2013 Patrick Spendrin <ps_ml@gmx.de>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
// clang-format off
#include "cpufeatures.h"
#ifndef _MSC_VER
//for cpuFeatures
#include <csignal>
#include <csetjmp>
#else
#include <intrin.h>
#endif
#include <config-processor.h>
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
# define HAVE_GNU_INLINE_ASM
#endif
namespace Solid
{
namespace Backends
{
namespace Shared
{
#ifndef _MSC_VER
typedef void (*kde_sighandler_t)(int);
#if defined( __i386__ ) || defined( __x86_64__ )
static jmp_buf env;
#if HAVE_X86_SSE
// Sighandler for the SSE OS support check
static void sighandler(int)
{
std::longjmp(env, 1);
}
#endif
#endif
#ifdef __i386__
#define ASM_REG(reg) "%e" reg
#define ASM_POP(reg) "popl %%e" reg " \n\t"
#define ASM_PUSH(reg) "pushl %%e" reg " \n\t"
#define ASM_XOR_REG(reg1, reg2) "xorl %%e" reg1 ", %%e" reg2 " \n\t"
#define ASM_XOR_VAR(var, reg) "xorl " var ", %%e" reg " \n\t"
#define ASM_CMP_REG(reg1, reg2) "cmpl %%e" reg1 ", %%e" reg2 " \n\t"
#define ASM_MOV_REG(reg1, reg2) "movl %%e" reg1 ", %%e" reg2 " \n\t"
#define ASM_MOV_VAR(var, reg) "movl " var ", %%e" reg " \n\t"
#elif defined(__x86_64__)
#define ASM_REG(reg) "%r" reg
#define ASM_POP(reg) "popq %%r" reg " \n\t"
#define ASM_PUSH(reg) "pushq %%r" reg " \n\t"
#define ASM_XOR_REG(reg1, reg2) "xorq %%r" reg1 ", %%r" reg2 " \n\t"
#define ASM_XOR_VAR(var, reg) "xorq " var ", %%r" reg " \n\t"
#define ASM_CMP_REG(reg1, reg2) "cmpq %%r" reg1 ", %%r" reg2 " \n\t"
#define ASM_MOV_REG(reg1, reg2) "movq %%r" reg1 ", %%r" reg2 " \n\t"
#define ASM_MOV_VAR(var, reg) "movq " var ", %%r" reg " \n\t"
#endif
#endif
#ifdef __PPC__
static sigjmp_buf jmpbuf;
static sig_atomic_t canjump = 0;
static void sigill_handler(int sig)
{
if (!canjump) {
signal(sig, SIG_DFL);
raise(sig);
}
canjump = 0;
siglongjmp(jmpbuf, 1);
}
#endif
Solid::Processor::InstructionSets cpuFeatures()
{
volatile unsigned int features = 0;
#if defined( HAVE_GNU_INLINE_ASM )
#if defined( __i386__ ) || defined( __x86_64__ )
bool haveCPUID = false;
unsigned int result = 0;
unsigned int result2 = 0;
// First check if the CPU supports the CPUID instruction
__asm__ __volatile__(
// Try to toggle the CPUID bit in the EFLAGS register
"pushf \n\t" // Push the EFLAGS register onto the stack
ASM_POP("cx") // Pop the value into ECX
ASM_MOV_REG("cx", "dx") // Copy ECX to EDX
ASM_XOR_VAR("$0x00200000", "cx") // Toggle bit 21 (CPUID) in ECX
ASM_PUSH("cx") // Push the modified value onto the stack
"popf \n\t" // Pop it back into EFLAGS
// Check if the CPUID bit was successfully toggled
"pushf \n\t" // Push EFLAGS back onto the stack
ASM_POP("cx") // Pop the value into ECX
ASM_XOR_REG("ax", "ax") // Zero out the EAX register
ASM_CMP_REG("cx", "dx") // Compare ECX with EDX
"je .Lno_cpuid_support%= \n\t" // Jump if they're identical
ASM_MOV_VAR("$1", "ax") // Set EAX to true
".Lno_cpuid_support%=: \n\t"
: "=a"(haveCPUID) : : ASM_REG("cx"), ASM_REG("dx"));
// If we don't have CPUID we won't have the other extensions either
if (haveCPUID) {
// Execute CPUID with the feature request bit set
__asm__ __volatile__(
ASM_PUSH("bx") // Save EBX
ASM_MOV_VAR("$1", "ax") // Set EAX to 1 (features request)
"cpuid \n\t" // Call CPUID
ASM_POP("bx") // Restore EBX
: "=d"(result), "=c"(result2) : : ASM_REG("ax"));
features = result & 0x06800000; //copy the mmx and sse & sse2 bits to features
features |= result2 & 0x00180101; //copy the ssse3, sse3 and sse4.1, sse4.2 bits to features
__asm__ __volatile__(
ASM_PUSH("bx")
ASM_PUSH("dx")
ASM_MOV_VAR("$0x80000000", "ax")
ASM_MOV_VAR("$0x80000000", "dx")
"cpuid \n\t"
ASM_CMP_REG("dx", "ax")
"jbe .Lno_extended%= \n\t"
ASM_MOV_VAR("$0x80000001", "ax")
"cpuid \n\t"
".Lno_extended%=: \n\t"
ASM_POP("dx")
ASM_POP("bx") // Restore EBX
: "=d"(result) : : ASM_REG("ax"), ASM_REG("cx"));
if (result & 0x80000000) {
features |= 0x80000000;
}
#if HAVE_X86_SSE
// Test bit 25 (SSE support)
if (features & 0x02000000) {
// OS support test for SSE.
// Install our own sighandler for SIGILL.
kde_sighandler_t oldhandler = std::signal(SIGILL, sighandler);
// Try executing an SSE insn to see if we get a SIGILL
if (setjmp(env)) {
features &= ~0x06080001; // The OS support test failed
} else {
__asm__ __volatile__("xorps %xmm0, %xmm0");
}
// Restore the default sighandler
std::signal(SIGILL, oldhandler);
// Note: The OS requirements for SSE2 are the same as for SSE
// so we don't have to do any additional tests for that.
}
#endif // HAVE_X86_SSE
}
#elif defined __PPC__ && HAVE_PPC_ALTIVEC
signal(SIGILL, sigill_handler);
if (sigsetjmp(jmpbuf, 1)) {
signal(SIGILL, SIG_DFL);
} else {
canjump = 1;
__asm__ __volatile__("mtspr 256, %0\n\t"
"vand %%v0, %%v0, %%v0"
: /* none */
: "r"(-1));
signal(SIGILL, SIG_DFL);
features = 0x2;
}
#endif // __i386__ || __x86_64__
#elif defined(_MSC_VER)
int array[4], ft = 1;
__cpuid(array, ft);
features = array[3] & 0x06800000; //copy the mmx and sse & sse2 bits to features
features |= array[2] & 0x00180101; //copy the ssse3, sse3 and sse4.1, sse4.2 bits to features
if (array[3] & 0x80000000) {
features |= 0x80000000;
}
#endif //HAVE_GNU_INLINE_ASM
Solid::Processor::InstructionSets featureflags;
if (features & 0x80000000) {
featureflags |= Solid::Processor::Amd3DNow;
}
if (features & 0x00800000) {
featureflags |= Solid::Processor::IntelMmx;
}
if (features & 0x02000000) {
featureflags |= Solid::Processor::IntelSse;
}
if (features & 0x04000000) {
featureflags |= Solid::Processor::IntelSse2;
}
if (features & 0x00000001) {
featureflags |= Solid::Processor::IntelSse3;
}
if (features & 0x00000100) {
featureflags |= Solid::Processor::IntelSsse3;
}
if (features & 0x00080000) {
featureflags |= Solid::Processor::IntelSse41;
}
if (features & 0x00100000) {
featureflags |= Solid::Processor::IntelSse42;
}
if (features & 0x2) {
featureflags |= Solid::Processor::AltiVec;
}
return featureflags;
}
}
}
}
@@ -0,0 +1,24 @@
/*
SPDX-FileCopyrightText: 2010 Rafael Fernández López <ereslibre@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef CPUFEATURES_H
#define CPUFEATURES_H
#include <solid/processor.h>
namespace Solid
{
namespace Backends
{
namespace Shared
{
Solid::Processor::InstructionSets cpuFeatures();
}
}
}
#endif // CPUFEATURES_H
@@ -0,0 +1,93 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "rootdevice.h"
using namespace Solid::Backends::Shared;
RootDevice::RootDevice(const QString &udi, const QString &parentUdi)
: Solid::Ifaces::Device()
, m_udi(udi)
, m_parentUdi(parentUdi)
, m_vendor(QStringLiteral("KDE"))
{
}
RootDevice::~RootDevice()
{
}
QString RootDevice::udi() const
{
return m_udi;
}
QString RootDevice::parentUdi() const
{
return m_parentUdi;
}
QString RootDevice::vendor() const
{
return m_vendor;
}
void RootDevice::setVendor(const QString &vendor)
{
m_vendor = vendor;
}
QString RootDevice::product() const
{
return m_product;
}
void RootDevice::setProduct(const QString &product)
{
m_product = product;
}
QString RootDevice::icon() const
{
return m_icon;
}
void RootDevice::setIcon(const QString &icon)
{
m_icon = icon;
}
QStringList RootDevice::emblems() const
{
return m_emblems;
}
void RootDevice::setEmblems(const QStringList &emblems)
{
m_emblems = emblems;
}
QString RootDevice::description() const
{
return m_description;
}
void RootDevice::setDescription(const QString &description)
{
m_description = description;
}
bool RootDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &) const
{
return false;
}
QObject *RootDevice::createDeviceInterface(const Solid::DeviceInterface::Type &)
{
return nullptr;
}
#include "moc_rootdevice.cpp"
@@ -0,0 +1,64 @@
/*
SPDX-FileCopyrightText: 2010 Mario Bensi <mbensi@ipsquad.net>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef SOLID_BACKENDS_SHARED_ROOT_DEVICE_H
#define SOLID_BACKENDS_SHARED_ROOT_DEVICE_H
#include <solid/devices/ifaces/device.h>
#include <QStringList>
namespace Solid
{
namespace Backends
{
namespace Shared
{
class RootDevice : public Solid::Ifaces::Device
{
Q_OBJECT
public:
explicit RootDevice(const QString &udi, const QString &parentUdi = QString());
~RootDevice() override;
QString udi() const override;
QString parentUdi() const override;
QString vendor() const override;
void setVendor(const QString &vendor);
QString product() const override;
void setProduct(const QString &product);
QString icon() const override;
void setIcon(const QString &icon);
QStringList emblems() const override;
void setEmblems(const QStringList &emblems);
QString description() const override;
void setDescription(const QString &description);
bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const override;
QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) override;
private:
QString m_udi;
QString m_parentUdi;
QString m_vendor;
QString m_product;
QString m_icon;
QStringList m_emblems;
QString m_description;
};
}
}
}
#endif
@@ -0,0 +1,7 @@
#ifndef UDEVQT_H
#define UDEVQT_H
#include "udevqtclient.h"
#include "udevqtdevice.h"
#endif
@@ -0,0 +1,67 @@
/*
SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef UDEVQT_P_H
#define UDEVQT_P_H
extern "C" {
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <libudev.h>
}
class QByteArray;
class QSocketNotifier;
namespace UdevQt
{
class DevicePrivate
{
public:
DevicePrivate(struct udev_device *udev_, bool ref = true);
~DevicePrivate();
DevicePrivate &operator=(const DevicePrivate &other);
QString decodePropertyValue(const QByteArray &encoded) const;
struct udev_device *udev;
};
class Client;
class ClientPrivate
{
public:
enum ListenToWhat { ListenToList, ListenToNone };
ClientPrivate(Client *q_);
~ClientPrivate();
void init(const QStringList &subsystemList, ListenToWhat what);
void setWatchedSubsystems(const QStringList &subsystemList);
void dispatchEvent();
DeviceList deviceListFromEnumerate(struct udev_enumerate *en);
struct udev *udev;
struct udev_monitor *monitor;
Client *q;
QSocketNotifier *monitorNotifier;
QStringList watchedSubsystems;
};
inline QStringList listFromListEntry(struct udev_list_entry *list)
{
QStringList ret;
struct udev_list_entry *entry;
udev_list_entry_foreach(entry, list)
{
ret << QString::fromLatin1(udev_list_entry_get_name(entry));
}
return ret;
}
}
#endif
@@ -0,0 +1,282 @@
/*
SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "udevqtclient.h"
#include "udevqt_p.h"
#include "devices_debug.h"
#include <QSocketNotifier>
#include <qplatformdefs.h>
namespace UdevQt
{
ClientPrivate::ClientPrivate(Client *q_)
: udev(nullptr)
, monitor(nullptr)
, q(q_)
, monitorNotifier(nullptr)
{
}
ClientPrivate::~ClientPrivate()
{
udev_unref(udev);
delete monitorNotifier;
if (monitor) {
udev_monitor_unref(monitor);
}
}
void ClientPrivate::init(const QStringList &subsystemList, ListenToWhat what)
{
udev = udev_new();
if (what != ListenToNone) {
setWatchedSubsystems(subsystemList);
}
}
void ClientPrivate::setWatchedSubsystems(const QStringList &subsystemList)
{
// create a listener
struct udev_monitor *newM = udev_monitor_new_from_netlink(udev, "udev");
if (!newM) {
qWarning("UdevQt: unable to create udev monitor connection");
return;
}
// apply our filters; an empty list means listen to everything
for (const QString &subsysDevtype : subsystemList) {
int ix = subsysDevtype.indexOf(QLatin1String("/"));
if (ix > 0) {
QByteArray subsystem = subsysDevtype.left(ix).toLatin1();
QByteArray devType = subsysDevtype.mid(ix + 1).toLatin1();
udev_monitor_filter_add_match_subsystem_devtype(newM, subsystem.constData(), devType.constData());
} else {
udev_monitor_filter_add_match_subsystem_devtype(newM, subsysDevtype.toLatin1().constData(), nullptr);
}
}
// start the new monitor receiving
udev_monitor_enable_receiving(newM);
QSocketNotifier *sn = new QSocketNotifier(udev_monitor_get_fd(newM), QSocketNotifier::Read);
QObject::connect(sn, &QSocketNotifier::activated, q, [this]() {
dispatchEvent();
});
// kill any previous monitor
delete monitorNotifier;
if (monitor) {
udev_monitor_unref(monitor);
}
// and save our new one
monitor = newM;
monitorNotifier = sn;
watchedSubsystems = subsystemList;
}
void ClientPrivate::dispatchEvent()
{
monitorNotifier->setEnabled(false);
struct udev_device *dev = udev_monitor_receive_device(monitor);
monitorNotifier->setEnabled(true);
if (!dev) {
return;
}
Device device(new DevicePrivate(dev, false));
QByteArray action(udev_device_get_action(dev));
if (action == "add") {
Q_EMIT q->deviceAdded(device);
} else if (action == "remove") {
Q_EMIT q->deviceRemoved(device);
} else if (action == "change") {
Q_EMIT q->deviceChanged(device);
} else if (action == "online") {
Q_EMIT q->deviceOnlined(device);
} else if (action == "offline") {
Q_EMIT q->deviceOfflined(device);
} else if (action == "bind") {
Q_EMIT q->deviceBound(device);
} else if (action == "unbind") {
Q_EMIT q->deviceUnbound(device);
} else {
qCDebug(Solid::Frontend::DeviceManager::DEVICEMANAGER) << "UdevQt: unhandled action:" << action.constData() << "for device:" << device.sysfsPath();
}
}
DeviceList ClientPrivate::deviceListFromEnumerate(struct udev_enumerate *en)
{
DeviceList ret;
struct udev_list_entry *list;
struct udev_list_entry *entry;
udev_enumerate_scan_devices(en);
list = udev_enumerate_get_list_entry(en);
udev_list_entry_foreach(entry, list)
{
struct udev_device *ud = udev_device_new_from_syspath(udev_enumerate_get_udev(en), udev_list_entry_get_name(entry));
if (!ud) {
continue;
}
ret << Device(new DevicePrivate(ud, false));
}
udev_enumerate_unref(en);
return ret;
}
Client::Client(QObject *parent)
: QObject(parent)
, d(new ClientPrivate(this))
{
d->init(QStringList(), ClientPrivate::ListenToNone);
}
Client::Client(const QStringList &subsystemList, QObject *parent)
: QObject(parent)
, d(new ClientPrivate(this))
{
d->init(subsystemList, ClientPrivate::ListenToList);
}
Client::~Client()
{
delete d;
}
QStringList Client::watchedSubsystems() const
{
// we're watching a specific list
if (!d->watchedSubsystems.isEmpty()) {
return d->watchedSubsystems;
}
// we're not watching anything
if (!d->monitor) {
return QStringList();
}
// we're watching everything: figure out what "everything" currently is
// we don't cache it, since it may be subject to change, depending on hotplug
struct udev_enumerate *en = udev_enumerate_new(d->udev);
udev_enumerate_scan_subsystems(en);
QStringList s = listFromListEntry(udev_enumerate_get_list_entry(en));
udev_enumerate_unref(en);
return s;
}
void Client::setWatchedSubsystems(const QStringList &subsystemList)
{
d->setWatchedSubsystems(subsystemList);
}
DeviceList Client::devicesByProperty(const QString &property, const QVariant &value)
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
if (value.isValid()) {
udev_enumerate_add_match_property(en, property.toLatin1().constData(), value.toString().toLatin1().constData());
} else {
udev_enumerate_add_match_property(en, property.toLatin1().constData(), nullptr);
}
return d->deviceListFromEnumerate(en);
}
DeviceList Client::allDevices()
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
return d->deviceListFromEnumerate(en);
}
DeviceList Client::devicesBySubsystem(const QString &subsystem)
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData());
return d->deviceListFromEnumerate(en);
}
DeviceList Client::devicesBySubsystemsAndProperties(const QStringList &subsystems, const QVariantMap &properties)
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
for (const QString &subsystem : subsystems) {
udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData());
}
for (auto it = properties.begin(), end = properties.end(); it != end; ++it) {
if (it.value().isValid()) {
udev_enumerate_add_match_property(en, it.key().toLatin1().constData(), it.value().toString().toLatin1().constData());
} else {
udev_enumerate_add_match_property(en, it.key().toLatin1().constData(), nullptr);
}
}
return d->deviceListFromEnumerate(en);
}
Device Client::deviceByDeviceFile(const QString &deviceFile)
{
QT_STATBUF sb;
if (QT_STAT(deviceFile.toLatin1().constData(), &sb) != 0) {
return Device();
}
struct udev_device *ud = nullptr;
if (S_ISBLK(sb.st_mode)) {
ud = udev_device_new_from_devnum(d->udev, 'b', sb.st_rdev);
} else if (S_ISCHR(sb.st_mode)) {
ud = udev_device_new_from_devnum(d->udev, 'c', sb.st_rdev);
}
if (!ud) {
return Device();
}
return Device(new DevicePrivate(ud, false));
}
Device Client::deviceBySysfsPath(const QString &sysfsPath)
{
struct udev_device *ud = udev_device_new_from_syspath(d->udev, sysfsPath.toLatin1().constData());
if (!ud) {
return Device();
}
return Device(new DevicePrivate(ud, false));
}
Device Client::deviceBySubsystemAndName(const QString &subsystem, const QString &name)
{
struct udev_device *ud = udev_device_new_from_subsystem_sysname(d->udev, //
subsystem.toLatin1().constData(),
name.toLatin1().constData());
if (!ud) {
return Device();
}
return Device(new DevicePrivate(ud, false));
}
}
#include "moc_udevqtclient.cpp"
@@ -0,0 +1,63 @@
/*
SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef UDEVQTCLIENT_H
#define UDEVQTCLIENT_H
#include <QObject>
#include <QString>
#include <QStringList>
#include <QVariant>
#include "udevqtdevice.h"
namespace UdevQt
{
class ClientPrivate;
class Client : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList watchedSubsystems READ watchedSubsystems WRITE setWatchedSubsystems)
public:
Client(QObject *parent = nullptr);
Client(const QStringList &subsystemList, QObject *parent = nullptr);
~Client() override;
QStringList watchedSubsystems() const;
void setWatchedSubsystems(const QStringList &subsystemList);
DeviceList allDevices();
DeviceList devicesByProperty(const QString &property, const QVariant &value);
DeviceList devicesBySubsystem(const QString &subsystem);
/**
* Returns a list of devices matching any of the given subsystems AND any of the properties.
*
* (subsystem1 || subsystem2 || ...) && (property1 || property2 || ...)
*/
DeviceList devicesBySubsystemsAndProperties(const QStringList &subsystems, const QVariantMap &properties);
Device deviceByDeviceFile(const QString &deviceFile);
Device deviceBySysfsPath(const QString &sysfsPath);
Device deviceBySubsystemAndName(const QString &subsystem, const QString &name);
Q_SIGNALS:
void deviceAdded(const UdevQt::Device &dev);
void deviceRemoved(const UdevQt::Device &dev);
void deviceChanged(const UdevQt::Device &dev);
void deviceOnlined(const UdevQt::Device &dev);
void deviceOfflined(const UdevQt::Device &dev);
void deviceBound(const UdevQt::Device &dev);
void deviceUnbound(const UdevQt::Device &dev);
private:
friend class ClientPrivate;
ClientPrivate *d;
};
}
#endif
@@ -0,0 +1,278 @@
/*
SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "udevqtdevice.h"
#include "udevqt_p.h"
#include <QByteArray>
namespace UdevQt
{
DevicePrivate::DevicePrivate(struct udev_device *udev_, bool ref)
: udev(udev_)
{
if (ref) {
udev_device_ref(udev);
}
}
DevicePrivate::~DevicePrivate()
{
udev_device_unref(udev);
}
DevicePrivate &DevicePrivate::operator=(const DevicePrivate &other)
{
udev_device_unref(udev);
udev = udev_device_ref(other.udev);
return *this;
}
QString DevicePrivate::decodePropertyValue(const QByteArray &encoded) const
{
QByteArray decoded;
const int len = encoded.length();
for (int i = 0; i < len; i++) {
quint8 ch = encoded.at(i);
if (ch == '\\') {
if (i + 1 < len && encoded.at(i + 1) == '\\') {
decoded.append('\\');
i++;
continue;
} else if (i + 3 < len && encoded.at(i + 1) == 'x') {
QByteArray hex = encoded.mid(i + 2, 2);
bool ok;
int code = hex.toInt(&ok, 16);
if (ok) {
decoded.append(char(code));
}
i += 3;
continue;
}
} else {
decoded.append(ch);
}
}
return QString::fromUtf8(decoded);
}
Device::Device()
: d(nullptr)
{
}
Device::Device(const Device &other)
{
if (other.d) {
d = new DevicePrivate(other.d->udev);
} else {
d = nullptr;
}
}
Device::Device(DevicePrivate *devPrivate)
: d(devPrivate)
{
}
Device::~Device()
{
delete d;
}
Device &Device::operator=(const Device &other)
{
if (this == &other) {
return *this;
}
if (!other.d) {
delete d;
d = nullptr;
return *this;
}
if (!d) {
d = new DevicePrivate(other.d->udev);
} else {
*d = *other.d;
}
return *this;
}
bool Device::isValid() const
{
return (d != nullptr);
}
QString Device::subsystem() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_subsystem(d->udev));
}
QString Device::devType() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_devtype(d->udev));
}
QString Device::name() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_sysname(d->udev));
}
QString Device::sysfsPath() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_syspath(d->udev));
}
int Device::sysfsNumber() const
{
if (!d) {
return -1;
}
QString value = QString::fromLatin1(udev_device_get_sysnum(d->udev));
bool success = false;
int number = value.toInt(&success);
if (success) {
return number;
}
return -1;
}
QString Device::driver() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_driver(d->udev));
}
QString Device::primaryDeviceFile() const
{
if (!d) {
return QString();
}
return QString::fromLatin1(udev_device_get_devnode(d->udev));
}
QStringList Device::alternateDeviceSymlinks() const
{
if (!d) {
return QStringList();
}
return listFromListEntry(udev_device_get_devlinks_list_entry(d->udev));
}
QStringList Device::deviceProperties() const
{
if (!d) {
return QStringList();
}
return listFromListEntry(udev_device_get_properties_list_entry(d->udev));
}
#ifdef UDEV_HAVE_GET_SYSATTR_LIST_ENTRY
QStringList Device::sysfsProperties() const
{
if (!d) {
return QStringList();
}
return listFromListEntry(udev_device_get_sysattr_list_entry(d->udev));
}
#endif
Device Device::parent() const
{
if (!d) {
return Device();
}
struct udev_device *p = udev_device_get_parent(d->udev);
if (!p) {
return Device();
}
return Device(new DevicePrivate(p));
}
QVariant Device::deviceProperty(const QString &name) const
{
if (!d) {
return QVariant();
}
QByteArray propName = name.toLatin1();
QString propValue = QString::fromLatin1(udev_device_get_property_value(d->udev, propName.constData()));
if (!propValue.isEmpty()) {
return QVariant::fromValue(propValue);
}
return QVariant();
}
QString Device::decodedDeviceProperty(const QString &name) const
{
if (!d) {
return QString();
}
QByteArray propName = name.toLatin1();
return d->decodePropertyValue(udev_device_get_property_value(d->udev, propName.constData()));
}
QVariant Device::sysfsProperty(const QString &name) const
{
if (!d) {
return QVariant();
}
QByteArray propName = name.toLatin1();
QString propValue = QString::fromLatin1(udev_device_get_sysattr_value(d->udev, propName.constData()));
if (!propValue.isEmpty()) {
return QVariant::fromValue(propValue);
}
return QVariant();
}
Device Device::ancestorOfType(const QString &subsys, const QString &devtype) const
{
if (!d) {
return Device();
}
struct udev_device *p = udev_device_get_parent_with_subsystem_devtype(d->udev, subsys.toLatin1().constData(), devtype.toLatin1().constData());
if (!p) {
return Device();
}
return Device(new DevicePrivate(p));
}
}
@@ -0,0 +1,60 @@
/*
SPDX-FileCopyrightText: 2009 Benjamin K. Stuhl <bks24@cornell.edu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef UDEVQTDEVICE_H
#define UDEVQTDEVICE_H
#include <QList>
#include <QString>
#include <QStringList>
#include <QVariant>
namespace UdevQt
{
class DevicePrivate;
class Device
{
public:
Device();
Device(const Device &other);
~Device();
Device &operator=(const Device &other);
bool isValid() const;
QString subsystem() const;
QString devType() const;
QString name() const;
QString sysfsPath() const;
int sysfsNumber() const;
QString driver() const;
QString primaryDeviceFile() const;
QStringList alternateDeviceSymlinks() const;
QStringList deviceProperties() const;
#ifdef UDEV_HAVE_GET_SYSATTR_LIST_ENTRY
QStringList sysfsProperties() const;
#endif
Device parent() const;
// ### should this really be a QVariant? as far as udev knows, everything is a string...
// see also Client::devicesByProperty
QVariant deviceProperty(const QString &name) const;
QString decodedDeviceProperty(const QString &name) const;
QVariant sysfsProperty(const QString &name) const;
Device ancestorOfType(const QString &subsys, const QString &devtype) const;
private:
Device(DevicePrivate *devPrivate);
friend class Client;
friend class ClientPrivate;
DevicePrivate *d;
};
typedef QList<Device> DeviceList;
}
#endif

Some files were not shown because too many files have changed in this diff Show More