File indexing completed on 2025-03-16 04:29:56
0001 /* 0002 SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0004 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "k3bdevicemanager.h" 0010 #include "k3bdevice.h" 0011 #include "k3bdeviceglobals.h" 0012 #include "k3bscsicommand.h" 0013 #include "k3bmmc.h" 0014 0015 #include <config-k3b.h> 0016 0017 #include <KConfig> 0018 #include <KConfigGroup> 0019 0020 #include <Solid/DeviceNotifier> 0021 #include <Solid/DeviceInterface> 0022 #include <Solid/OpticalDrive> 0023 #include <Solid/Block> 0024 #include <Solid/Device> 0025 #ifdef Q_OS_NETBSD 0026 #include <Solid/GenericInterface> 0027 #endif 0028 0029 #include <QDebug> 0030 #include <QString> 0031 #include <QStringList> 0032 #include <QFile> 0033 #include <QFileInfo> 0034 #include <QRegExp> 0035 #include <QTemporaryFile> 0036 0037 #include <iostream> 0038 #include <limits.h> 0039 #include <assert.h> 0040 0041 #ifdef Q_OS_FREEBSD 0042 #include <sys/param.h> 0043 #include <sys/ucred.h> 0044 #include <osreldate.h> 0045 #endif 0046 0047 #include <stdio.h> 0048 #include <stdlib.h> 0049 #include <fcntl.h> 0050 #include <unistd.h> 0051 #include <errno.h> 0052 #include <sys/stat.h> 0053 #include <sys/ioctl.h> 0054 0055 #ifdef HAVE_RESMGR 0056 #include <resmgr.h> 0057 #endif 0058 0059 #ifdef Q_OS_LINUX 0060 #include <sys/utsname.h> 0061 /* Fix definitions for 2.5 kernels */ 0062 #include <linux/version.h> 0063 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) 0064 typedef unsigned char u8; 0065 #endif 0066 0067 #undef __STRICT_ANSI__ 0068 #include <asm/types.h> 0069 #define __STRICT_ANSI__ 0070 0071 #include <scsi/scsi.h> 0072 #include <linux/major.h> 0073 0074 0075 #ifndef SCSI_DISK_MAJOR 0076 #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ 0077 ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ 0078 ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) 0079 #endif 0080 0081 #ifndef SCSI_BLK_MAJOR 0082 #define SCSI_BLK_MAJOR(M) \ 0083 (SCSI_DISK_MAJOR(M) \ 0084 || (M) == SCSI_CDROM_MAJOR) 0085 #endif 0086 0087 #ifndef SCSI_GENERIC_MAJOR 0088 #define SCSI_GENERIC_MAJOR 21 0089 #endif 0090 0091 #endif // Q_OS_LINUX 0092 0093 0094 #ifdef Q_OS_FREEBSD 0095 #include <cam/cam.h> 0096 #include <cam/scsi/scsi_pass.h> 0097 #include <camlib.h> 0098 #endif 0099 0100 #ifdef Q_OS_NETBSD 0101 #include <sys/scsiio.h> 0102 #endif 0103 0104 0105 0106 class K3b::Device::DeviceManager::Private 0107 { 0108 public: 0109 QList<Device*> allDevices; 0110 QList<Device*> cdReader; 0111 QList<Device*> cdWriter; 0112 QList<Device*> dvdReader; 0113 QList<Device*> dvdWriter; 0114 QList<Device*> bdReader; 0115 QList<Device*> bdWriter; 0116 0117 bool checkWritingModes; 0118 }; 0119 0120 0121 0122 K3b::Device::DeviceManager::DeviceManager( QObject* parent ) 0123 : QObject( parent ), 0124 d( new Private() ) 0125 { 0126 connect( Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), 0127 this, SLOT(slotSolidDeviceAdded(QString)) ); 0128 connect( Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), 0129 this, SLOT(slotSolidDeviceRemoved(QString)) ); 0130 } 0131 0132 0133 K3b::Device::DeviceManager::~DeviceManager() 0134 { 0135 qDeleteAll( d->allDevices ); 0136 delete d; 0137 } 0138 0139 0140 void K3b::Device::DeviceManager::setCheckWritingModes( bool b ) 0141 { 0142 d->checkWritingModes = b; 0143 } 0144 0145 0146 K3b::Device::Device* K3b::Device::DeviceManager::deviceByName( const QString& name ) 0147 { 0148 return findDevice( name ); 0149 } 0150 0151 0152 K3b::Device::Device* K3b::Device::DeviceManager::findDevice( const QString& devicename ) 0153 { 0154 if( devicename.isEmpty() ) { 0155 qDebug() << "(K3b::Device::DeviceManager) request for empty device!"; 0156 return 0; 0157 } 0158 0159 foreach( Device* dev, d->allDevices ) { 0160 if( dev->blockDeviceName() == devicename ) 0161 return dev; 0162 } 0163 0164 return 0; 0165 } 0166 0167 0168 K3b::Device::Device* K3b::Device::DeviceManager::findDeviceByUdi( const QString& udi ) 0169 { 0170 foreach( Device* dev, d->allDevices ) { 0171 if ( dev->solidDevice().udi() == udi ) 0172 return dev; 0173 } 0174 return 0; 0175 } 0176 0177 0178 QList<K3b::Device::Device*> K3b::Device::DeviceManager::cdWriter() const 0179 { 0180 return d->cdWriter; 0181 } 0182 0183 QList<K3b::Device::Device*> K3b::Device::DeviceManager::cdReader() const 0184 { 0185 return d->cdReader; 0186 } 0187 0188 QList<K3b::Device::Device*> K3b::Device::DeviceManager::dvdWriter() const 0189 { 0190 return d->dvdWriter; 0191 } 0192 0193 QList<K3b::Device::Device*> K3b::Device::DeviceManager::dvdReader() const 0194 { 0195 return d->dvdReader; 0196 } 0197 0198 QList<K3b::Device::Device*> K3b::Device::DeviceManager::blueRayReader() const 0199 { 0200 return d->bdReader; 0201 } 0202 0203 QList<K3b::Device::Device*> K3b::Device::DeviceManager::blueRayWriters() const 0204 { 0205 return d->bdWriter; 0206 } 0207 0208 QList<K3b::Device::Device*> K3b::Device::DeviceManager::burningDevices() const 0209 { 0210 return cdWriter(); 0211 } 0212 0213 0214 QList<K3b::Device::Device*> K3b::Device::DeviceManager::readingDevices() const 0215 { 0216 return cdReader(); 0217 } 0218 0219 0220 QList<K3b::Device::Device*> K3b::Device::DeviceManager::allDevices() const 0221 { 0222 return d->allDevices; 0223 } 0224 0225 0226 int K3b::Device::DeviceManager::scanBus() 0227 { 0228 int cnt = 0; 0229 0230 QList<Solid::Device> dl = Solid::Device::listFromType( Solid::DeviceInterface::OpticalDrive ); 0231 Q_FOREACH( const Solid::Device& solidDev, dl ) { 0232 if ( checkDevice( solidDev ) ) { 0233 ++cnt; 0234 } 0235 } 0236 0237 return cnt; 0238 } 0239 0240 0241 K3b::Device::Device* K3b::Device::DeviceManager::checkDevice( const Solid::Device& dev ) 0242 { 0243 if ( dev.is<Solid::OpticalDrive>() ) { 0244 return addDevice( dev ); 0245 } 0246 else { 0247 return 0; 0248 } 0249 } 0250 0251 0252 void K3b::Device::DeviceManager::printDevices() 0253 { 0254 qDebug() << "Devices:" << Qt::endl 0255 << "------------------------------" << Qt::endl; 0256 Q_FOREACH( Device* dev, d->allDevices ) { 0257 qDebug() << "Blockdevice: " << dev->blockDeviceName() << Qt::endl 0258 << "Vendor: " << dev->vendor() << Qt::endl 0259 << "Description: " << dev->description() << Qt::endl 0260 << "Version: " << dev->version() << Qt::endl 0261 << "Write speed: " << dev->maxWriteSpeed() << Qt::endl 0262 << "Profiles: " << mediaTypeString( dev->supportedProfiles() ) << Qt::endl 0263 << "Read Cap: " << mediaTypeString( dev->readCapabilities() ) << Qt::endl 0264 << "Write Cap: " << mediaTypeString( dev->writeCapabilities() ) << Qt::endl 0265 << "Writing modes: " << writingModeString( dev->writingModes() ) << Qt::endl 0266 << "------------------------------" << Qt::endl; 0267 } 0268 } 0269 0270 0271 void K3b::Device::DeviceManager::clear() 0272 { 0273 // clear current devices 0274 d->cdReader.clear(); 0275 d->cdWriter.clear(); 0276 d->dvdReader.clear(); 0277 d->dvdWriter.clear(); 0278 d->bdReader.clear(); 0279 d->bdWriter.clear(); 0280 0281 // to make sure no one crashes lets keep the devices around until the changed 0282 // signals return 0283 QList<Device*> devicesToDelete( d->allDevices ); 0284 d->allDevices.clear(); 0285 0286 emit changed( this ); 0287 emit changed(); 0288 0289 qDeleteAll( devicesToDelete ); 0290 } 0291 0292 0293 bool K3b::Device::DeviceManager::readConfig( const KConfigGroup& c ) 0294 { 0295 // 0296 // New configuration format since K3b 0.11.94 0297 // for details see saveConfig() 0298 // 0299 0300 // 0301 // Iterate over all devices and check if we have a config entry 0302 // 0303 for( QList<K3b::Device::Device*>::iterator it = d->allDevices.begin(); it != d->allDevices.end(); ++it ) { 0304 K3b::Device::Device* dev = *it; 0305 0306 QString configEntryName = dev->vendor() + ' ' + dev->description(); 0307 QStringList list = c.readEntry( configEntryName, QStringList() ); 0308 if( !list.isEmpty() ) { 0309 qDebug() << "(K3b::Device::DeviceManager) found config entry for devicetype: " << configEntryName; 0310 0311 dev->setMaxReadSpeed( list[0].toInt() ); 0312 if( list.count() > 1 ) 0313 dev->setMaxWriteSpeed( list[1].toInt() ); 0314 } 0315 } 0316 0317 return true; 0318 } 0319 0320 0321 bool K3b::Device::DeviceManager::saveConfig( KConfigGroup c ) 0322 { 0323 // 0324 // New configuration format since K3b 0.11.94 0325 // 0326 // We save a device search path which contains all device nodes 0327 // where devices could be found including the old search path. 0328 // This way also for example a manually added USB device will be 0329 // found between sessions. 0330 // Then we do not save the device settings (writing speed, cdrdao driver) 0331 // for every single device but for every device type. 0332 // This also makes sure device settings are kept between sessions 0333 // 0334 0335 Q_FOREACH( Device* dev, d->allDevices ) { 0336 0337 // save the device type settings 0338 QString configEntryName = dev->vendor() + ' ' + dev->description(); 0339 QStringList list; 0340 list << QString::number(dev->maxReadSpeed()) 0341 << QString::number(dev->maxWriteSpeed()); 0342 0343 c.writeEntry( configEntryName, list ); 0344 } 0345 0346 return true; 0347 } 0348 0349 0350 K3b::Device::Device* K3b::Device::DeviceManager::addDevice( const Solid::Device& solidDevice ) 0351 { 0352 if( const Solid::Block* blockDevice = solidDevice.as<Solid::Block>() ) { 0353 #ifndef Q_OS_NETBSD 0354 if( !findDevice( blockDevice->device() ) ) 0355 #else 0356 if( !findDevice( solidDevice.as<Solid::GenericInterface>()->propertyExists("block.netbsd.raw_device") ? solidDevice.as<Solid::GenericInterface>()->property("block.netbsd.raw_device").toString() : blockDevice->device() ) ) 0357 #endif 0358 return addDevice( new K3b::Device::Device( solidDevice ) ); 0359 else 0360 qDebug() << "(K3b::Device::DeviceManager) dev " << blockDevice->device() << " already found"; 0361 } 0362 return 0; 0363 } 0364 0365 0366 K3b::Device::Device* K3b::Device::DeviceManager::addDevice( K3b::Device::Device* device ) 0367 { 0368 const QString devicename = device->blockDeviceName(); 0369 0370 if( !device->init() ) { 0371 qDebug() << "Could not initialize device " << devicename; 0372 delete device; 0373 return 0; 0374 } 0375 0376 if( device ) { 0377 d->allDevices.append( device ); 0378 0379 // not every drive is able to read CDs 0380 // there are some 1st generation DVD writer that cannot 0381 if( device->type() & K3b::Device::DEVICE_CD_ROM ) 0382 d->cdReader.append( device ); 0383 if( device->readsDvd() ) 0384 d->dvdReader.append( device ); 0385 if( device->writesCd() ) 0386 d->cdWriter.append( device ); 0387 if( device->writesDvd() ) 0388 d->dvdWriter.append( device ); 0389 if( device->readCapabilities() & MEDIA_BD_ALL ) 0390 d->bdReader.append( device ); 0391 if( device->writeCapabilities() & MEDIA_BD_ALL ) 0392 d->bdWriter.append( device ); 0393 0394 if( device->writesCd() ) { 0395 // default to max write speed 0396 qDebug() << "(K3b::Device::DeviceManager) setting current write speed of device " 0397 << device->blockDeviceName() 0398 << " to " << device->maxWriteSpeed(); 0399 device->setCurrentWriteSpeed( device->maxWriteSpeed() ); 0400 } 0401 0402 emit changed( this ); 0403 emit changed(); 0404 } 0405 0406 return device; 0407 } 0408 0409 0410 void K3b::Device::DeviceManager::removeDevice( const Solid::Device& dev ) 0411 { 0412 if( const Solid::Block* blockDevice = dev.as<Solid::Block>() ) { 0413 if( Device* device = findDevice( blockDevice->device() ) ) { 0414 d->cdReader.removeAll( device ); 0415 d->dvdReader.removeAll( device ); 0416 d->bdReader.removeAll( device ); 0417 d->cdWriter.removeAll( device ); 0418 d->dvdWriter.removeAll( device ); 0419 d->bdWriter.removeAll( device ); 0420 d->allDevices.removeAll( device ); 0421 0422 emit changed( this ); 0423 emit changed(); 0424 0425 delete device; 0426 } 0427 } 0428 } 0429 0430 0431 void K3b::Device::DeviceManager::slotSolidDeviceAdded( const QString& udi ) 0432 { 0433 qDebug() << udi; 0434 checkDevice( Solid::Device( udi ) ); 0435 } 0436 0437 0438 void K3b::Device::DeviceManager::slotSolidDeviceRemoved( const QString& udi ) 0439 { 0440 qDebug() << udi; 0441 Solid::Device solidDev( udi ); 0442 if ( solidDev.isDeviceInterface( Solid::DeviceInterface::OpticalDrive ) ) { 0443 if ( solidDev.is<Solid::OpticalDrive>() ) { 0444 removeDevice( solidDev ); 0445 } 0446 } 0447 } 0448 0449 #include "moc_k3bdevicemanager.cpp"