--- src/core/device/k3bdevicemanager.cpp.orig Sun Nov 2 15:42:06 2003 +++ src/core/device/k3bdevicemanager.cpp Fri Nov 7 12:35:44 2003 @@ -33,7 +33,13 @@ #include #include +#ifndef __FreeBSD__ #include +#else +#include +#include +#include +#endif #include #include #include @@ -42,6 +48,11 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#include +#include +#else /* Fix definitions for 2.5 kernels */ #include @@ -80,6 +91,7 @@ (SCSI_DISK_MAJOR(M) \ || (M) == SCSI_CDROM_MAJOR) #endif /* #ifndef SCSI_BLK_MAJOR */ +#endif class K3bCdDevice::DeviceManager::Private { @@ -194,6 +206,22 @@ { m_foundDevices = 0; +#ifdef __FreeBSD__ +// What k3b does here is the following: it takes a list of device point, which are good candidates for cd drives +// and asks their properties. If they are indeed cd drives, they are added to a device list. This does not work +// on FreeBSD (no corresponding ioctls). Here cdrecord is asked for a list of scsi device, which work as cd +// drives. The device points of those devices are added to the device list. + bsd_scan_devices(false); + kdDebug() << "(K3bDeviceManager) analyze found device" << endl; + for ( QValueList::iterator it = m_devices.begin(); it != m_devices.end(); ++it ) + { + if( addDevice( (*it).m_name ) ) + { + kdDebug() << "(K3bDeviceManager) Device " << (*it).m_name << " added" << endl; + m_foundDevices++; + } + } +#else QFile info("/proc/sys/dev/cdrom/info"); QString line,devstring; info.open(IO_ReadOnly); @@ -284,6 +312,7 @@ // m_foundDevices++; // } +#endif scanFstab(); return m_foundDevices; @@ -426,10 +455,11 @@ void K3bCdDevice::DeviceManager::determineCapabilities(K3bDevice *dev) { +#ifndef __FreeBSD__ // we just need to do this for writers since we use it to determine the writing modes if( !dev->burner() ) return; - +#endif // we do not use the user configured cdrecord here since we want to make sure // to get all the capabilities of the system @@ -480,9 +510,17 @@ dev->m_burner = true; dev->m_writeModes = 0; QStringList lines = QStringList::split( "\n", m_processOutput ); +#ifdef __FreeBSD__ + bool done = false; +#endif for( QStringList::const_iterator it = lines.begin(); it != lines.end(); ++it ) { const QString& line = *it; +#ifdef __FreeBSD__ + kdDebug() << "(K3bDeviceManager): " << line << endl; + if (done) + continue; +#endif // no info in cdrecord <= 1.10 !!!!! if( line.startsWith( "Supported modes" ) ) @@ -504,7 +542,11 @@ dev->m_writeModes |= K3bDevice::RAW_R96R; if( modes.contains( "RAW/R96P" ) ) dev->m_writeModes |= K3bDevice::RAW_R96P; +#ifdef __FreeBSD__ + done = true; +#else break; +#endif } } } @@ -515,12 +557,110 @@ if( dev->m_writeModes == 0 ) dev->m_writeModes = K3bDevice::SAO|K3bDevice::TAO; } +#ifdef __FreeBSD__ +// For some unknown reason KDE stdout redirection fails on cdrecord -prcap (FreeBSD) :-( +// See http://www.FreeBSD.org/cgi/query-pr.cgi?pr=ports/51651 +// So it is written to a temp file here + KTempFile tmpfile; + tmpfile.setAutoDelete(true); + QString call = cdrecordBin->path + " " + QString("dev=%1").arg(dev->busTargetLun()) + " -prcap > " + tmpfile.name(); + kdDebug() << "(K3bDeviceManager) calling: " << call << endl; + int result = system(call.latin1()); + if (!result) + kdDebug() << "(K3bDeviceManager) call failed: " << result << endl; + QFile tmp (tmpfile.name()); + if ( tmp.open( IO_ReadOnly ) ) + { + QTextStream stream( &tmp ); + while ( !stream.eof() ) + { + QString line = stream.readLine(); + kdDebug() << "(K3bDeviceManager): " << line << endl; + if( line.startsWith(" ") ) + { + if( line.contains("write CD-R media") ) + { + bool b = !line.contains( "not" ); + dev->m_burner = b; + kdDebug() << "(K3bDeviceManager) is burner: " << b << endl; + if (b) + { + dev->addDeviceType(K3bDevice::CDR); + kdDebug() << "(K3bDeviceManager) device type: CDR" << endl; + } + } + + else if( line.contains("write CD-RW media") ) + { + bool b = !line.contains( "not" ); + dev->m_bWritesCdrw = b; + kdDebug() << "(K3bDeviceManager) writes cdr: " << b << endl; + if (b) + { + dev->addDeviceType(K3bDevice::CDRW); + kdDebug() << "(K3bDeviceManager) device type: CDRW" << endl; + } + } + + else if( line.contains("Buffer-Underrun-Free recording") || + line.contains("support BURN-Proof") ) + { + bool b = !line.contains( "not" ); + dev->setBurnproof(b); + kdDebug() << "(K3bDeviceManager) burn proof: " << b << endl; + } + + else if( line.contains( "Maximum read speed" ) ) //lukas: are there really two spaces? trueg: Yes, there are! ;) + dev->m_maxReadSpeed = K3b::round( line.mid( line.find(":")+1 ).toDouble() * 1000.0 / ( 2352.0 * 75.0 ) ); + + else if( line.contains( "Maximum write speed" ) ) +{ + dev->m_maxWriteSpeed = K3b::round( line.mid( line.find(":")+1 ).toDouble() * 1000.0 / ( 2352.0 * 75.0 ) ); +} + else if( line.contains( "Does read CD-R media" ) ) + { + dev->addDeviceType(K3bDevice::CDROM); + kdDebug() << "(K3bDeviceManager) device type: CDROM" << endl; + } + else if( line.contains( "Does write DVD-R media" ) ) + { + dev->addDeviceType(K3bDevice::DVDR); + kdDebug() << "(K3bDeviceManager) device type: DVDR" << endl; + } + else if( line.contains( "Does write DVD-RAM media" ) ) + { + dev->addDeviceType(K3bDevice::DVDRAM); + kdDebug() << "(K3bDeviceManager) device type: DVDRAM" << endl; + } + else if( line.contains( "Does read DVD-ROM media" ) ) + { + dev->addDeviceType(K3bDevice::DVD); + kdDebug() << "(K3bDeviceManager) device type: DVD" << endl; + } + else if( line.contains( "Buffer size" ) ) + dev->m_bufferSize = line.mid( line.find(":")+1 ).toInt(); + } + else if( line.startsWith("Vendor_info") ) + dev->m_vendor = line.mid( line.find(":")+3, 8 ).stripWhiteSpace(); + else if( line.startsWith("Identifikation") ) + dev->m_description = line.mid( line.find(":")+3, 16 ).stripWhiteSpace(); + else if( line.startsWith("Revision") ) + dev->m_version = line.mid( line.find(":")+3, 4 ).stripWhiteSpace(); + else + kdDebug() << "(K3bDeviceManager) unused cdrecord output: " << line << endl; + + } + tmp.close(); + } + dev->guessProfiles(); +#endif } bool K3bCdDevice::DeviceManager::testForCdrom(const QString& devicename) { bool ret = false; +#ifndef __FreeBSD__ int cdromfd = K3bCdDevice::openDevice( devicename.ascii() ); if (cdromfd < 0) { kdDebug() << "could not open device " << devicename << " (" << strerror(errno) << ")" << endl; @@ -549,11 +689,51 @@ } } ::close( cdromfd ); +#endif return ret; } K3bDevice* K3bCdDevice::DeviceManager::addDevice( const QString& devicename ) { +#ifdef __FreeBSD__ +// this piece of code extracts some device parameter, like scsi or ide device. The whole process +// fails on FreeBSD. Here the device name is simply looked up in a list of devices found by a +// call of cdrecord --scanbus. + K3bDevice* device = 0; + if (!m_lastRefresh.isValid()) + bsd_scan_devices(false); + bool found = false; + for ( QValueList::iterator it = m_devices.begin(); it != m_devices.end(); ++it ) + { + if( (*it).m_name == devicename ) + { + device = new K3bDevice((*it).m_name.latin1()); + device->m_bus = (*it).m_bus; + device->m_target = (*it).m_target; + device->m_lun = (*it).m_lun; + device->m_passDevice = (*it).m_passDevice; + device->m_vendor = (*it).m_vendor; + device->m_description = (*it).m_product; + device->m_version = (*it).m_revision; + found = true; + break; + } + } + if (!found) + { + // resolve all symlinks + QString resolved = resolveSymLink( devicename ); + kdDebug() << "(K3bDeviceManager) " << devicename << " resolved to " << resolved << endl; + int bus, target, lun; + if( K3bDevice* oldDev = findDevice( bus, target, lun ) ) + { + kdDebug() << "(K3bDeviceManager) dev already found" << endl; + oldDev->addDeviceNode( resolved ); + } + return 0; + } + +#else K3bDevice* device = 0; // resolve all symlinks @@ -586,6 +766,7 @@ device->m_lun = lun; } +#endif if( !device->init() ) { kdDebug() << "Could not initialize device " << devicename << endl; delete device; @@ -623,13 +804,14 @@ void K3bCdDevice::DeviceManager::scanFstab() { +#ifndef __FreeBSD__ FILE* fstabFile = setmntent( _PATH_FSTAB, "r" ); if( !fstabFile ) { kdDebug() << "(K3bDeviceManager) could not open " << _PATH_FSTAB << endl; return; } - +#endif // clear all mount-Infos for( QPtrListIterator it( d->allDevices ); it.current(); ++it ) @@ -639,12 +821,22 @@ } +#ifndef __FreeBSD__ struct mntent* mountInfo = 0; while( (mountInfo = ::getmntent( fstabFile )) ) +#else + struct fstab * mountInfo = 0; + while( (mountInfo = ::getfsent()) ) +#endif { // check if the entry corresponds to a device +#ifndef __FreeBSD__ QString md = QFile::decodeName( mountInfo->mnt_fsname ); QString type = QFile::decodeName( mountInfo->mnt_type ); +#else + QString md = QFile::decodeName( mountInfo->fs_spec ); + QString type = QFile::decodeName( mountInfo->fs_vfstype ); +#endif bool supermount = false; @@ -652,7 +844,11 @@ supermount = true; // parse the device +#ifndef __FreeBSD__ QStringList opts = QStringList::split( ",", QString::fromLocal8Bit(mountInfo->mnt_opts) ); +#else + QStringList opts = QStringList::split( ",", QString::fromLocal8Bit(mountInfo->fs_mntops) ); +#endif for( QStringList::const_iterator it = opts.begin(); it != opts.end(); ++it ) { if( (*it).startsWith("dev=") ) { md = (*it).mid( 4 ); @@ -668,9 +864,20 @@ if( K3bDevice* dev = findDevice( resolveSymLink(md) ) ) { +#ifndef __FreeBSD__ kdDebug() << "(K3bDeviceManager) found device for " << md << ": " << resolveSymLink(md) << endl; if( dev->mountDevice().isEmpty() ) { dev->setMountPoint( mountInfo->mnt_dir ); +#else + kdDebug() << "(K3bDeviceManager) found device for " << md << " (" << resolveSymLink(md) << "): " << mountInfo->fs_file << endl; +// Several mount points for one device might exist. If more than one are found, the one with +// user permission should have a higher priority. + struct stat filestat; + if( dev->mountDevice().isEmpty() || (mountInfo->fs_file && !stat(mountInfo->fs_file, &filestat) && filestat.st_uid == geteuid())) + { + kdDebug() << "(K3bDeviceManager) setting mount point for device " << md << ": " << mountInfo->fs_file << endl; + dev->setMountPoint( mountInfo->fs_file ); +#endif dev->setMountDevice( md ); dev->m_supermount = supermount; } @@ -679,6 +886,8 @@ { // compare bus, id, lun since the same device can for example be // determined as /dev/srX or /dev/scdX +#ifndef __FreeBSD__ +// On FreeBSD scsi parameters can not be extracted from a file handle int bus = -1, id = -1, lun = -1; if( determineBusIdLun( mountInfo->mnt_fsname, bus, id, lun ) ) { if( K3bDevice* dev = findDevice( bus, id, lun ) ) { @@ -689,12 +898,27 @@ } } } +#else +// Therefore they are looked up in the device list. + kdDebug() << "(K3bDeviceManager) device: " << mountInfo->fs_spec << endl; + if( K3bDevice* dev = findDevice( mountInfo->fs_spec ) ) { + kdDebug() << " found! " << endl; + if( dev->mountDevice().isEmpty() ) { + dev->setMountPoint( mountInfo->fs_file ); + dev->setMountDevice( md ); + } + } +#endif } } // while mountInfo +#ifndef __FreeBSD__ endmntent( fstabFile ); +#else + endfsent(); +#endif } @@ -707,6 +931,8 @@ bool K3bCdDevice::DeviceManager::determineBusIdLun( const QString& dev, int& bus, int& id, int& lun ) { int ret = false; +#ifndef __FreeBSD__ +// On FreeBSD scsi parameters can not be extracted from a file handle int cdromfd = K3bCdDevice::openDevice( dev.ascii() ); if (cdromfd < 0) { kdDebug() << "could not open device " << dev << " (" << strerror(errno) << ")" << endl; @@ -743,6 +969,7 @@ ::close(cdromfd); +#endif return ret; } @@ -750,6 +977,7 @@ QString K3bCdDevice::DeviceManager::resolveSymLink( const QString& path ) { char resolved[PATH_MAX]; + kdDebug() << "(K3bDeviceManager) resolveSymLink: \"" << path << "\"" << endl; if( !realpath( QFile::encodeName(path), resolved ) ) { kdDebug() << "Could not resolve " << path << endl; @@ -784,5 +1012,125 @@ else return QString("ATAPI:%1").arg(dev->blockDeviceName()); } + +#ifdef __FreeBSD__ +// Calls "camcontrol devlist" to get a list of all available cd devices. +// The sudo flag indicates, that "camcontrol devlist" should be +// called. This is tried, if bsd_scan_devices(false) fails. +// The result of the scan ist stored in m_devices. If within 3 +// seconds after the last call to bsd_scan_devices this function +// is called again, the last result is used (prevents to call +// camcontrol several times within a short time). +void K3bCdDevice::DeviceManager::bsd_scan_devices(bool sudo) +{ + QDateTime now = QDateTime::currentDateTime(); + if (m_lastRefresh.isValid() && m_lastRefresh.secsTo(now) < 3) + return; + m_lastRefresh = now; + m_devices.clear(); + kdDebug() << "(K3bDeviceManager) Scanning for devices: " << sudo << endl; + KTempFile tmpfile; + tmpfile.setAutoDelete(true); + + // create call + QString call = "/bin/sh -c \""; + if (sudo) + call += "sudo "; + call += "camcontrol devlist > " + tmpfile.name() + " 2>&1 \""; + kdDebug() << "(K3bDeviceManager) Reading device list : " << call << endl; + if (system(call.latin1())) + { + if (!sudo) + { + m_lastRefresh = m_lastRefresh.addDays(-1); + bsd_scan_devices(true); + } + return; + } + + // read tmp file line by line + QFile tmp (tmpfile.name()); + if ( tmp.open( IO_ReadOnly ) ) + { + QTextStream stream( &tmp ); + while ( !stream.eof() ) + { + QString str = stream.readLine(); + if (!str.startsWith("<")) + continue; + str.remove(0,1); + int i = str.find(">"); + if (i < 0) + continue; + QStringList details = QStringList::split(" ", str.left(i)); + i = str.find("at scbus", i); + if (i < 0) + continue; + str.remove(0, i+8); + i = str.find(" "); + if (i < 0) + continue; + bool ok; + int bus = str.left(i).toInt(&ok); + if (!ok) + continue; + i = str.find("target ", i); + if (i < 0) + continue; + str.remove(0, i+7); + i = str.find(" "); + if (i < 0) + continue; + int target = str.left(i).toInt(&ok); + if (!ok) + continue; + i = str.find("lun ", i); + if (i < 0) + continue; + str.remove(0, i+4); + i = str.find(" "); + if (i < 0) + continue; + int lun = str.left(i).toInt(&ok); + if (!ok) + continue; + i = str.find("(", i); + if (i < 0) + continue; + str.remove(0, i+1); + i = str.find(","); + if (i < 0) + continue; + QString name = str.left(i); + str.remove(0, i+1); + i = str.find(")"); + if (i < 0) + continue; + QString pass = name; + if (name.startsWith("pass")) + name = str.left(i); + else + pass = str.left(i); + QString vendor, product, revision; + if (details.count() > 0) + revision = details.last(); + details.pop_back(); + if (details.count() > 0) + product = details.last(); + details.pop_back(); + if (details.count() > 0) + vendor = details.join(" "); + kdDebug() << "(K3bDeviceManager) Found device " << name << ", pass = " << pass << ", bus = " << bus << ", target = " << target << ", lun = " << lun << endl; + kdDebug() << "(K3bDeviceManager) vendor: " << vendor << ", product: " << product << ", revision: " << revision << ", target = " << target << ", lun = " << lun << endl; +#if __FreeBSD_version >= 500100 + m_devices.push_back(BSDDevice("/dev/" + name, "/dev/" + pass, vendor, product, revision, bus, target, lun)); +#else + m_devices.push_back(BSDDevice("/dev/" + name + "c", "/dev/" + pass, vendor, product, revision, bus, target, lun)); +#endif + } + } +} +#endif + #include "k3bdevicemanager.moc"