/* This file is part of the TDE libraries Copyright (C) 2012 Timothy Pearson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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; m_parentDevice = 0; m_blacklistedForUpdate = false; } TDEGenericDevice::~TDEGenericDevice() { } TDEGenericDeviceType::TDEGenericDeviceType TDEGenericDevice::type() { return m_deviceType; } TQString &TDEGenericDevice::name() { return m_deviceName; } 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; } void TDEGenericDevice::setSystemPath(TQString sp) { m_systemPath = sp; } TQString &TDEGenericDevice::deviceNode() { return m_deviceNode; } void TDEGenericDevice::setDeviceNode(TQString sn) { m_deviceNode = sn; } TQString &TDEGenericDevice::deviceBus() { return m_deviceBus; } void TDEGenericDevice::setDeviceBus(TQString db) { m_deviceBus = db; } TQString TDEGenericDevice::uniqueID() { m_uniqueID = m_systemPath+m_deviceNode; return m_uniqueID; } TQString &TDEGenericDevice::vendorID() { return m_vendorID; } void TDEGenericDevice::setVendorID(TQString id) { m_vendorID = id; } TQString &TDEGenericDevice::modelID() { return m_modelID; } void TDEGenericDevice::setModelID(TQString id) { m_modelID = id; } void TDEGenericDevice::setParentDevice(TDEGenericDevice* pd) { m_parentDevice = pd; } TDEGenericDevice* TDEGenericDevice::parentDevice() { return m_parentDevice; } bool TDEGenericDevice::blacklistedForUpdate() { return m_blacklistedForUpdate; } void TDEGenericDevice::setBlacklistedForUpdate(bool bl) { m_blacklistedForUpdate = bl; } TDEStorageDevice::TDEStorageDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn), m_mediaInserted(true) { m_diskType = TDEDiskDeviceType::Null; m_diskStatus = TDEDiskDeviceStatus::Null; } TDEStorageDevice::~TDEStorageDevice() { } TDEDiskDeviceType::TDEDiskDeviceType TDEStorageDevice::diskType() { return m_diskType; } void TDEStorageDevice::setDiskType(TDEDiskDeviceType::TDEDiskDeviceType dt) { m_diskType = dt; } bool TDEStorageDevice::isDiskOfType(TDEDiskDeviceType::TDEDiskDeviceType tf) { return ((m_diskType&tf)!=TDEDiskDeviceType::Null); } TDEDiskDeviceStatus::TDEDiskDeviceStatus TDEStorageDevice::diskStatus() { return m_diskStatus; } void TDEStorageDevice::setDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus st) { m_diskStatus = st; } bool TDEStorageDevice::checkDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus sf) { return ((m_diskStatus&sf)!=(TDEDiskDeviceStatus::TDEDiskDeviceStatus)0); } 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; } TQStringList &TDEStorageDevice::holdingDevices() { return m_holdingDevices; } void TDEStorageDevice::setHoldingDevices(TQStringList hd) { m_holdingDevices = hd; } TQStringList &TDEStorageDevice::slaveDevices() { return m_slaveDevices; } void TDEStorageDevice::setSlaveDevices(TQStringList sd) { m_slaveDevices = sd; } unsigned long TDEStorageDevice::deviceSize() { TQString bsnodename = systemPath(); bsnodename.append("/queue/physical_block_size"); TQFile bsfile( bsnodename ); TQString blocksize; if ( bsfile.open( IO_ReadOnly ) ) { TQTextStream stream( &bsfile ); blocksize = stream.readLine(); bsfile.close(); } else { // Drat, I can't get a gauranteed block size. Assume a block size of 512, as everything I have read indicates that /sys/block//size is given in terms of a 512 byte block... blocksize = "512"; } TQString dsnodename = systemPath(); dsnodename.append("/size"); TQFile dsfile( dsnodename ); TQString devicesize; if ( dsfile.open( IO_ReadOnly ) ) { TQTextStream stream( &dsfile ); devicesize = stream.readLine(); dsfile.close(); } return (blocksize.toULong()*devicesize.toULong()); } TQString TDEStorageDevice::deviceFriendlySize() { double bytes = deviceSize(); TQString prettystring; prettystring = TQString("%1b").arg(bytes); if (bytes > 1024) { bytes = bytes / 1024; prettystring = TQString("%1Kb").arg(bytes, 0, 'f', 1); } if (bytes > 1024) { bytes = bytes / 1024; prettystring = TQString("%1Mb").arg(bytes, 0, 'f', 1); } if (bytes > 1024) { bytes = bytes / 1024; prettystring = TQString("%1Gb").arg(bytes, 0, 'f', 1); } if (bytes > 1024) { bytes = bytes / 1024; prettystring = TQString("%1Tb").arg(bytes, 0, 'f', 1); } if (bytes > 1024) { bytes = bytes / 1024; prettystring = TQString("%1Pb").arg(bytes, 0, 'f', 1); } return prettystring; } TQString TDEStorageDevice::mountPath() { // See if this device node is mounted // This requires parsing /proc/mounts, looking for deviceNode() // The Device Mapper throws a monkey wrench into this // It likes to advertise mounts as /dev/mapper/, // where is listed in /dm/name // First, ensure that all device information (mainly holders/slaves) is accurate KGlobal::hardwareDevices()->rescanDeviceInformation(this); TQString dmnodename = systemPath(); dmnodename.append("/dm/name"); TQFile namefile( dmnodename ); TQString dmaltname; if ( namefile.open( IO_ReadOnly ) ) { TQTextStream stream( &namefile ); dmaltname = stream.readLine(); namefile.close(); } if (!dmaltname.isNull()) { dmaltname.prepend("/dev/mapper/"); } 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); TQString testNode = *mountInfo.at(0); // Check for match if ((testNode == deviceNode()) || (testNode == dmaltname)) { return *mountInfo.at(1); } lines += line; } file.close(); } // While this device is not directly mounted, it could concievably be mounted via the Device Mapper // If so, try to retrieve the mount path... TQStringList slaveDeviceList = holdingDevices(); for ( TQStringList::Iterator slavedevit = slaveDeviceList.begin(); slavedevit != slaveDeviceList.end(); ++slavedevit ) { // Try to locate this device path in the TDE device tree TDEHardwareDevices *hwdevices = KGlobal::hardwareDevices(); TDEGenericDevice *hwdevice = hwdevices->findBySystemPath(*slavedevit); if ((hwdevice) && (hwdevice->type() == TDEGenericDeviceType::Disk)) { TDEStorageDevice* sdevice = static_cast(hwdevice); return sdevice->mountPath(); } } return TQString::null; } TQString TDEStorageDevice::mountDevice(TQString mediaName, TQString mountOptions, TQString* errRet, int* retcode) { int internal_retcode; if (!retcode) { retcode = &internal_retcode; } TQString ret = mountPath(); if (!ret.isNull()) { return ret; } // Create dummy password file KTempFile passwordFile(TQString::null, "tmp", 0600); passwordFile.setAutoDelete(true); TQString command = TQString("pmount -p %1 %2 %3 2>&1").arg(passwordFile.name()).arg(mountOptions).arg(deviceNode()); if (!mediaName.isNull()) { command.append(mediaName); } FILE *exepipe = popen(command.ascii(), "r"); if (exepipe) { TQString pmount_output; char buffer[8092]; pmount_output = fgets(buffer, sizeof(buffer), exepipe); *retcode = pclose(exepipe); if (errRet) { *errRet = pmount_output; } } // Update internal mount data KGlobal::hardwareDevices()->processModifiedMounts(); ret = mountPath(); return ret; } TQString TDEStorageDevice::mountEncryptedDevice(TQString passphrase, TQString mediaName, TQString mountOptions, TQString* errRet, int* retcode) { int internal_retcode; if (!retcode) { retcode = &internal_retcode; } TQString ret = mountPath(); if (!ret.isNull()) { return ret; } // Create dummy password file KTempFile passwordFile(TQString::null, "tmp", 0600); passwordFile.setAutoDelete(true); TQFile* pwFile = passwordFile.file(); if (!pwFile) { return TQString::null; } pwFile->writeBlock(passphrase.ascii(), passphrase.length()); pwFile->flush(); TQString command = TQString("pmount -p %1 %2 %3 2>&1").arg(passwordFile.name()).arg(mountOptions).arg(deviceNode()); if (!mediaName.isNull()) { command.append(mediaName); } FILE *exepipe = popen(command.ascii(), "r"); if (exepipe) { TQString pmount_output; char buffer[8092]; pmount_output = fgets(buffer, sizeof(buffer), exepipe); *retcode = pclose(exepipe); if (errRet) { *errRet = pmount_output; } } // Update internal mount data KGlobal::hardwareDevices()->processModifiedMounts(); ret = mountPath(); return ret; } bool TDEStorageDevice::unmountDevice(TQString* errRet, int* retcode) { int internal_retcode; if (!retcode) { retcode = &internal_retcode; } TQString mountpoint = mountPath(); if (mountpoint.isNull()) { return true; } TQString command = TQString("pumount %1 2>&1").arg(mountpoint); FILE *exepipe = popen(command.ascii(), "r"); if (exepipe) { TQString pmount_output; char buffer[8092]; pmount_output = fgets(buffer, sizeof(buffer), exepipe); *retcode = pclose(exepipe); if (*retcode == 0) { return true; } else { if (errRet) { *errRet = pmount_output; } } } // Update internal mount data KGlobal::hardwareDevices()->processModifiedMounts(); return false; } TDEHardwareDevices::TDEHardwareDevices() { // Set up device list m_deviceList.setAutoDelete( TRUE ); // the list owns the objects // Initialize udev interface m_udevStruct = udev_new(); if (!m_udevStruct) { printf("Unable to create udev interface\n\r"); } 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_devScanNotifier = new TQSocketNotifier(udev_monitor_get_fd(m_udevMonitorStruct), TQSocketNotifier::Read, this); connect( m_devScanNotifier, TQT_SIGNAL(activated(int)), this, TQT_SLOT(processHotPluggedHardware()) ); // Read in the current mount table // Yes, a race condition exists between this and the mount monitor start below, but it shouldn't be a problem 99.99% of the time m_mountTable.clear(); TQFile file( "/proc/mounts" ); if ( file.open( IO_ReadOnly ) ) { TQTextStream stream( &file ); while ( !stream.atEnd() ) { m_mountTable.append(stream.readLine()); } file.close(); } // Monitor for changed mounts m_procMountsFd = open("/proc/mounts", O_RDONLY, 0); m_mountScanNotifier = new TQSocketNotifier(m_procMountsFd, TQSocketNotifier::Exception, this); connect( m_mountScanNotifier, TQT_SIGNAL(activated(int)), this, TQT_SLOT(processModifiedMounts()) ); // Update internal device information queryHardwareInformation(); } } TDEHardwareDevices::~TDEHardwareDevices() { // Stop mount scanning close(m_procMountsFd); // Tear down udev interface udev_unref(m_udevStruct); } void TDEHardwareDevices::rescanDeviceInformation(TDEGenericDevice* hwdevice) { struct udev_device *dev; dev = udev_device_new_from_syspath(m_udevStruct, hwdevice->systemPath().ascii()); classifyUnknownDevice(dev, hwdevice, false); updateParentDeviceInformation(hwdevice); // Update parent/child tables for this device udev_device_unref(dev); } TDEGenericDevice* TDEHardwareDevices::findBySystemPath(TQString syspath) { TDEGenericDevice *hwdevice; for ( hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next() ) { if (hwdevice->systemPath() == syspath) { return hwdevice; } } return 0; } TDEGenericDevice* TDEHardwareDevices::findByDeviceNode(TQString devnode) { TDEGenericDevice *hwdevice; for ( hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next() ) { if (hwdevice->deviceNode() == devnode) { return hwdevice; } } return 0; } TDEStorageDevice* TDEHardwareDevices::findDiskByUID(TQString uid) { TDEGenericDevice *hwdevice; for ( hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next() ) { if (hwdevice->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(hwdevice); if (sdevice->uniqueID() == uid) { return sdevice; } } } return 0; } void TDEHardwareDevices::processHotPluggedHardware() { 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); updateParentDeviceInformation(device); // Update parent/child tables for this 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) { emit hardwareRemoved(hwdevice); // If the device is a storage device and has a slave, update it as well if (hwdevice->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(hwdevice); TQStringList slavedevices = sdevice->slaveDevices(); m_deviceList.remove(hwdevice); for ( TQStringList::Iterator slaveit = slavedevices.begin(); slaveit != slavedevices.end(); ++slaveit ) { TDEGenericDevice* slavedevice = findBySystemPath(*slaveit); if (slavedevice) { rescanDeviceInformation(slavedevice); emit hardwareUpdated(slavedevice); } } } else { m_deviceList.remove(hwdevice); } break; } } } else if (actionevent == "change") { // Update device and emit change event TQString systempath(udev_device_get_syspath(dev)); TDEGenericDevice *hwdevice; for (hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next()) { if (hwdevice->systemPath() == systempath) { if (!hwdevice->blacklistedForUpdate()) { classifyUnknownDevice(dev, hwdevice, false); updateParentDeviceInformation(hwdevice); // Update parent/child tables for this device emit hardwareUpdated(hwdevice); } break; } } } } } void TDEHardwareDevices::processModifiedMounts() { // Detect what changed between the old mount table and the new one, // and emit appropriate events TQStringList deletedEntries = m_mountTable; // Read in the new mount table m_mountTable.clear(); TQFile file( "/proc/mounts" ); if ( file.open( IO_ReadOnly ) ) { TQTextStream stream( &file ); while ( !stream.atEnd() ) { m_mountTable.append(stream.readLine()); } file.close(); } TQStringList addedEntries = m_mountTable; // Remove all entries that are identical in both tables processModifiedMounts_removeagain: for ( TQStringList::Iterator delit = deletedEntries.begin(); delit != deletedEntries.end(); ++delit ) { for ( TQStringList::Iterator addit = addedEntries.begin(); addit != addedEntries.end(); ++addit ) { if ((*delit) == (*addit)) { deletedEntries.remove(delit); addedEntries.remove(addit); // Reset iterators to prevent bugs/crashes // FIXME // Is there any way to completely reset both loops without using goto? goto processModifiedMounts_removeagain; } } } TQStringList::Iterator it; for ( it = addedEntries.begin(); it != addedEntries.end(); ++it ) { TQStringList mountInfo = TQStringList::split(" ", (*it), true); // Try to find a device that matches the altered node TDEGenericDevice* hwdevice = findByDeviceNode(*mountInfo.at(0)); if (hwdevice) { emit hardwareUpdated(hwdevice); // If the device is a storage device and has a slave, update it as well if (hwdevice->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(hwdevice); TQStringList slavedevices = sdevice->slaveDevices(); for ( TQStringList::Iterator slaveit = slavedevices.begin(); slaveit != slavedevices.end(); ++slaveit ) { TDEGenericDevice* slavedevice = findBySystemPath(*slaveit); if (slavedevice) { emit hardwareUpdated(slavedevice); } } } } } for ( it = deletedEntries.begin(); it != deletedEntries.end(); ++it ) { TQStringList mountInfo = TQStringList::split(" ", (*it), true); // Try to find a device that matches the altered node TDEGenericDevice* hwdevice = findByDeviceNode(*mountInfo.at(0)); if (hwdevice) { emit hardwareUpdated(hwdevice); // If the device is a storage device and has a slave, update it as well if (hwdevice->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(hwdevice); TQStringList slavedevices = sdevice->slaveDevices(); for ( TQStringList::Iterator slaveit = slavedevices.begin(); slaveit != slavedevices.end(); ++slaveit ) { TDEGenericDevice* slavedevice = findBySystemPath(*slaveit); if (slavedevice) { emit hardwareUpdated(slavedevice); } } } } } emit mountTableModified(); } TDEDiskDeviceType::TDEDiskDeviceType classifyDiskType(udev_device* dev, const TQString &devicebus, const TQString &disktypestring, const TQString &systempath, const TQString &devicevendor, const TQString &devicemodel, const TQString &filesystemtype, const TQString &devicedriver) { // Classify a disk device type to the best of our ability TDEDiskDeviceType::TDEDiskDeviceType disktype = TDEDiskDeviceType::Null; 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 ((devicevendor.upper() == "APPLE") && (devicemodel.upper().contains("IPOD"))) { disktype = disktype | TDEDiskDeviceType::MediaDevice; } if ((devicevendor.upper() == "SANDISK") && (devicemodel.upper().contains("SANSA"))) { disktype = disktype | TDEDiskDeviceType::MediaDevice; } 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.isNull()) { // Fallback // If we can't recognize the disk type then set it as a simple HDD volume disktype = disktype | TDEDiskDeviceType::HDD; } // Certain combinations of media flags should never be set at the same time as they don't make sense // This block is needed as udev is more than happy to provide inconsistent data to us if ((disktype & TDEDiskDeviceType::Zip) || (disktype & TDEDiskDeviceType::Floppy) || (disktype & TDEDiskDeviceType::Jaz)) { 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_CD_RW")) == "1") { disktype = disktype | TDEDiskDeviceType::CDRW; 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; } } // 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; } if (filesystemtype.upper() == "CRYPTO_LUKS") { disktype = disktype | TDEDiskDeviceType::LUKS; } else if (filesystemtype.upper() == "CRYPTO") { disktype = disktype | TDEDiskDeviceType::OtherCrypted; } return disktype; } // KStandardDirs::kde_default typedef TQMap KConfigMap; TQString readUdevAttribute(udev_device* dev, TQString attr) { return TQString(udev_device_get_property_value(dev, attr.ascii())); } TDEGenericDeviceType::TDEGenericDeviceType readGenericDeviceTypeFromString(TQString query) { TDEGenericDeviceType::TDEGenericDeviceType ret = TDEGenericDeviceType::Other; // Keep this in sync with the TDEGenericDeviceType definition in the header if (query == "Root") { ret = TDEGenericDeviceType::Root; } else if (query == "CPU") { ret = TDEGenericDeviceType::CPU; } else if (query == "GPU") { ret = TDEGenericDeviceType::GPU; } else if (query == "RAM") { ret = TDEGenericDeviceType::RAM; } else if (query == "Mainboard") { ret = TDEGenericDeviceType::Mainboard; } else if (query == "Disk") { ret = TDEGenericDeviceType::Disk; } else if (query == "StorageController") { ret = TDEGenericDeviceType::StorageController; } else if (query == "Mouse") { ret = TDEGenericDeviceType::Mouse; } else if (query == "Keyboard") { ret = TDEGenericDeviceType::Keyboard; } else if (query == "HID") { ret = TDEGenericDeviceType::HID; } else if (query == "Network") { ret = TDEGenericDeviceType::Network; } else if (query == "Printer") { ret = TDEGenericDeviceType::Printer; } else if (query == "Scanner") { ret = TDEGenericDeviceType::Scanner; } else if (query == "Sound") { ret = TDEGenericDeviceType::Sound; } else if (query == "IEEE1394") { ret = TDEGenericDeviceType::IEEE1394; } else if (query == "Camera") { ret = TDEGenericDeviceType::Camera; } else if (query == "TextIO") { ret = TDEGenericDeviceType::TextIO; } else if (query == "Peripheral") { ret = TDEGenericDeviceType::Peripheral; } else if (query == "Battery") { ret = TDEGenericDeviceType::Battery; } else if (query == "Power") { ret = TDEGenericDeviceType::Power; } else if (query == "ThermalSensor") { ret = TDEGenericDeviceType::ThermalSensor; } else if (query == "ThermalControl") { ret = TDEGenericDeviceType::ThermalControl; } else if (query == "OtherACPI") { ret = TDEGenericDeviceType::OtherACPI; } else if (query == "OtherUSB") { ret = TDEGenericDeviceType::OtherUSB; } else if (query == "OtherPeripheral") { ret = TDEGenericDeviceType::OtherPeripheral; } else if (query == "OtherSensor") { ret = TDEGenericDeviceType::OtherSensor; } else { ret = TDEGenericDeviceType::Other; } return ret; } TDEDiskDeviceType::TDEDiskDeviceType readDiskDeviceSubtypeFromString(TQString query, TDEDiskDeviceType::TDEDiskDeviceType flagsIn=TDEDiskDeviceType::Null) { TDEDiskDeviceType::TDEDiskDeviceType ret = flagsIn; // Keep this in sync with the TDEDiskDeviceType definition in the header if (query == "MediaDevice") { ret = ret | TDEDiskDeviceType::MediaDevice; } if (query == "Floppy") { ret = ret | TDEDiskDeviceType::Floppy; } if (query == "CDROM") { ret = ret | TDEDiskDeviceType::CDROM; } if (query == "CDRW") { ret = ret | TDEDiskDeviceType::CDRW; } if (query == "DVDROM") { ret = ret | TDEDiskDeviceType::DVDROM; } if (query == "DVDRAM") { ret = ret | TDEDiskDeviceType::DVDRAM; } if (query == "DVDRW") { ret = ret | TDEDiskDeviceType::DVDRW; } if (query == "BDROM") { ret = ret | TDEDiskDeviceType::BDROM; } if (query == "BDRW") { ret = ret | TDEDiskDeviceType::BDRW; } if (query == "Zip") { ret = ret | TDEDiskDeviceType::Zip; } if (query == "Jaz") { ret = ret | TDEDiskDeviceType::Jaz; } if (query == "Camera") { ret = ret | TDEDiskDeviceType::Camera; } if (query == "LUKS") { ret = ret | TDEDiskDeviceType::LUKS; } if (query == "OtherCrypted") { ret = ret | TDEDiskDeviceType::OtherCrypted; } if (query == "CDAudio") { ret = ret | TDEDiskDeviceType::CDAudio; } if (query == "CDVideo") { ret = ret | TDEDiskDeviceType::CDVideo; } if (query == "DVDVideo") { ret = ret | TDEDiskDeviceType::DVDVideo; } if (query == "BDVideo") { ret = ret | TDEDiskDeviceType::BDVideo; } if (query == "Flash") { ret = ret | TDEDiskDeviceType::Flash; } if (query == "USB") { ret = ret | TDEDiskDeviceType::USB; } if (query == "Tape") { ret = ret | TDEDiskDeviceType::Tape; } if (query == "HDD") { ret = ret | TDEDiskDeviceType::HDD; } if (query == "Optical") { ret = ret | TDEDiskDeviceType::Optical; } if (query == "RAM") { ret = ret | TDEDiskDeviceType::RAM; } if (query == "Loop") { ret = ret | TDEDiskDeviceType::Loop; } if (query == "CompactFlash") { ret = ret | TDEDiskDeviceType::CompactFlash; } if (query == "MemoryStick") { ret = ret | TDEDiskDeviceType::MemoryStick; } if (query == "SmartMedia") { ret = ret | TDEDiskDeviceType::SmartMedia; } if (query == "SDMMC") { ret = ret | TDEDiskDeviceType::SDMMC; } if (query == "UnlockedCrypt") { ret = ret | TDEDiskDeviceType::UnlockedCrypt; } return ret; } TDEGenericDevice* createDeviceObjectForType(TDEGenericDeviceType::TDEGenericDeviceType type) { TDEGenericDevice* ret = 0; if (type == TDEGenericDeviceType::Disk) { ret = new TDEStorageDevice(type); } else { ret = new TDEGenericDevice(type); } return ret; } TDEGenericDevice* TDEHardwareDevices::classifyUnknownDeviceByExternalRules(udev_device* dev, TDEGenericDevice* existingdevice, bool classifySubDevices) { // This routine expects to see the hardware config files into /share/apps/tdehwlib/deviceclasses/, suffixed with "hwclass" TDEGenericDevice* device = existingdevice; if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::Other); // Handle subtype if needed/desired // To speed things up we rely on the prior scan results stored in m_externalSubtype if (classifySubDevices) { if (!device->m_externalRulesFile.isNull()) { if (device->type() == TDEGenericDeviceType::Disk) { // Disk class TDEStorageDevice* sdevice = static_cast(device); TQStringList subtype = device->m_externalSubtype; TDEDiskDeviceType::TDEDiskDeviceType desiredSubdeviceType = TDEDiskDeviceType::Null; if (subtype.count()>0) { for ( TQStringList::Iterator paramit = subtype.begin(); paramit != subtype.end(); ++paramit ) { desiredSubdeviceType = readDiskDeviceSubtypeFromString(*paramit, desiredSubdeviceType); } if (desiredSubdeviceType != sdevice->diskType()) { printf("[tdehardwaredevices] Rules file %s used to set device subtype for device at path %s\n\r", device->m_externalRulesFile.ascii(), device->systemPath().ascii()); fflush(stdout); sdevice->setDiskType(desiredSubdeviceType); } } } } } else { TQStringList hardware_info_directories(KGlobal::dirs()->resourceDirs("data")); TQString hardware_info_directory_suffix("tdehwlib/deviceclasses/"); TQString hardware_info_directory; // Scan the hardware_info_directory for configuration files // For each one, open it with KConfig() and apply its rules to classify the device // FIXME // Should this also scan up to subdirectories for the files? That feature might end up being too expensive... device->m_externalRulesFile = TQString::null; for ( TQStringList::Iterator it = hardware_info_directories.begin(); it != hardware_info_directories.end(); ++it ) { hardware_info_directory = (*it); hardware_info_directory += hardware_info_directory_suffix; if (KGlobal::dirs()->exists(hardware_info_directory)) { TQDir d(hardware_info_directory); d.setFilter( TQDir::Files | TQDir::Hidden ); const TQFileInfoList *list = d.entryInfoList(); TQFileInfoListIterator it( *list ); TQFileInfo *fi; while ((fi = it.current()) != 0) { if (fi->extension(false) == "hwclass") { bool match = true; // Open the rules file KConfig rulesFile(fi->absFilePath(), true, false); rulesFile.setGroup("Conditions"); KConfigMap conditionmap = rulesFile.entryMap("Conditions"); KConfigMap::Iterator cndit; for (cndit = conditionmap.begin(); cndit != conditionmap.end(); ++cndit) { TQStringList conditionList = TQStringList::split(',', cndit.data(), false); bool atleastonematch = false; for ( TQStringList::Iterator paramit = conditionList.begin(); paramit != conditionList.end(); ++paramit ) { if (cndit.key() == "VENDOR_ID") { if (device->vendorID() == (*paramit)) { atleastonematch = true; } } else if (cndit.key() == "MODEL_ID") { if (device->modelID() == (*paramit)) { atleastonematch = true; } } else if (readUdevAttribute(dev, cndit.key()) == (*paramit)) { atleastonematch = true; } } if (!atleastonematch) { match = false; } } if (match) { rulesFile.setGroup("DeviceType"); TQString gentype = rulesFile.readEntry("GENTYPE"); TDEGenericDeviceType::TDEGenericDeviceType desiredDeviceType = device->type(); if (!gentype.isNull()) { desiredDeviceType = readGenericDeviceTypeFromString(gentype); } // Handle main type if (desiredDeviceType != device->type()) { printf("[tdehardwaredevices] Rules file %s used to set device type for device at path %s\n\r", fi->absFilePath().ascii(), device->systemPath().ascii()); fflush(stdout); if (m_deviceList.contains(device)) { m_deviceList.remove(device); } else { delete device; } device = createDeviceObjectForType(desiredDeviceType); } // Parse subtype and store in m_externalSubtype for later // This speeds things up considerably due to the expense of the file scanning/parsing/matching operation device->m_externalSubtype = rulesFile.readListEntry("SUBTYPE", ','); device->m_externalRulesFile = fi->absFilePath(); // Process blacklist entries rulesFile.setGroup("DeviceSettings"); device->setBlacklistedForUpdate(rulesFile.readBoolEntry("UPDATE_BLACKLISTED", device->blacklistedForUpdate())); } } ++it; } } } } return device; } TDEGenericDevice* TDEHardwareDevices::classifyUnknownDevice(udev_device* dev, TDEGenericDevice* existingdevice, bool force_full_classification) { // 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)); TQString devicevendorid(udev_device_get_property_value(dev, "ID_VENDOR_ID")); TQString devicemodelid(udev_device_get_property_value(dev, "ID_MODEL_ID")); bool removable = false; TDEGenericDevice* device = existingdevice; // 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 // Many devices do not provide their vendor/model ID via udev // Go after it manually... if (devicevendorid.isNull() || devicemodelid.isNull()) { bool done = false; TQString current_path = systempath; TQString modalias_string = TQString::null; while (done == false) { TQString malnodename = current_path; malnodename.append("/modalias"); TQFile malfile(malnodename); if (malfile.open(IO_ReadOnly)) { TQTextStream stream( &malfile ); modalias_string = stream.readLine(); malfile.close(); } if (modalias_string.startsWith("pci") || modalias_string.startsWith("usb")) { done = true; } else { modalias_string = TQString::null; current_path.truncate(current_path.findRev("/")); if (!current_path.startsWith("/sys/devices")) { // Abort! done = true; } } } if (modalias_string != TQString::null) { int vloc = modalias_string.find("v"); int dloc = modalias_string.find("d", vloc); // For added fun the device string lengths differ between pci and usb if (modalias_string.startsWith("pci")) { devicevendorid = modalias_string.mid(vloc+1, 8).lower(); devicemodelid = modalias_string.mid(dloc+1, 8).lower(); devicevendorid.remove(0,4); devicemodelid.remove(0,4); } if (modalias_string.startsWith("usb")) { devicevendorid = modalias_string.mid(vloc+1, 4).lower(); devicemodelid = modalias_string.mid(dloc+1, 4).lower(); } } } // Classify generic device type and create appropriate object if ((devicetype == "disk") || (devicetype == "partition") || (devicedriver == "floppy") ) { if (!device) device = new TDEStorageDevice(TDEGenericDeviceType::Disk); } else if (devicetype.isNull()) { if (devicesubsystem == "acpi") { if (!device) 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")) { if (!device) 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) { if (!device) 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) { if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::Keyboard); } } if (!device) { if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::HID); } } else if (devicesubsystem == "tty") { if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::TextIO); } else if (devicesubsystem == "thermal") { // FIXME // Figure out a way to differentiate between ThermalControl (fans and coolers) and ThermalSensor types if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::ThermalControl); } else if (devicesubsystem == "hwmon") { // FIXME // This might pick up thermal sensors if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::OtherSensor); } } if (device == 0) { // Unhandled if (!device) device = new TDEGenericDevice(TDEGenericDeviceType::Other); printf("[FIXME] UNCLASSIFIED DEVICE name: %s type: %s subsystem: %s driver: %s [Node Path: %s] [Syspath: %s] [%s:%s]\n\r", devicename.ascii(), devicetype.ascii(), devicesubsystem.ascii(), devicedriver.ascii(), devicenode.ascii(), udev_device_get_syspath(dev), devicevendorid.ascii(), devicemodelid.ascii()); fflush(stdout); } // Set preliminary basic device information device->setName(devicename); device->setDeviceNode(devicenode); device->setSystemPath(systempath); device->setVendorID(devicevendorid); device->setModelID(devicemodelid); updateBlacklists(device, dev); if (force_full_classification) { // Check external rules for possible device type overrides device = classifyUnknownDeviceByExternalRules(dev, device, false); } if (device->type() == TDEGenericDeviceType::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); } // See if any other devices are exclusively using this device, such as the Device Mapper| TQStringList holdingDeviceNodes; TQString holdersnodename = udev_device_get_syspath(dev); holdersnodename.append("/holders/"); TQDir holdersdir(holdersnodename); holdersdir.setFilter(TQDir::All); const TQFileInfoList *dirlist = holdersdir.entryInfoList(); if (dirlist) { TQFileInfoListIterator holdersdirit(*dirlist); TQFileInfo *dirfi; while ( (dirfi = holdersdirit.current()) != 0 ) { if (dirfi->isSymLink()) { char* collapsedPath = realpath((holdersnodename + dirfi->readLink()).ascii(), NULL); holdingDeviceNodes.append(TQString(collapsedPath)); free(collapsedPath); } ++holdersdirit; } } // See if any other physical devices underlie this device, for example when the Device Mapper is in use TQStringList slaveDeviceNodes; TQString slavesnodename = udev_device_get_syspath(dev); slavesnodename.append("/slaves/"); TQDir slavedir(slavesnodename); slavedir.setFilter(TQDir::All); dirlist = slavedir.entryInfoList(); if (dirlist) { TQFileInfoListIterator slavedirit(*dirlist); TQFileInfo *dirfi; while ( (dirfi = slavedirit.current()) != 0 ) { if (dirfi->isSymLink()) { char* collapsedPath = realpath((slavesnodename + dirfi->readLink()).ascii(), NULL); slaveDeviceNodes.append(TQString(collapsedPath)); free(collapsedPath); } ++slavedirit; } } // 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(device); TDEDiskDeviceType::TDEDiskDeviceType disktype = sdevice->diskType(); TDEDiskDeviceStatus::TDEDiskDeviceStatus diskstatus = sdevice->diskStatus(); if (force_full_classification) { disktype = classifyDiskType(dev, devicebus, disktypestring, systempath, devicevendor, devicemodel, filesystemtype, devicedriver); sdevice->setDiskType(disktype); device = classifyUnknownDeviceByExternalRules(dev, device, true); // Check external rules for possible subtype overrides disktype = sdevice->diskType(); // The type can be overridden by an external rule } if ((disktype & TDEDiskDeviceType::CDROM) || (disktype & TDEDiskDeviceType::CDRW) || (disktype & TDEDiskDeviceType::DVDROM) || (disktype & TDEDiskDeviceType::DVDRAM) || (disktype & TDEDiskDeviceType::DVDRW) || (disktype & TDEDiskDeviceType::BDROM) || (disktype & TDEDiskDeviceType::BDRW) || (disktype & TDEDiskDeviceType::CDAudio) || (disktype & TDEDiskDeviceType::CDVideo) || (disktype & TDEDiskDeviceType::DVDVideo) || (disktype & TDEDiskDeviceType::BDVideo) ) { // These drives are guaranteed to be optical disktype = disktype | TDEDiskDeviceType::Optical; } if (disktype & TDEDiskDeviceType::Floppy) { // Floppy drives don't work well under udev // I have to look for the block device name manually TQString floppyblknodename = systempath; floppyblknodename.append("/block"); TQDir floppyblkdir(floppyblknodename); floppyblkdir.setFilter(TQDir::All); const TQFileInfoList *floppyblkdirlist = floppyblkdir.entryInfoList(); if (floppyblkdirlist) { TQFileInfoListIterator floppyblkdirit(*floppyblkdirlist); TQFileInfo *dirfi; while ( (dirfi = floppyblkdirit.current()) != 0 ) { if ((dirfi->fileName() != ".") && (dirfi->fileName() != "..")) { // Does this routine work with more than one floppy drive in the system? devicenode = TQString("/dev/").append(dirfi->fileName()); } ++floppyblkdirit; } } // Some interesting information can be gleaned from the CMOS type file // 0 : Defaults // 1 : 5 1/4 DD // 2 : 5 1/4 HD // 3 : 3 1/2 DD // 4 : 3 1/2 HD // 5 : 3 1/2 ED // 6 : 3 1/2 ED // 16 : unknown or not installed TQString floppycmsnodename = systempath; floppycmsnodename.append("/cmos"); TQFile floppycmsfile( floppycmsnodename ); TQString cmosstring; if ( floppycmsfile.open( IO_ReadOnly ) ) { TQTextStream stream( &floppycmsfile ); cmosstring = stream.readLine(); floppycmsfile.close(); } // FIXME // Do something with the information in cmosstring if (devicenode.isNull()) { // This floppy drive cannot be mounted, so ignore it disktype = disktype & ~TDEDiskDeviceType::Floppy; } } if (disktypestring.upper() == "CD") { 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 (disktype & TDEDiskDeviceType::Zip) { // A Zip drive does not advertise its status via udev, but it can be guessed from the size parameter TQString zipnodename = systempath; zipnodename.append("/size"); TQFile namefile( zipnodename ); TQString zipsize; if ( namefile.open( IO_ReadOnly ) ) { TQTextStream stream( &namefile ); zipsize = stream.readLine(); namefile.close(); } if (!zipsize.isNull()) { sdevice->setMediaInserted((zipsize.toInt() != 0)); } } if (removable) { diskstatus = diskstatus | TDEDiskDeviceStatus::Removable; } if ((filesystemtype.upper() != "CRYPTO_LUKS") && (filesystemtype.upper() != "CRYPTO") && (!filesystemtype.isNull())) { diskstatus = diskstatus | TDEDiskDeviceStatus::ContainsFilesystem; } // 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 (removable) { if (sdevice->mediaInserted()) { diskstatus = diskstatus | TDEDiskDeviceStatus::Inserted; } else { diskstatus = diskstatus & ~TDEDiskDeviceStatus::Mountable; } } if (holdingDeviceNodes.count() > 0) { diskstatus = diskstatus | TDEDiskDeviceStatus::UsedByDevice; } if (slaveDeviceNodes.count() > 0) { diskstatus = diskstatus | TDEDiskDeviceStatus::UsesDevice; } // See if any slaves were crypted for ( TQStringList::Iterator slaveit = slaveDeviceNodes.begin(); slaveit != slaveDeviceNodes.end(); ++slaveit ) { struct udev_device *slavedev; slavedev = udev_device_new_from_syspath(m_udevStruct, (*slaveit).ascii()); TQString slavediskfstype(udev_device_get_property_value(slavedev, "ID_FS_TYPE")); if ((slavediskfstype.upper() == "CRYPTO_LUKS") || (slavediskfstype.upper() == "CRYPTO")) { disktype = disktype | TDEDiskDeviceType::UnlockedCrypt; // Set disk type based on parent device disktype = disktype | classifyDiskType(slavedev, TQString(udev_device_get_property_value(dev, "ID_BUS")), TQString(udev_device_get_property_value(dev, "ID_TYPE")), (*slaveit), TQString(udev_device_get_property_value(dev, "ID_VENDOR")), TQString(udev_device_get_property_value(dev, "ID_MODEL")), TQString(udev_device_get_property_value(dev, "ID_FS_TYPE")), TQString(udev_device_get_driver(dev))); } udev_device_unref(slavedev); } sdevice->setDiskType(disktype); sdevice->setDiskUUID(diskuuid); sdevice->setDiskStatus(diskstatus); sdevice->setFileSystemName(filesystemtype); sdevice->setFileSystemUsage(filesystemusage); sdevice->setSlaveDevices(slaveDeviceNodes); sdevice->setHoldingDevices(holdingDeviceNodes); // Clean up disk label if ((sdevice->isDiskOfType(TDEDiskDeviceType::CDROM)) || (sdevice->isDiskOfType(TDEDiskDeviceType::CDRW)) || (sdevice->isDiskOfType(TDEDiskDeviceType::DVDROM)) || (sdevice->isDiskOfType(TDEDiskDeviceType::DVDRW)) || (sdevice->isDiskOfType(TDEDiskDeviceType::BDROM)) || (sdevice->isDiskOfType(TDEDiskDeviceType::BDRW)) || (sdevice->isDiskOfType(TDEDiskDeviceType::CDAudio)) || (sdevice->isDiskOfType(TDEDiskDeviceType::CDVideo)) || (sdevice->isDiskOfType(TDEDiskDeviceType::DVDVideo)) || (sdevice->isDiskOfType(TDEDiskDeviceType::BDVideo)) ) { if (disklabel == "" && sdevice->diskLabel().isNull()) { // Read the volume label in via volname, since udev couldn't be bothered to do this on its own FILE *exepipe = popen(((TQString("volname %1").arg(devicenode).ascii())), "r"); if (exepipe) { char buffer[8092]; disklabel = fgets(buffer, sizeof(buffer), exepipe); pclose(exepipe); } } } sdevice->setDiskLabel(disklabel); } // Set basic device information again, as some information may have changed device->setName(devicename); device->setDeviceNode(devicenode); device->setSystemPath(systempath); device->setVendorID(devicevendorid); device->setModelID(devicemodelid); return device; } void TDEHardwareDevices::updateBlacklists(TDEGenericDevice* hwdevice, udev_device* dev) { // HACK // I am lucky enough to have a Flash drive that spams udev continually with device change events // I imagine I am not the only one, so here is a section in which specific devices can be blacklisted! // For "U3 System" fake CD if ((hwdevice->vendorID() == "08ec") && (hwdevice->modelID() == "0020") && (TQString(udev_device_get_property_value(dev, "ID_TYPE")) == "cd")) { hwdevice->setBlacklistedForUpdate(true); } } bool TDEHardwareDevices::queryHardwareInformation() { if (!m_udevStruct) { return false; } // Prepare the device list for repopulation m_deviceList.clear(); addCoreSystemDevices(); struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; struct udev_device *dev; // Create a list of all devices enumerate = udev_enumerate_new(m_udevStruct); udev_enumerate_add_match_subsystem(enumerate, NULL); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); // 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); 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); } udev_device_unref(dev); } // Free the enumerator object udev_enumerate_unref(enumerate); // Update parent/child tables for all devices updateParentDeviceInformation(); return true; } void TDEHardwareDevices::updateParentDeviceInformation(TDEGenericDevice* hwdevice) { // Scan for the first path up the sysfs tree that is available in the main hardware table bool done = false; TQString current_path = hwdevice->systemPath(); TDEGenericDevice* parentdevice = 0; if (current_path.endsWith("/")) { current_path.truncate(current_path.findRev("/")); } while (done == false) { current_path.truncate(current_path.findRev("/")); if (current_path.startsWith("/sys/devices")) { if (current_path.endsWith("/")) { current_path.truncate(current_path.findRev("/")); } parentdevice = findBySystemPath(current_path); if (parentdevice) { done = true; } } else { // Abort! done = true; } } hwdevice->setParentDevice(parentdevice); } void TDEHardwareDevices::updateParentDeviceInformation() { TDEGenericDevice *hwdevice; // We can't use m_deviceList directly as m_deviceList can only have one iterator active against it at any given time TDEGenericHardwareList devList = listAllPhysicalDevices(); for ( hwdevice = devList.first(); hwdevice; hwdevice = devList.next() ) { updateParentDeviceInformation(hwdevice); } } void TDEHardwareDevices::addCoreSystemDevices() { // Add core top-level devices in /sys/devices to the hardware listing TQStringList holdingDeviceNodes; TQString devicesnodename = "/sys/devices"; TQDir devicesdir(devicesnodename); devicesdir.setFilter(TQDir::All); TQString nodename; TDEGenericDevice *hwdevice; const TQFileInfoList *dirlist = devicesdir.entryInfoList(); if (dirlist) { TQFileInfoListIterator devicesdirit(*dirlist); TQFileInfo *dirfi; while ( (dirfi = devicesdirit.current()) != 0 ) { nodename = dirfi->fileName(); if (nodename != "." && nodename != "..") { hwdevice = new TDEGenericDevice(TDEGenericDeviceType::Root); hwdevice->setSystemPath(dirfi->absFilePath()); m_deviceList.append(hwdevice); } ++devicesdirit; } } } TQPtrList TDEHardwareDevices::listByDeviceClass(TDEGenericDeviceType::TDEGenericDeviceType cl) { TDEGenericHardwareList ret; ret.setAutoDelete(false); TDEGenericDevice *hwdevice; for ( hwdevice = m_deviceList.first(); hwdevice; hwdevice = m_deviceList.next() ) { if (hwdevice->type() == cl) { ret.append(hwdevice); } } return ret; } TDEGenericHardwareList TDEHardwareDevices::listAllPhysicalDevices() { TDEGenericHardwareList ret = m_deviceList; ret.setAutoDelete(false); return ret; } #include "tdehardwaredevices.moc"