diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-03 02:15:56 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-03 02:15:56 +0000 |
commit | 50b48aec6ddd451a6d1709c0942477b503457663 (patch) | |
tree | a9ece53ec06fd0a2819de7a2a6de997193566626 /libk3bdevice/k3bdevicemanager.cpp | |
download | k3b-50b48aec6ddd451a6d1709c0942477b503457663.tar.gz k3b-50b48aec6ddd451a6d1709c0942477b503457663.zip |
Added abandoned KDE3 version of K3B
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/k3b@1084400 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libk3bdevice/k3bdevicemanager.cpp')
-rw-r--r-- | libk3bdevice/k3bdevicemanager.cpp | 903 |
1 files changed, 903 insertions, 0 deletions
diff --git a/libk3bdevice/k3bdevicemanager.cpp b/libk3bdevice/k3bdevicemanager.cpp new file mode 100644 index 0000000..b7c04d0 --- /dev/null +++ b/libk3bdevice/k3bdevicemanager.cpp @@ -0,0 +1,903 @@ +/* + * + * $Id: k3bdevicemanager.cpp 676188 2007-06-16 08:55:00Z trueg $ + * Copyright (C) 2003-2007 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file "COPYING" for the exact licensing terms. + */ + +#include <config.h> + +#include "k3bdevicemanager.h" +#include "k3bdevice.h" +#include "k3bdeviceglobals.h" +#include "k3bscsicommand.h" +#include "k3bmmc.h" +#include "k3bdebug.h" + +#include <qstring.h> +#include <qstringlist.h> +#include <qptrlist.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> + +#include <kprocess.h> +#include <kapplication.h> +#include <kconfig.h> +#include <ktempfile.h> + +#include <iostream> +#include <limits.h> +#include <assert.h> + +#ifdef Q_OS_FREEBSD +#include <sys/param.h> +#include <sys/ucred.h> +#include <osreldate.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#ifdef HAVE_RESMGR +#include <resmgr.h> +#endif + +#ifdef Q_OS_LINUX + +/* Fix definitions for 2.5 kernels */ +#include <linux/version.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) +typedef unsigned char u8; +#endif + +#undef __STRICT_ANSI__ +#include <asm/types.h> +#define __STRICT_ANSI__ + +#include <scsi/scsi.h> +#include <linux/major.h> + + +#ifndef SCSI_DISK_MAJOR +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ + ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) +#endif + +#ifndef SCSI_BLK_MAJOR +#define SCSI_BLK_MAJOR(M) \ + (SCSI_DISK_MAJOR(M) \ + || (M) == SCSI_CDROM_MAJOR) +#endif + +#ifndef SCSI_GENERIC_MAJOR +#define SCSI_GENERIC_MAJOR 21 +#endif + +#endif // Q_OS_LINUX + + +#ifdef Q_OS_FREEBSD +#include <cam/cam.h> +#include <cam/scsi/scsi_pass.h> +#include <camlib.h> +#endif + +#ifdef Q_OS_NETBSD +#include <sys/scsiio.h> +#endif + + + +class K3bDevice::DeviceManager::Private +{ +public: + QPtrList<K3bDevice::Device> allDevices; + QPtrList<K3bDevice::Device> cdReader; + QPtrList<K3bDevice::Device> cdWriter; + QPtrList<K3bDevice::Device> dvdReader; + QPtrList<K3bDevice::Device> dvdWriter; + QPtrList<K3bDevice::Device> bdReader; + QPtrList<K3bDevice::Device> bdWriter; + + bool checkWritingModes; +}; + + + +K3bDevice::DeviceManager::DeviceManager( QObject* parent, const char* name ) + : QObject( parent, name ) +{ + d = new Private; +} + + +K3bDevice::DeviceManager::~DeviceManager() +{ + d->allDevices.setAutoDelete( true ); + delete d; +} + + +void K3bDevice::DeviceManager::setCheckWritingModes( bool b ) +{ + d->checkWritingModes = b; +} + + +K3bDevice::Device* K3bDevice::DeviceManager::deviceByName( const QString& name ) +{ + return findDevice( name ); +} + + +K3bDevice::Device* K3bDevice::DeviceManager::findDevice( int bus, int id, int lun ) +{ + QPtrListIterator<K3bDevice::Device> it( d->allDevices ); + while( it.current() ) + { + if( it.current()->scsiBus() == bus && + it.current()->scsiId() == id && + it.current()->scsiLun() == lun ) + return it.current(); + + ++it; + } + + return 0; +} + + +K3bDevice::Device* K3bDevice::DeviceManager::findDevice( const QString& devicename ) +{ + if( devicename.isEmpty() ) { + k3bDebug() << "(K3bDevice::DeviceManager) request for empty device!" << endl; + return 0; + } + QPtrListIterator<K3bDevice::Device> it( d->allDevices ); + while( it.current() ) { + if( it.current()->deviceNodes().contains(devicename) ) + return it.current(); + + ++it; + } + + return 0; +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::cdWriter() const +{ + return d->cdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::cdReader() const +{ + return d->cdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::dvdWriter() const +{ + return d->dvdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::dvdReader() const +{ + return d->dvdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::blueRayReader() const +{ + return d->bdReader; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::blueRayWriters() const +{ + return d->bdWriter; +} + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::burningDevices() const +{ + return cdWriter(); +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::readingDevices() const +{ + return cdReader(); +} + + +const QPtrList<K3bDevice::Device>& K3bDevice::DeviceManager::allDevices() const +{ + return d->allDevices; +} + + +int K3bDevice::DeviceManager::scanBus() +{ + unsigned int numDevs = d->allDevices.count(); + +#ifdef Q_OS_LINUX + LinuxDeviceScan(); +#endif +#ifdef Q_OS_FREEBSD + BSDDeviceScan(); +#endif +#ifdef Q_OS_NETBSD + NetBSDDeviceScan(); +#endif + + return d->allDevices.count() - numDevs; +} + + +void K3bDevice::DeviceManager::LinuxDeviceScan() +{ +#ifdef HAVE_RESMGR + // + // Resmgr device scan + // + char** resmgrDevices = rsm_list_devices( 0 ); + if( resmgrDevices ) { + for( int i = 0; resmgrDevices[i]; ++i ) { + addDevice( resmgrDevices[i] ); + free( resmgrDevices[i] ); + } + + free( resmgrDevices ); + } +#endif + + QFile info("/proc/sys/dev/cdrom/info"); + QString line,devstring; + if( info.open(IO_ReadOnly) ) { + info.readLine(line,80); // CD-ROM information, Id: cdrom.c 3.12 2000/10/18 + info.readLine(line,80); // + + QRegExp re("[\t\n:]+"); + while( info.readLine( line, 80 ) > 0 ) { + if( line.contains("drive name") > 0 ) { + int i = 1; + QString dev; + while( !(dev = line.section(re, i, i)).isEmpty() ) { + if( addDevice( QString("/dev/%1").arg(dev) ) ) { + devstring += dev + "|"; + } + // according to the LINUX ALLOCATED DEVICES document (http://www.lanana.org/docs/device-list/), + // the official device names for SCSI-CDROM's (block major 11) are /dev/sr*, the + // prefix /dev/scd instead of /dev/sr has been used as well, and might make more sense. + // Since there should be one and only one device node (and maybe several symbolic links) for + // each physical device the next line should be better + // else if ( dev.startsWith("sr") ) + if ( dev.startsWith("sr") ) { + if( addDevice(QString("/dev/%1").arg(dev.replace(QRegExp("r"),"cd"))) ) + devstring += dev + "|"; + } + ++i; + } + } + break; + } + info.close(); + } + else { + kdError() << "(K3bDevice::DeviceManager) could not open /proc/sys/dev/cdrom/info" << endl; + } + + // + // Scan the generic devices if we have scsi devices + // + k3bDebug() << "(K3bDevice::DeviceManager) SCANNING FOR GENERIC DEVICES." << endl; + for( int i = 0; i < 16; i++ ) { + QString sgDev = resolveSymLink( QString("/dev/sg%1").arg(i) ); + int bus = -1, id = -1, lun = -1; + if( determineBusIdLun( sgDev, bus, id, lun ) ) { + if( Device* dev = findDevice( bus, id, lun ) ) { + dev->m_genericDevice = sgDev; + } + } + } + // FIXME: also scan /dev/scsi/hostX.... for devfs without symlinks +} + + +void K3bDevice::DeviceManager::NetBSDDeviceScan() +{ + // Generate entries for /dev/cd* devices + // Note: As there are only 10 possible /dev/(r)cd devices, + // only these will be found. + + int i; + + // Whole disk mask (According to cd(4), the AMD64, i386 and BeBox ports use + // 'd' as whole-disk partition, the rest uses 'c'.) + +#if defined(__i386__) || defined (__amd64__) || defined (__bebox__) + static const char slicename = 'd'; +#else + static const char slicename = 'c'; +#endif + + char devicename[11]; // /dev/rcdXd + trailing zero + + for (i = 0; i < 10; i++ ) // cd(4) claims there are max. 10 CD devices. + { + snprintf(devicename,11,"/dev/rcd%d%c",i, slicename); + addDevice(QString(devicename)); + } +} + + +void K3bDevice::DeviceManager::BSDDeviceScan() +{ + // Unfortunately uses lots of FBSD-specific data structures +#ifndef Q_OS_FREEBSD + // bool bsdspecificcode = false; + // assert(bsdspecificcode); +#endif + +#ifdef Q_OS_FREEBSD + union ccb ccb; + int fd; + int need_close = 0; + int skip_device = 0; + int bus, target, lun; + QString dev1, dev2; + + if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) + { + k3bDebug() << "couldn't open %s " << XPT_DEVICE << endl; + return; + } + + memset(&ccb, 0, sizeof(ccb)); + + ccb.ccb_h.func_code = XPT_DEV_MATCH; + char buffer[100*sizeof(struct dev_match_result)]; + ccb.cdm.match_buf_len = 100*sizeof(struct dev_match_result); + ccb.cdm.matches = (struct dev_match_result *)buffer; + ccb.cdm.num_matches = 0; + ccb.cdm.num_patterns = 0; + ccb.cdm.pattern_buf_len = 0; + do { + if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { + k3bDebug() << "(BSDDeviceScan) error sending CAMIOCOMMAND ioctl: " << errno << endl; + break; + } + + if ((ccb.ccb_h.status != CAM_REQ_CMP) + || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { + k3bDebug() << "(BSDDeviceScan) got CAM error " << ccb.ccb_h.status << ", CDM error %d" << ccb.cdm.status << endl; + break; + } + k3bDebug() << "(BSDDeviceScan) number of matches " << (int)ccb.cdm.num_matches << endl; + for (int i = 0; i < (int)ccb.cdm.num_matches; i++) { + switch (ccb.cdm.matches[i].type) { + case DEV_MATCH_DEVICE: { + struct device_match_result *dev_result = &ccb.cdm.matches[i].result.device_result; + + if (dev_result->flags & DEV_RESULT_UNCONFIGURED) + { + skip_device = 1; + break; + } + else + skip_device = 0; + if (need_close) + { + QString pass = dev1; + QString dev = "/dev/" + dev2; + if (dev2.startsWith("pass")) + { + pass = dev2; + dev = "/dev/" + dev1; + } +#if __FreeBSD_version < 500100 + dev += "c"; +#endif + if (!dev1.isEmpty() && !dev2.isEmpty() && dev.startsWith("/dev/cd")) + { + Device* device = new Device(dev.latin1()); + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + device->m_passDevice = "/dev/" + pass; + k3bDebug() << "(BSDDeviceScan) add device " << dev << ":" << bus << ":" << target << ":" << lun << endl; + addDevice(device); + } + need_close = 0; + dev1=""; + dev2=""; + } + bus = dev_result->path_id; + target = dev_result->target_id; + lun = dev_result->target_lun; + + need_close = 1; + + break; + } + case DEV_MATCH_PERIPH: { + struct periph_match_result *periph_result = &ccb.cdm.matches[i].result.periph_result; + + if (skip_device != 0) + break; + + if (need_close > 1) + dev1 = periph_result->periph_name + QString::number(periph_result->unit_number); + else + dev2 = periph_result->periph_name + QString::number(periph_result->unit_number); + + need_close++; + break; + } + case DEV_MATCH_BUS : { + // bool cannotmatchbus = false; + // assert(cannotmatchbus); + break; + } + } + } + + } while ((ccb.ccb_h.status == CAM_REQ_CMP) + && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); + + if (need_close) + { + QString pass = dev1; + QString dev = "/dev/" + dev2; + if (dev2.startsWith("pass")) + { + pass = dev2; + dev = "/dev/" + dev1; + } +#if __FreeBSD_version < 500100 + dev += "c"; +#endif + if (!dev1.isEmpty() && !dev2.isEmpty() && dev.startsWith("/dev/cd")) + { + Device* device = new Device(dev.latin1()); + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + device->m_passDevice = "/dev/" + pass; + k3bDebug() << "(BSDDeviceScan) add device " << dev << ":" << bus << ":" << target << ":" << lun << endl; + addDevice(device); + } + } + close(fd); +#endif +} + + +void K3bDevice::DeviceManager::printDevices() +{ + k3bDebug() << "Devices:" << endl + << "------------------------------" << endl; + QPtrListIterator<Device> it( allDevices() ); + for( ; *it; ++it ) { + Device* dev = *it; + k3bDebug() << "Blockdevice: " << dev->blockDeviceName() << endl + << "Generic device: " << dev->genericDevice() << endl + << "Vendor: " << dev->vendor() << endl + << "Description: " << dev->description() << endl + << "Version: " << dev->version() << endl + << "Write speed: " << dev->maxWriteSpeed() << endl + << "Profiles: " << mediaTypeString( dev->supportedProfiles() ) << endl + << "Read Cap: " << mediaTypeString( dev->readCapabilities() ) << endl + << "Write Cap: " << mediaTypeString( dev->writeCapabilities() ) << endl + << "Writing modes: " << writingModeString( dev->writingModes() ) << endl + << "Reader aliases: " << dev->deviceNodes().join(", ") << endl + << "------------------------------" << endl; + } +} + + +void K3bDevice::DeviceManager::clear() +{ + // clear current devices + d->cdReader.clear(); + d->cdWriter.clear(); + d->dvdReader.clear(); + d->dvdWriter.clear(); + d->bdReader.clear(); + d->bdWriter.clear(); + + // to make sure no one crashes lets keep the devices around until the changed + // signals return + QPtrList<K3bDevice::Device> tmp = d->allDevices; + tmp.setAutoDelete( true ); + + d->allDevices.clear(); + + emit changed( this ); + emit changed(); +} + + +bool K3bDevice::DeviceManager::readConfig( KConfig* c ) +{ + // + // New configuration format since K3b 0.11.94 + // for details see saveConfig() + // + + if( !c->hasGroup( "Devices" ) ) + return false; + + c->setGroup( "Devices" ); + + QStringList deviceSearchPath = c->readListEntry( "device_search_path" ); + for( QStringList::const_iterator it = deviceSearchPath.constBegin(); + it != deviceSearchPath.constEnd(); ++it ) + addDevice( *it ); + + // + // Iterate over all devices and check if we have a config entry + // + for( QPtrListIterator<K3bDevice::Device> it( d->allDevices ); *it; ++it ) { + K3bDevice::Device* dev = *it; + + QString configEntryName = dev->vendor() + " " + dev->description(); + QStringList list = c->readListEntry( configEntryName ); + if( !list.isEmpty() ) { + k3bDebug() << "(K3bDevice::DeviceManager) found config entry for devicetype: " << configEntryName << endl; + + dev->setMaxReadSpeed( list[0].toInt() ); + if( list.count() > 1 ) + dev->setMaxWriteSpeed( list[1].toInt() ); + if( list.count() > 2 ) + dev->setCdrdaoDriver( list[2] ); + if( list.count() > 3 ) + dev->setCdTextCapability( list[3] == "yes" ); + } + } + + return true; +} + + +bool K3bDevice::DeviceManager::saveConfig( KConfig* c ) +{ + // + // New configuration format since K3b 0.11.94 + // + // We save a device search path which contains all device nodes + // where devices could be found including the old search path. + // This way also for example a manually added USB device will be + // found between sessions. + // Then we do not save the device settings (writing speed, cdrdao driver) + // for every single device but for every device type. + // This also makes sure device settings are kept between sessions + // + + c->setGroup( "Devices" ); + QStringList deviceSearchPath = c->readListEntry( "device_search_path" ); + // remove duplicate entries (caused by buggy old implementations) + QStringList saveDeviceSearchPath; + for( QStringList::const_iterator it = deviceSearchPath.constBegin(); it != deviceSearchPath.constEnd(); ++it ) + if( !saveDeviceSearchPath.contains( *it ) ) + saveDeviceSearchPath.append( *it ); + + for( QPtrListIterator<K3bDevice::Device> it( d->allDevices ); *it; ++it ) { + K3bDevice::Device* dev = *it; + + // update device search path + if( !saveDeviceSearchPath.contains( dev->blockDeviceName() ) ) + saveDeviceSearchPath.append( dev->blockDeviceName() ); + + // save the device type settings + QString configEntryName = dev->vendor() + " " + dev->description(); + QStringList list; + list << QString::number(dev->maxReadSpeed()) + << QString::number(dev->maxWriteSpeed()) + << dev->cdrdaoDriver(); + + if( dev->cdrdaoDriver() != "auto" ) + list << ( dev->cdTextCapable() == 1 ? "yes" : "no" ); + else + list << "auto"; + + c->writeEntry( configEntryName, list ); + } + + c->writeEntry( "device_search_path", saveDeviceSearchPath ); + + c->sync(); + + return true; +} + + +bool K3bDevice::DeviceManager::testForCdrom( const QString& devicename ) +{ +#ifdef Q_OS_FREEBSD + Q_UNUSED(devicename); + return true; +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) + bool ret = false; + int cdromfd = K3bDevice::openDevice( devicename.ascii() ); + if (cdromfd < 0) { + k3bDebug() << "could not open device " << devicename << " (" << strerror(errno) << ")" << endl; + return ret; + } + + // stat the device + struct stat cdromStat; + if( ::fstat( cdromfd, &cdromStat ) ) + return false; + + if( !S_ISBLK( cdromStat.st_mode) ) { + k3bDebug() << devicename << " is no block device" << endl; + } + else { + k3bDebug() << devicename << " is block device (" << (int)(cdromStat.st_rdev & 0xFF) << ")" << endl; +#if defined(Q_OS_NETBSD) + } + { +#endif + // inquiry + // use a 36 bytes buffer since not all devices return the full inquiry struct + unsigned char buf[36]; + struct inquiry* inq = (struct inquiry*)buf; + ::memset( buf, 0, sizeof(buf) ); + + ScsiCommand cmd( cdromfd ); + cmd[0] = MMC_INQUIRY; + cmd[4] = sizeof(buf); + cmd[5] = 0; + + if( cmd.transport( TR_DIR_READ, buf, sizeof(buf) ) ) { + k3bDebug() << "(K3bDevice::Device) Unable to do inquiry. " << devicename << " is not a cdrom device" << endl; + } + else if( (inq->p_device_type&0x1f) != 0x5 ) { + k3bDebug() << devicename << " seems not to be a cdrom device: " << strerror(errno) << endl; + } + else { + ret = true; + k3bDebug() << devicename << " seems to be cdrom" << endl; + } + } + + ::close( cdromfd ); + return ret; +#endif +} + +K3bDevice::Device* K3bDevice::DeviceManager::addDevice( const QString& devicename ) +{ +#ifdef Q_OS_FREEBSD + return 0; +#endif + + K3bDevice::Device* device = 0; + + // resolve all symlinks + QString resolved = resolveSymLink( devicename ); + k3bDebug() << devicename << " resolved to " << resolved << endl; + + if ( K3bDevice::Device* oldDev = findDevice(resolved) ) { + k3bDebug() << "(K3bDevice::DeviceManager) dev " << resolved << " already found" << endl; + oldDev->addDeviceNode( devicename ); + return 0; + } + + if( !testForCdrom(resolved) ) { +#ifdef HAVE_RESMGR + // With resmgr we might only be able to open the symlink name. + if( testForCdrom(devicename) ) { + resolved = devicename; + } + else { + return 0; + } +#else + return 0; +#endif + } + + int bus = -1, target = -1, lun = -1; + bool scsi = determineBusIdLun( resolved, bus, target, lun ); + if(scsi) { + if ( K3bDevice::Device* oldDev = findDevice(bus, target, lun) ) { + k3bDebug() << "(K3bDevice::DeviceManager) dev " << resolved << " already found" << endl; + oldDev->addDeviceNode( devicename ); + return 0; + } + } + + device = new K3bDevice::Device(resolved); + if( scsi ) { + device->m_bus = bus; + device->m_target = target; + device->m_lun = lun; + } + + return addDevice(device); +} + + +K3bDevice::Device* K3bDevice::DeviceManager::addDevice( K3bDevice::Device* device ) +{ + const QString devicename = device->devicename(); + + if( !device->init() ) { + k3bDebug() << "Could not initialize device " << devicename << endl; + delete device; + return 0; + } + + if( device ) { + d->allDevices.append( device ); + + // not every drive is able to read CDs + // there are some 1st generation DVD writer that cannot + if( device->type() & K3bDevice::DEVICE_CD_ROM ) + d->cdReader.append( device ); + if( device->readsDvd() ) + d->dvdReader.append( device ); + if( device->writesCd() ) + d->cdWriter.append( device ); + if( device->writesDvd() ) + d->dvdWriter.append( device ); + if( device->readCapabilities() & MEDIA_BD_ALL ) + d->bdReader.append( device ); + if( device->writeCapabilities() & MEDIA_BD_ALL ) + d->bdWriter.append( device ); + + if( device->writesCd() ) { + // default to max write speed + k3bDebug() << "(K3bDevice::DeviceManager) setting current write speed of device " + << device->blockDeviceName() + << " to " << device->maxWriteSpeed() << endl; + device->setCurrentWriteSpeed( device->maxWriteSpeed() ); + } + + emit changed( this ); + emit changed(); + } + + return device; +} + + +void K3bDevice::DeviceManager::removeDevice( const QString& dev ) +{ + if( Device* device = findDevice( dev ) ) { + d->cdReader.removeRef( device ); + d->dvdReader.removeRef( device ); + d->bdReader.removeRef( device ); + d->cdWriter.removeRef( device ); + d->dvdWriter.removeRef( device ); + d->bdWriter.removeRef( device ); + d->allDevices.removeRef( device ); + + emit changed( this ); + emit changed(); + + delete device; + } +} + + +bool K3bDevice::DeviceManager::determineBusIdLun( const QString& dev, int& bus, int& id, int& lun ) +{ +#ifdef Q_OS_FREEBSD + Q_UNUSED(dev); + Q_UNUSED(bus); + Q_UNUSED(id); + Q_UNUSED(lun); + return false; + /* NOTREACHED */ +#endif + +#ifdef Q_OS_NETBSD + int cdromfd = K3bDevice::openDevice ( dev.ascii() ); + if (cdromfd < 0) { + int local_errno = errno; // For all we know, k3bDebug() destroys errno + k3bDebug() << "could not open device " << dev << " (" << strerror(local_errno) << ")" << endl; + return false; + } + + struct scsi_addr my_addr; + + if (::ioctl(cdromfd, SCIOCIDENTIFY, &my_addr)) + { + int local_errno = errno; // For all we know, k3bDebug() destroys errno + k3bDebug() << "ioctl(SCIOCIDENTIFY) failed on device " << dev << " (" << strerror(local_errno) << ")" << endl; + + ::close(cdromfd); + return false; + } + + if (my_addr.type == TYPE_ATAPI) + { + // XXX Re-map atapibus, so it doesn't conflict with "real" scsi + // busses + + bus = 15; + id = my_addr.addr.atapi.drive + 2 * my_addr.addr.atapi.atbus; + lun = 0; + } + else + { + bus = my_addr.addr.scsi.scbus; + id = my_addr.addr.scsi.target; + lun = my_addr.addr.scsi.lun; + } + + ::close(cdromfd); + + return true; +#endif + +#ifdef Q_OS_LINUX + int ret = false; + int cdromfd = K3bDevice::openDevice( dev.ascii() ); + if (cdromfd < 0) { + return false; + } + + struct stat cdromStat; + if ( ::fstat( cdromfd, &cdromStat ) ) + return false; + + if( SCSI_BLK_MAJOR( cdromStat.st_rdev>>8 ) || + SCSI_GENERIC_MAJOR == (cdromStat.st_rdev>>8) ) { + struct ScsiIdLun + { + int id; + int lun; + }; + ScsiIdLun idLun; + + // in kernel 2.2 SCSI_IOCTL_GET_IDLUN does not contain the bus id + if ( (::ioctl( cdromfd, SCSI_IOCTL_GET_IDLUN, &idLun ) < 0) || + (::ioctl( cdromfd, SCSI_IOCTL_GET_BUS_NUMBER, &bus ) < 0) ) { + k3bDebug() << "Need a filename that resolves to a SCSI device" << endl; + ret = false; + } + else { + id = idLun.id & 0xff; + lun = (idLun.id >> 8) & 0xff; + k3bDebug() << "bus: " << bus << ", id: " << id << ", lun: " << lun << endl; + ret = true; + } + } + + ::close(cdromfd); + return ret; +#endif +} + + +QString K3bDevice::DeviceManager::resolveSymLink( const QString& path ) +{ + char resolved[PATH_MAX]; + if( !realpath( QFile::encodeName(path), resolved ) ) + { + k3bDebug() << "Could not resolve " << path << endl; + return path; + } + + return QString::fromLatin1( resolved ); +} + + +#include "k3bdevicemanager.moc" |