From 1b63411074c3bbd49a6d0dc90c5eb906025e3aec Mon Sep 17 00:00:00 2001
From: Timothy Pearson <kb9vqf@pearsoncomputing.net>
Date: Fri, 30 Mar 2012 03:11:31 -0500
Subject: Greatly enhance udev disk scanning and mount detection functions of
 TDE hardware library

---
 tdecore/tdehardwaredevices.cpp | 528 ++++++++++++++++++++++++++++++++++++-----
 tdecore/tdehardwaredevices.h   | 235 +++++++++++++++++-
 2 files changed, 700 insertions(+), 63 deletions(-)

(limited to 'tdecore')

diff --git a/tdecore/tdehardwaredevices.cpp b/tdecore/tdehardwaredevices.cpp
index a101cb017..1874c65d7 100644
--- a/tdecore/tdehardwaredevices.cpp
+++ b/tdecore/tdehardwaredevices.cpp
@@ -18,8 +18,18 @@
 
 #include <tdehardwaredevices.h>
 
+#include <tqfile.h>
+#include <tqstringlist.h>
+
 #include <libudev.h>
 
+#include <fcntl.h>
+#include <poll.h>
+
+// NOTE TO DEVELOPERS
+// This command will greatly help when attempting to find properties to distinguish one device from another
+// udevadm info --query=all --path=/sys/....
+
 TDEGenericDevice::TDEGenericDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) {
 	m_deviceType = dt;
 	m_deviceName = dn;
@@ -40,6 +50,22 @@ void TDEGenericDevice::setName(TQString dn) {
 	m_deviceName = dn;
 }
 
+TQString &TDEGenericDevice::vendorName() {
+	return m_vendorName;
+}
+
+void TDEGenericDevice::setVendorName(TQString vn) {
+	m_vendorName = vn;
+}
+
+TQString &TDEGenericDevice::vendorModel() {
+	return m_vendorModel;
+}
+
+void TDEGenericDevice::setVendorModel(TQString vm) {
+	m_vendorModel = vm;
+}
+
 TQString &TDEGenericDevice::systemPath() {
 	return m_systemPath;
 }
@@ -56,6 +82,99 @@ void TDEGenericDevice::setDeviceNode(TQString sn) {
 	m_deviceNode = sn;
 }
 
+TQString &TDEGenericDevice::deviceBus() {
+	return m_deviceBus;
+}
+
+void TDEGenericDevice::setDeviceBus(TQString db) {
+	m_deviceBus = db;
+}
+
+TDEStorageDevice::TDEStorageDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn), m_mediaInserted(true) {
+}
+
+TDEStorageDevice::~TDEStorageDevice() {
+}
+
+TDEDiskDeviceType::TDEDiskDeviceType TDEStorageDevice::diskType() {
+	return m_diskType;
+}
+
+void TDEStorageDevice::setDiskType(TDEDiskDeviceType::TDEDiskDeviceType dt) {
+	m_diskType = dt;
+}
+
+TDEDiskDeviceStatus::TDEDiskDeviceStatus TDEStorageDevice::diskStatus() {
+	return m_diskStatus;
+}
+
+void TDEStorageDevice::setDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus st) {
+	m_diskStatus = st;
+}
+
+TQString &TDEStorageDevice::diskLabel() {
+	return m_diskName;
+}
+
+void TDEStorageDevice::setDiskLabel(TQString dn) {
+	m_diskName = dn;
+}
+
+bool TDEStorageDevice::mediaInserted() {
+	return m_mediaInserted;
+}
+
+void TDEStorageDevice::setMediaInserted(bool inserted) {
+	m_mediaInserted = inserted;
+}
+
+TQString &TDEStorageDevice::fileSystemName() {
+	return m_fileSystemName;
+}
+
+void TDEStorageDevice::setFileSystemName(TQString fn) {
+	m_fileSystemName = fn;
+}
+
+TQString &TDEStorageDevice::fileSystemUsage() {
+	return m_fileSystemUsage;
+}
+
+void TDEStorageDevice::setFileSystemUsage(TQString fu) {
+	m_fileSystemUsage = fu;
+}
+
+TQString &TDEStorageDevice::diskUUID() {
+	return m_diskUUID;
+}
+
+void TDEStorageDevice::setDiskUUID(TQString id) {
+	m_diskUUID = id;
+}
+
+TQString TDEStorageDevice::mountPath() {
+	// See if this device node is mounted
+	// This requires parsing /proc/mounts, looking for deviceNode()
+
+	TQStringList lines;
+	TQFile file( "/proc/mounts" );
+	if ( file.open( IO_ReadOnly ) ) {
+		TQTextStream stream( &file );
+		TQString line;
+		while ( !stream.atEnd() ) {
+			line = stream.readLine();
+			TQStringList mountInfo = TQStringList::split(" ", line, true);
+			if (*mountInfo.at(0) == deviceNode()) {
+				return *mountInfo.at(1);
+			}
+			lines += line;
+		}
+		file.close();
+	}
+
+	return TQString::null;
+}
+
 TDEHardwareDevices::TDEHardwareDevices() {
 	// Set up device list
 	m_deviceList.setAutoDelete( TRUE );	// the list owns the objects
@@ -66,15 +185,345 @@ TDEHardwareDevices::TDEHardwareDevices() {
 		printf("Unable to create udev interface\n\r");
 	}
 
-	// Update internal device information
-	queryHardwareInformation();
+	if (m_udevStruct) {
+		// Set up device add/remove monitoring
+		m_udevMonitorStruct = udev_monitor_new_from_netlink(m_udevStruct, "udev");
+		udev_monitor_filter_add_match_subsystem_devtype(m_udevMonitorStruct, NULL, NULL);
+		udev_monitor_enable_receiving(m_udevMonitorStruct);
+
+		m_devScanTimer = new TQTimer();
+		connect( m_devScanTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkForHotPluggedHardware()) );
+		m_devScanTimer->start(1, TRUE);
+
+		// Monitor for changed mounts
+		m_mountScanTimer = new TQTimer();
+		connect( m_mountScanTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkForModifiedMounts()) );
+		m_mountScanTimer->start(1, TRUE);
+
+		// Update internal device information
+		queryHardwareInformation();
+	}
 }
 
 TDEHardwareDevices::~TDEHardwareDevices() {
+	// Stop hardware scanning
+	m_devScanTimer->stop();
+	delete m_devScanTimer;
+
+	// Stop mount scanning
+	m_mountScanTimer->stop();
+	delete m_mountScanTimer;
+
 	// Tear down udev interface
 	udev_unref(m_udevStruct);
 }
 
+void TDEHardwareDevices::checkForHotPluggedHardware() {
+	udev_device* dev = udev_monitor_receive_device(m_udevMonitorStruct);
+	if (dev) {
+		TQString actionevent(udev_device_get_action(dev));
+		if (actionevent == "add") {	
+			TDEGenericDevice* device = classifyUnknownDevice(dev);
+	
+			// Make sure this device is not a duplicate
+			TDEGenericDevice *hwdevice;
+			for (hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next()) {
+				if (hwdevice->systemPath() == device->systemPath()) {
+					delete device;
+					device = 0;
+					break;
+				}
+			}
+	
+			if (device) {
+				m_deviceList.append(device);
+				emit hardwareAdded(*device);
+			}
+		}
+		else if (actionevent == "remove") {
+			// Delete device from hardware listing
+			TQString systempath(udev_device_get_syspath(dev));
+			TDEGenericDevice *hwdevice;
+			for (hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next()) {
+				if (hwdevice->systemPath() == systempath) {
+					m_deviceList.remove(hwdevice);
+					emit hardwareAdded(*hwdevice);
+					break;
+				}
+			}
+		}
+	}
+
+	// Continue scanning for added/removed hardware
+	m_devScanTimer->start(1, TRUE);
+}
+
+void TDEHardwareDevices::checkForModifiedMounts() {
+	int mfd = open("/proc/mounts", O_RDONLY, 0);
+	struct pollfd pfd;
+	int rv;
+	
+	pfd.fd = mfd;
+	pfd.events = POLLERR | POLLPRI;
+	pfd.revents = 0;
+	while ((rv = poll(&pfd, 1, 5)) >= 0) {
+		if (pfd.revents & POLLERR) {
+			emit mountTableModified();
+		}
+	
+		pfd.revents = 0;
+	}
+
+	// Continue scanning for changed mounts
+	m_mountScanTimer->start(1, TRUE);
+}
+
+TDEGenericDevice* TDEHardwareDevices::classifyUnknownDevice(udev_device* dev) {
+	// Classify device and create TDEW device object
+	TQString devicename(udev_device_get_sysname(dev));
+	TQString devicetype(udev_device_get_devtype(dev));
+	TQString devicedriver(udev_device_get_driver(dev));
+	TQString devicesubsystem(udev_device_get_subsystem(dev));
+	TQString devicenode(udev_device_get_devnode(dev));
+	TQString systempath(udev_device_get_syspath(dev));
+	bool removable = false;
+	TDEGenericDevice* device = 0;
+
+	// FIXME
+	// Only a small subset of devices are classified right now
+	// Figure out the remaining udev logic to classify the rest!
+	// Helpful file: http://www.enlightenment.org/svn/e/trunk/PROTO/enna-explorer/src/bin/udev.c
+
+	if ((devicetype == "disk") || (devicetype == "partition")) {
+		// Determine if disk is removable
+		TQString removablenodename = udev_device_get_syspath(dev);
+		removablenodename.append("/removable");
+		FILE *fp = fopen(removablenodename.ascii(),"r");
+		if (fp) {
+			if (fgetc(fp) == '1') {
+				removable = true;
+			}
+			fclose(fp);
+		}
+		device = new TDEStorageDevice(TDEGenericDeviceType::Disk);
+
+		// Determine generic disk information
+		TQString devicevendor(udev_device_get_property_value(dev, "ID_VENDOR"));
+		TQString devicemodel(udev_device_get_property_value(dev, "ID_MODEL"));
+		TQString devicebus(udev_device_get_property_value(dev, "ID_BUS"));
+
+		// Get disk specific info
+		TQString disktypestring(udev_device_get_property_value(dev, "ID_TYPE"));
+		TQString disklabel(udev_device_get_property_value(dev, "ID_FS_LABEL"));
+		TQString diskuuid(udev_device_get_property_value(dev, "ID_FS_UUID"));
+		TQString filesystemtype(udev_device_get_property_value(dev, "ID_FS_TYPE"));
+		TQString filesystemusage(udev_device_get_property_value(dev, "ID_FS_USAGE"));
+
+		device->setVendorName(devicevendor);
+		device->setVendorModel(devicemodel);
+		device->setDeviceBus(devicebus);
+
+		TDEStorageDevice* sdevice = static_cast<TDEStorageDevice*>(device);
+
+		TDEDiskDeviceType::TDEDiskDeviceType disktype = (TDEDiskDeviceType::TDEDiskDeviceType)0;
+		TDEDiskDeviceStatus::TDEDiskDeviceStatus diskstatus = (TDEDiskDeviceStatus::TDEDiskDeviceStatus)0;
+
+		if (devicebus.upper() == "USB") {
+			disktype = disktype | TDEDiskDeviceType::USB;
+		}
+
+		if (disktypestring.upper() == "ZIP") {
+			disktype = disktype | TDEDiskDeviceType::Zip;
+		}
+		if ((devicevendor.upper() == "IOMEGA") && (devicemodel.upper().contains("ZIP"))) {
+			disktype = disktype | TDEDiskDeviceType::Zip;
+		}
+
+		if (disktypestring.upper() == "FLOPPY") {
+			disktype = disktype | TDEDiskDeviceType::Floppy;
+		}
+
+		if (disktypestring.upper() == "TAPE") {
+			disktype = disktype | TDEDiskDeviceType::Tape;
+		}
+
+		if (disktypestring.upper() == "COMPACT_FLASH") {
+			disktype = disktype | TDEDiskDeviceType::CompactFlash;
+		}
+
+		if (disktypestring.upper() == "MEMORY_STICK") {
+			disktype = disktype | TDEDiskDeviceType::MemoryStick;
+		}
+
+		if (disktypestring.upper() == "SMART_MEDIA") {
+			disktype = disktype | TDEDiskDeviceType::SmartMedia;
+		}
+
+		if (disktypestring.upper() == "SD_MMC") {
+			disktype = disktype | TDEDiskDeviceType::SDMMC;
+		}
+
+		if (disktypestring.upper() == "FLASHKEY") {
+			disktype = disktype | TDEDiskDeviceType::Flash;
+		}
+
+		if (disktypestring.upper() == "OPTICAL") {
+			disktype = disktype | TDEDiskDeviceType::Optical;
+		}
+
+		if (disktypestring.upper() == "JAZ") {
+			disktype = disktype | TDEDiskDeviceType::Jaz;
+		}
+
+		if (disktypestring.upper() == "DISK") {
+			disktype = disktype | TDEDiskDeviceType::HDD;
+		}
+
+		if (disktypestring.upper() == "CD") {
+			if (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA")) == "1") {
+				disktype = disktype | TDEDiskDeviceType::CDROM;
+			}
+			if (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD")) == "1") {
+				disktype = disktype | TDEDiskDeviceType::DVDROM;
+				disktype = disktype & ~TDEDiskDeviceType::CDROM;
+			}
+			if (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_RAM")) == "1") {
+				disktype = disktype | TDEDiskDeviceType::DVDRAM;
+				disktype = disktype & ~TDEDiskDeviceType::DVDROM;
+			}
+			if ((TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_RW_DL")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_PLUS_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_MINUS_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_PLUS_RW_DL")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_MINUS_RW_DL")) == "1")
+				) {
+				disktype = disktype | TDEDiskDeviceType::DVDRW;
+				disktype = disktype & ~TDEDiskDeviceType::DVDROM;
+			}
+			if (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_BD")) == "1") {
+				disktype = disktype | TDEDiskDeviceType::BDROM;
+				disktype = disktype & ~TDEDiskDeviceType::CDROM;
+			}
+			if ((TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_BD_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_BD_RW_DL")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_BD_PLUS_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_BD_MINUS_RW")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_PLUS_RW_DL")) == "1")
+				|| (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_DVD_MINUS_RW_DL")) == "1")
+				) {
+				disktype = disktype | TDEDiskDeviceType::BDRW;
+				disktype = disktype & ~TDEDiskDeviceType::BDROM;
+			}
+			if (!TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO")).isNull()) {
+				disktype = disktype | TDEDiskDeviceType::CDAudio;
+			}
+			if ((TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_VCD")) == "1") || (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_SDVD")) == "1")) {
+				disktype = disktype | TDEDiskDeviceType::CDVideo;
+			}
+			if (TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA_STATE")).upper() == "BLANK") {
+				diskstatus = diskstatus | TDEDiskDeviceStatus::Blank;
+			}
+
+			sdevice->setMediaInserted(!(TQString(udev_device_get_property_value(dev, "ID_CDROM_MEDIA")) == "0"));
+		}
+
+		if (removable) {
+			diskstatus = diskstatus | TDEDiskDeviceStatus::Removable;
+		}
+
+		if (disktypestring.upper() == "CRYPTO_LUKS") {
+			disktype = disktype | TDEDiskDeviceType::LUKS;
+		}
+		else if (disktypestring.upper() == "CRYPTO") {
+			disktype = disktype | TDEDiskDeviceType::OtherCrypted;
+		}
+
+		// Detect RAM and Loop devices, since udev can't seem to...
+		if (systempath.startsWith("/sys/devices/virtual/block/ram")) {
+			disktype = disktype | TDEDiskDeviceType::RAM;
+		}
+		if (systempath.startsWith("/sys/devices/virtual/block/loop")) {
+			disktype = disktype | TDEDiskDeviceType::Loop;
+		}
+
+		// Set mountable flag if device is likely to be mountable
+		diskstatus = diskstatus | TDEDiskDeviceStatus::Mountable;
+		if ((!disktypestring.upper().isNull()) && (disktype & TDEDiskDeviceType::HDD)) {
+			diskstatus = diskstatus & ~TDEDiskDeviceStatus::Mountable;
+		}
+		if (sdevice->mediaInserted()) {
+			diskstatus = diskstatus | TDEDiskDeviceStatus::Inserted;
+		}
+		else {
+			diskstatus = diskstatus & ~TDEDiskDeviceStatus::Mountable;
+		}
+
+		sdevice->setDiskType(disktype);
+		sdevice->setDiskUUID(diskuuid);
+		sdevice->setDiskLabel(disklabel);
+		sdevice->setDiskStatus(diskstatus);
+		sdevice->setFileSystemName(filesystemtype);
+		sdevice->setFileSystemUsage(filesystemusage);
+
+		printf("DISK DEVICE name: %s type: %s subsystem: %s vendor: %s model: %s bus: %s label: %s filesystem: %s disk type: %s disk type flags: 0x%08x media inserted: %d [Node Path: %s] [Syspath: %s]\n\r\n\r", devicename.ascii(), devicetype.ascii(), devicesubsystem.ascii(), devicevendor.ascii(), devicemodel.ascii(), devicebus.ascii(), disklabel.ascii(), filesystemtype.ascii(), disktypestring.ascii(), disktype, sdevice->mediaInserted(), devicenode.ascii(), udev_device_get_syspath(dev)); fflush(stdout);
+	}
+	else if (devicetype.isNull()) {
+		if (devicesubsystem == "acpi") {
+			device = new TDEGenericDevice(TDEGenericDeviceType::OtherACPI);
+		}
+		else if (devicesubsystem == "input") {
+			// Figure out if this device is a mouse, keyboard, or something else
+			// Check for mouse
+			// udev doesn't reliably help here, so guess from the device name
+			if (systempath.contains("/mouse")) {
+				device = new TDEGenericDevice(TDEGenericDeviceType::Mouse);
+			}
+			if (!device) {
+				// Second mouse check 
+				// Look for ID_INPUT_MOUSE property presence
+				if (udev_device_get_property_value(dev, "ID_INPUT_MOUSE") != 0) {
+					device = new TDEGenericDevice(TDEGenericDeviceType::Mouse);
+				}
+			}
+			if (!device) {
+				// Check for keyboard
+				// Look for ID_INPUT_KEYBOARD property presence
+				if (udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD") != 0) {
+					device = new TDEGenericDevice(TDEGenericDeviceType::Keyboard);
+				}
+			}
+			if (!device) {
+				device = new TDEGenericDevice(TDEGenericDeviceType::HID);
+			}
+		}
+		else if (devicesubsystem == "tty") {
+			device = new TDEGenericDevice(TDEGenericDeviceType::TextIO);
+		}
+		else if (devicesubsystem == "thermal") {
+			// FIXME
+			// Figure out a way to differentiate between ThermalControl (fans and coolers) and ThermalSensor types
+			device = new TDEGenericDevice(TDEGenericDeviceType::ThermalControl);
+		}
+		else if (devicesubsystem == "hwmon") {
+			// FIXME
+			// This might pick up thermal sensors
+			device = new TDEGenericDevice(TDEGenericDeviceType::OtherSensor);
+		}
+	}
+
+	if (device == 0) {
+		// Unhandled
+		device = new TDEGenericDevice(TDEGenericDeviceType::Other);
+		printf("[FIXME] UNCLASSIFIED DEVICE name: %s type: %s subsystem: %s driver: %s [Node Path: %s] [Syspath: %s]\n\r", devicename.ascii(), devicetype.ascii(), devicesubsystem.ascii(), devicedriver.ascii(), devicenode.ascii(), udev_device_get_syspath(dev)); fflush(stdout);
+	}
+	device->setName(devicename);
+	device->setDeviceNode(devicenode);
+	device->setSystemPath(systempath);
+
+	return device;
+}
+
 bool TDEHardwareDevices::queryHardwareInformation() {
 	if (!m_udevStruct) {
 		return false;
@@ -95,69 +544,26 @@ bool TDEHardwareDevices::queryHardwareInformation() {
 	// Get detailed information on each detected device
 	udev_list_entry_foreach(dev_list_entry, devices) {
 		const char *path;
-		
+
 		// Get the filename of the /sys entry for the device and create a udev_device object (dev) representing it
 		path = udev_list_entry_get_name(dev_list_entry);
 		dev = udev_device_new_from_syspath(m_udevStruct, path);
-	
-		// Classify device and create TDEW device object
-		TQString devicename(udev_device_get_sysname(dev));
-		TQString devicetype(udev_device_get_devtype(dev));
-		TQString devicedriver(udev_device_get_driver(dev));
-		TQString devicesubsystem(udev_device_get_subsystem(dev));
-		TQString devicenode(udev_device_get_devnode(dev));
-		TQString systempath(udev_device_get_syspath(dev));
-		bool removable = false;
-		TDEGenericDevice* device = 0;
-
-		if (devicetype == "disk") {
-			// Determine if disk is removable
-			TQString removablenodename = udev_device_get_syspath(dev);
-			removablenodename.append("/removable");
-			FILE *fp = fopen(removablenodename.ascii(),"r");
-			if (fp) {
-				if (fgetc(fp) == '1') {
-					removable = true;
-				}
-				fclose(fp);
-			}
-			if (removable) {
-				device = new TDEGenericDevice(TDEGenericDeviceType::RemovableDisk);
-			}
-			else {
-				device = new TDEGenericDevice(TDEGenericDeviceType::FixedDisk);
-			}
-		}
-		else if (devicetype.isNull()) {
-			if (devicesubsystem == "acpi") {
-				device = new TDEGenericDevice(TDEGenericDeviceType::OtherACPI);
-			}
-			else if (devicesubsystem == "input") {
-				device = new TDEGenericDevice(TDEGenericDeviceType::HID);
-			}
-			else if (devicesubsystem == "tty") {
-				device = new TDEGenericDevice(TDEGenericDeviceType::TextIO);
-			}
-			else if (devicesubsystem == "thermal") {
-				// FIXME
-				// Figure out a way to differentiate between ThermalControl (fans and coolers) and ThermalSensor types
-				device = new TDEGenericDevice(TDEGenericDeviceType::ThermalControl);
-			}
-			else if (devicesubsystem == "hwmon") {
-				// FIXME
-				// This might pick up thermal sensors
-				device = new TDEGenericDevice(TDEGenericDeviceType::OtherSensor);
+
+		TDEGenericDevice* device = classifyUnknownDevice(dev);
+
+		// Make sure this device is not a duplicate
+		TDEGenericDevice *hwdevice;
+		for (hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next()) {
+			if (hwdevice->systemPath() == device->systemPath()) {
+				delete device;
+				device = 0;
+				break;
 			}
 		}
-		if (device == 0) {
-			// Unhandled
-			device = new TDEGenericDevice(TDEGenericDeviceType::Other);
-			printf("[FIXME] UNCLASSIFIED DEVICE name: %s type: %s subsystem: %s driver: %s [Node Path: %s] [Syspath: %s]\n\r", devicename.ascii(), devicetype.ascii(), devicesubsystem.ascii(), devicedriver.ascii(), devicenode.ascii(), udev_device_get_syspath(dev)); fflush(stdout);
+
+		if (device) {
+			m_deviceList.append(device);
 		}
-		device->setName(devicename);
-		device->setDeviceNode(devicenode);
-		device->setSystemPath(systempath);
-		m_deviceList.append(device);
 	}
 
 	// Free the enumerator object
@@ -168,4 +574,6 @@ bool TDEHardwareDevices::queryHardwareInformation() {
 
 TDEGenericHardwareList &TDEHardwareDevices::listAllPhysicalDevices() {
 	return m_deviceList;
-}
\ No newline at end of file
+}
+
+#include "tdehardwaredevices.moc"
\ No newline at end of file
diff --git a/tdecore/tdehardwaredevices.h b/tdecore/tdehardwaredevices.h
index d80b86432..e56217cbe 100644
--- a/tdecore/tdehardwaredevices.h
+++ b/tdecore/tdehardwaredevices.h
@@ -21,6 +21,7 @@
 // TDE includes
 #include <tqstring.h>
 #include <tqptrlist.h>
+#include <tqtimer.h>
 #include "tdelibs_export.h"
 
 // udev includes
@@ -42,13 +43,17 @@ enum TDEGenericDeviceType {
 	GPU,
 	RAM,
 	Mainboard,
-	FixedDisk,
-	RemovableDisk,
+	Disk,
 	StorageController,
+	Mouse,
+	Keyboard,
 	HID,
 	Network,
 	Printer,
 	Scanner,
+	Sound,
+	IEEE1394,
+	Camera,
 	TextIO,
 	Peripheral,
 	Battery,
@@ -63,6 +68,80 @@ enum TDEGenericDeviceType {
 };
 };
 
+namespace TDEDiskDeviceType {
+enum TDEDiskDeviceType {
+	Floppy =	0x00000002,
+	CDROM =		0x00000004,
+	CDRW =		0x00000008,
+	DVDROM =	0x00000010,
+	DVDRAM =	0x00000020,
+	DVDRW =		0x00000040,
+	BDROM =		0x00000080,
+	BDRW =		0x00000100,
+	Zip =		0x00000200,
+	Jaz =		0x00000400,
+	Camera =	0x00000800,
+	LUKS =		0x00001000,
+	OtherCrypted =	0x00002000,
+	CDAudio =	0x00004000,
+	CDVideo =	0x00008000,
+	DVDVideo =	0x00010000,
+	BDVideo =	0x00020000,
+	Flash =		0x00040000,
+	USB =		0x00080000,
+	Tape =		0x00100000,
+	HDD =		0x00200000,
+	Optical =	0x00400000,
+	RAM =		0x00800000,
+	Loop =		0x01000000,
+	CompactFlash =	0x02000000,
+	MemoryStick =	0x04000000,
+	SmartMedia =	0x08000000,
+	SDMMC =		0x10000000,
+	Other =		0x80000000
+};
+
+inline TDEDiskDeviceType operator|(TDEDiskDeviceType a, TDEDiskDeviceType b)
+{
+	return static_cast<TDEDiskDeviceType>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline TDEDiskDeviceType operator&(TDEDiskDeviceType a, TDEDiskDeviceType b)
+{
+	return static_cast<TDEDiskDeviceType>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+inline TDEDiskDeviceType operator~(TDEDiskDeviceType a)
+{
+	return static_cast<TDEDiskDeviceType>(~static_cast<int>(a));
+}
+};
+
+namespace TDEDiskDeviceStatus {
+enum TDEDiskDeviceStatus {
+	Mountable =	0x00000001,
+	Removable =	0x00000002,
+	Inserted =	0x00000004,
+	Blank =		0x00000008,
+	Other =		0x80000000
+};
+
+inline TDEDiskDeviceStatus operator|(TDEDiskDeviceStatus a, TDEDiskDeviceStatus b)
+{
+	return static_cast<TDEDiskDeviceStatus>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline TDEDiskDeviceStatus operator&(TDEDiskDeviceStatus a, TDEDiskDeviceStatus b)
+{
+	return static_cast<TDEDiskDeviceStatus>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+inline TDEDiskDeviceStatus operator~(TDEDiskDeviceStatus a)
+{
+	return static_cast<TDEDiskDeviceStatus>(~static_cast<int>(a));
+}
+};
+
 class TDECORE_EXPORT TDEGenericDevice
 {
 	public:
@@ -92,6 +171,36 @@ class TDECORE_EXPORT TDEGenericDevice
 		*/
 		void setName(TQString dn);
 
+		/**
+		* @return a TQString with the vendor name, if any
+		*/
+		TQString &vendorName();
+
+		/**
+		* @param a TQString with the vendor name, if any
+		*/
+		void setVendorName(TQString vn);
+
+		/**
+		* @return a TQString with the vendor model, if any
+		*/
+		TQString &vendorModel();
+
+		/**
+		* @param a TQString with the vendor model, if any
+		*/
+		void setVendorModel(TQString vm);
+
+		/**
+		* @return a TQString with the device bus name, if any
+		*/
+		TQString &deviceBus();
+
+		/**
+		* @param a TQString with the device bus name, if any
+		*/
+		void setDeviceBus(TQString db);
+
 		/**
 		* @return a TQString with the system path, if any
 		*
@@ -125,12 +234,117 @@ class TDECORE_EXPORT TDEGenericDevice
 		TQString m_deviceName;
 		TQString m_systemPath;
 		TQString m_deviceNode;
+		TQString m_vendorName;
+		TQString m_vendorModel;
+		TQString m_deviceBus;
+};
+
+class TDECORE_EXPORT TDEStorageDevice : public TDEGenericDevice
+{
+	public:
+		/**
+		*  Constructor.
+		*  @param Device type
+		*/
+		TDEStorageDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn=TQString::null);
+		
+		/**
+		* Destructor.
+		*/
+		~TDEStorageDevice();
+
+		/**
+		* @return a TQString with the disk or partition label, if any
+		*/
+		TQString &diskLabel();
+
+		/**
+		* @param a TQString with the disk or partition label, if any
+		*/
+		void setDiskLabel(TQString dn);
+
+		/**
+		* @return a TQString with the disk UUID, if any
+		*/
+		TQString &diskUUID();
+
+		/**
+		* @param a TQString with the disk UUID, if any
+		*/
+		void setDiskUUID(TQString id);
+
+		/**
+		* @return an OR-ed combination of TDEDiskDeviceType::TDEDiskDeviceType type flags
+		*/
+		TDEDiskDeviceType::TDEDiskDeviceType diskType();
+
+		/**
+		* @param an OR-ed combination of TDEDiskDeviceType::TDEDiskDeviceType type flags
+		*/
+		void setDiskType(TDEDiskDeviceType::TDEDiskDeviceType tf);
+
+		/**
+		* @return an OR-ed combination of TDEDiskDeviceStatus::TDEDiskDeviceStatus type flags
+		*/
+		TDEDiskDeviceStatus::TDEDiskDeviceStatus diskStatus();
+
+		/**
+		* @param an OR-ed combination of TDEDiskDeviceStatus::TDEDiskDeviceStatus type flags
+		*/
+		void setDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus st);
+
+		/**
+		* @return true if media inserted, false if no media available
+		*/
+		bool mediaInserted();
+
+		/**
+		* @param a bool with the media status
+		*/
+		void setMediaInserted(bool inserted);
+
+		/**
+		* @return a TQString with the filesystem name, if any
+		*/
+		TQString &fileSystemName();
+
+		/**
+		* @param a TQString with the filesystem name, if any
+		*/
+		void setFileSystemName(TQString fn);
+
+		/**
+		* @return a TQString with the filesystem usage string, if any
+		*/
+		TQString &fileSystemUsage();
+
+		/**
+		* @param a TQString with the filesystem usage string, if any
+		*/
+		void setFileSystemUsage(TQString fu);
+
+		/**
+		* @return a TQString with the mount path, if mounted
+		*/
+		TQString mountPath();
+
+	private:
+		TDEDiskDeviceType::TDEDiskDeviceType m_diskType;
+		TDEDiskDeviceStatus::TDEDiskDeviceStatus m_diskStatus;
+		TQString m_diskName;
+		TQString m_diskUUID;
+		TQString m_fileSystemName;
+		TQString m_fileSystemUsage;
+		bool m_mediaInserted;
+		TQString m_mountPath;
 };
 
 typedef TQPtrList<TDEGenericDevice> TDEGenericHardwareList;
 
-class TDECORE_EXPORT TDEHardwareDevices
+class TDECORE_EXPORT TDEHardwareDevices : TQObject
 {
+	Q_OBJECT
+
 	public:	
 		/**
 		*  Constructor.
@@ -160,9 +374,24 @@ class TDECORE_EXPORT TDEHardwareDevices
 		*/
 		TQPtrList<TDEGenericDevice> &listAllPhysicalDevices();
 
+	signals:
+		void hardwareAdded(TDEGenericDevice);
+		void hardwareRemoved(TDEGenericDevice);
+		void mountTableModified();
+
+	private slots:
+		void checkForHotPluggedHardware();
+		void checkForModifiedMounts();
+
 	private:
+		TDEGenericDevice *classifyUnknownDevice(udev_device* dev);
+
 		struct udev *m_udevStruct;
+		struct udev_monitor *m_udevMonitorStruct;
 		TDEGenericHardwareList m_deviceList;
+
+		TQTimer* m_devScanTimer;
+		TQTimer* m_mountScanTimer;
 };
 
 #endif
\ No newline at end of file
-- 
cgit v1.2.1