|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00002 #include "config.h" 00003 00004 // Standard C headers 00005 #include <cstdio> 00006 00007 // POSIX headers 00008 #include <dirent.h> 00009 #include <unistd.h> 00010 #include <fcntl.h> 00011 #include <fstab.h> 00012 00013 // UNIX System headers 00014 #include <sys/file.h> 00015 #include <sys/types.h> 00016 #include <sys/stat.h> 00017 #include <sys/wait.h> 00018 #include <sys/param.h> 00019 00020 // C++ headers 00021 #include <iostream> 00022 00023 using namespace std; 00024 00025 // Qt headers 00026 #if CONFIG_QTDBUS 00027 #include <QtDBus> 00028 #include <QDBusConnection> 00029 #endif 00030 #include <QList> 00031 #include <QTextStream> 00032 #include <QDir> 00033 #include <QFile> 00034 00035 // MythTV headers 00036 #include "mythmediamonitor.h" 00037 #include "mediamonitor-unix.h" 00038 #include "mythdialogs.h" 00039 #include "mythconfig.h" 00040 #include "mythcdrom.h" 00041 #include "mythhdd.h" 00042 #include "mythlogging.h" 00043 #include "mythsystem.h" 00044 #include "exitcodes.h" 00045 00046 #if HAVE_LIBUDEV 00047 extern "C" { 00048 #include <libudev.h> 00049 } 00050 #endif 00051 00052 00053 #ifndef MNTTYPE_ISO9660 00054 #ifdef linux 00055 #define MNTTYPE_ISO9660 "iso9660" 00056 #elif defined(__FreeBSD__) || CONFIG_DARWIN || defined(__OpenBSD__) 00057 #define MNTTYPE_ISO9660 "cd9660" 00058 #endif 00059 #endif 00060 00061 #ifndef MNTTYPE_UDF 00062 #define MNTTYPE_UDF "udf" 00063 #endif 00064 00065 #ifndef MNTTYPE_AUTO 00066 #define MNTTYPE_AUTO "auto" 00067 #endif 00068 00069 #ifndef MNTTYPE_SUPERMOUNT 00070 #define MNTTYPE_SUPERMOUNT "supermount" 00071 #endif 00072 #define SUPER_OPT_DEV "dev=" 00073 00074 #if CONFIG_QTDBUS 00075 // DBus UDisk service - http://hal.freedesktop.org/docs/udisks/ 00076 #define UDISKS_SVC "org.freedesktop.UDisks" 00077 #define UDISKS_PATH "/org/freedesktop/UDisks" 00078 #define UDISKS_IFACE "org.freedesktop.UDisks" 00079 #define UDISKS_DEVADD "DeviceAdded" 00080 #define UDISKS_DEVRMV "DeviceRemoved" 00081 #define UDISKS_DEVSIG "o" // OBJECT_PATH 00082 #endif 00083 00084 const char * MediaMonitorUnix::kUDEV_FIFO = "/tmp/mythtv_media"; 00085 00086 00087 // Some helpers for debugging: 00088 00089 static const QString LOC = QString("MMUnix:"); 00090 00091 // TODO: are these used? 00092 static void fstabError(const QString &methodName) 00093 { 00094 LOG(VB_GENERAL, LOG_ALERT, 00095 LOC + methodName + " Error: failed to open " + _PATH_FSTAB + 00096 " for reading, " + ENO); 00097 } 00098 00099 static void statError(const QString &methodName, const QString devPath) 00100 { 00101 LOG(VB_GENERAL, LOG_ALERT, 00102 LOC + methodName + " Error: failed to stat " + devPath + 00103 ", " + ENO); 00104 } 00105 00107 // MediaMonitor 00108 00109 00110 MediaMonitorUnix::MediaMonitorUnix(QObject* par, 00111 unsigned long interval, bool allowEject) 00112 : MediaMonitor(par, interval, allowEject), m_fifo(-1) 00113 { 00114 CheckFileSystemTable(); 00115 CheckMountable(); 00116 00117 LOG(VB_MEDIA, LOG_INFO, "Initial device list...\n" + listDevices()); 00118 } 00119 00120 00121 #if !CONFIG_QTDBUS 00122 void MediaMonitorUnix::deleteLater(void) 00123 { 00124 if (m_fifo >= 0) 00125 { 00126 close(m_fifo); 00127 m_fifo = -1; 00128 unlink(kUDEV_FIFO); 00129 } 00130 MediaMonitor::deleteLater(); 00131 } 00132 #endif // !CONFIG_QTDBUS 00133 00134 00135 // Loop through the file system table and add any supported devices. 00136 bool MediaMonitorUnix::CheckFileSystemTable(void) 00137 { 00138 struct fstab * mep = NULL; 00139 00140 // Attempt to open the file system descriptor entry. 00141 if (!setfsent()) 00142 { 00143 fstabError(":CheckFileSystemTable()"); 00144 return false; 00145 } 00146 00147 // Add all the entries 00148 while ((mep = getfsent()) != NULL) 00149 AddDevice(mep); 00150 00151 endfsent(); 00152 00153 if (m_Devices.isEmpty()) 00154 return false; 00155 00156 return true; 00157 } 00158 00159 #if CONFIG_QTDBUS 00160 // Get a device property by name 00161 static QVariant DeviceProperty(const QDBusObjectPath& o, const char kszProperty[]) 00162 { 00163 QVariant v; 00164 00165 QDBusInterface iface(UDISKS_SVC, o.path(), UDISKS_IFACE".Device", 00166 QDBusConnection::systemBus() ); 00167 if (iface.isValid()) 00168 v = iface.property(kszProperty); 00169 00170 return v; 00171 } 00172 #endif 00173 00185 bool MediaMonitorUnix::CheckMountable(void) 00186 { 00187 #if CONFIG_QTDBUS 00188 for (int i = 0; i < 10; ++i, usleep(500000)) 00189 { 00190 // Connect to UDisks. This can sometimes fail if mythfrontend 00191 // is started during system init 00192 QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, 00193 QDBusConnection::systemBus() ); 00194 if (!iface.isValid()) 00195 { 00196 LOG(VB_GENERAL, LOG_ALERT, LOC + 00197 "CheckMountable: DBus interface error: " + 00198 iface.lastError().message() ); 00199 continue; 00200 } 00201 00202 // Enumerate devices 00203 typedef QList<QDBusObjectPath> QDBusObjectPathList; 00204 QDBusReply<QDBusObjectPathList> reply = iface.call("EnumerateDevices"); 00205 if (!reply.isValid()) 00206 { 00207 LOG(VB_GENERAL, LOG_ALERT, LOC + 00208 "CheckMountable DBus EnumerateDevices error: " + 00209 reply.error().message() ); 00210 continue; 00211 } 00212 00213 // Listen on DBus for UDisk add/remove device messages 00214 (void)QDBusConnection::systemBus().connect( 00215 UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVADD, UDISKS_DEVSIG, 00216 this, SLOT(deviceAdded(QDBusObjectPath)) ); 00217 (void)QDBusConnection::systemBus().connect( 00218 UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVRMV, UDISKS_DEVSIG, 00219 this, SLOT(deviceRemoved(QDBusObjectPath)) ); 00220 00221 // Parse the returned device array 00222 const QDBusObjectPathList& list(reply.value()); 00223 for (QDBusObjectPathList::const_iterator it = list.begin(); 00224 it != list.end(); ++it) 00225 { 00226 if (!DeviceProperty(*it, "DeviceIsSystemInternal").toBool() && 00227 !DeviceProperty(*it, "DeviceIsPartitionTable").toBool() ) 00228 { 00229 QString dev = DeviceProperty(*it, "DeviceFile").toString(); 00230 00231 // ignore floppies, too slow 00232 if (dev.startsWith("/dev/fd")) 00233 continue; 00234 00235 MythMediaDevice* pDevice; 00236 if (DeviceProperty(*it, "DeviceIsRemovable").toBool()) 00237 pDevice = MythCDROM::get(this, dev.toAscii(), false, m_AllowEject); 00238 else 00239 pDevice = MythHDD::Get(this, dev.toAscii(), false, false); 00240 00241 if (pDevice && !AddDevice(pDevice)) 00242 pDevice->deleteLater(); 00243 } 00244 } 00245 00246 // Success 00247 return true; 00248 } 00249 00250 // Timed out 00251 return false; 00252 00253 #elif defined linux 00254 // NB needs script in /etc/udev/rules.d 00255 mkfifo(kUDEV_FIFO, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 00256 m_fifo = open(kUDEV_FIFO, O_RDONLY | O_NONBLOCK); 00257 00258 QDir sysfs("/sys/block"); 00259 sysfs.setFilter(QDir::Dirs); 00260 00261 QStringList devices = sysfs.entryList(); 00262 00263 for (QStringList::iterator it = devices.begin(); it != devices.end(); ++it) 00264 { 00265 if (*it == "." || *it == "..") 00266 continue; 00267 00268 // ignore floppies, too slow 00269 if ((*it).startsWith("fd")) 00270 continue; 00271 00272 sysfs.cd(*it); 00273 QString path = sysfs.absolutePath(); 00274 if (CheckRemovable(path)) 00275 FindPartitions(path, true); 00276 sysfs.cdUp(); 00277 } 00278 return true; 00279 #else // linux 00280 return false; 00281 #endif 00282 } 00283 00284 #if !CONFIG_QTDBUS 00285 00288 bool MediaMonitorUnix::CheckRemovable(const QString &dev) 00289 { 00290 #ifdef linux 00291 QString removablePath = dev + "/removable"; 00292 QFile removable(removablePath); 00293 if (removable.exists() && removable.open(QIODevice::ReadOnly)) 00294 { 00295 char c = 0; 00296 QString msg = LOC + ":CheckRemovable(" + dev + ")/removable "; 00297 bool ok = removable.getChar(&c); 00298 removable.close(); 00299 00300 if (ok) 00301 { 00302 LOG(VB_MEDIA, LOG_DEBUG, msg + c); 00303 if (c == '1') 00304 return true; 00305 } 00306 else 00307 { 00308 LOG(VB_GENERAL, LOG_ALERT, msg + "failed"); 00309 } 00310 } 00311 return false; 00312 #else // if !linux 00313 return false; 00314 #endif // !linux 00315 } 00316 00322 QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs) 00323 { 00324 QString msg = LOC + ":GetDeviceFile(" + sysfs + ")"; 00325 QString ret = sysfs; 00326 00327 // In case of error, a working default? (device names usually match) 00328 ret.replace(QRegExp(".*/"), "/dev/"); 00329 00330 #ifdef linux 00331 #if HAVE_LIBUDEV 00332 // Use libudev to determine the name 00333 ret.clear(); 00334 struct udev *udev = udev_new(); 00335 if (udev != NULL) 00336 { 00337 struct udev_device *device = 00338 udev_device_new_from_syspath(udev, sysfs.toAscii().constData()); 00339 if (device != NULL) 00340 { 00341 const char *name = udev_device_get_devnode(device); 00342 00343 if (name != NULL) 00344 ret = tr(name); 00345 else 00346 { 00347 // This can happen when udev sends an AddDevice for a block 00348 // device with partitions. FindPartition locates a partition 00349 // in sysfs but udev hasn't created the devnode for it yet. 00350 // Udev will send another AddDevice for the partition later. 00351 LOG(VB_MEDIA, LOG_DEBUG, msg + " devnode not (yet) known"); 00352 } 00353 00354 udev_device_unref(device); 00355 } 00356 else 00357 { 00358 LOG(VB_GENERAL, LOG_ALERT, 00359 msg + " udev_device_new_from_syspath returned NULL"); 00360 ret = ""; 00361 } 00362 00363 udev_unref(udev); 00364 } 00365 else 00366 LOG(VB_GENERAL, LOG_ALERT, 00367 "MediaMonitorUnix::GetDeviceFile udev_new failed"); 00368 #else // HAVE_LIBUDEV 00369 // Use udevadm info to determine the name 00370 QStringList args; 00371 args << "info" << "-q" << "name" 00372 << "-rp" << sysfs; 00373 00374 uint flags = kMSStdOut | kMSBuffered; 00375 if (VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG)) 00376 flags |= kMSStdErr; 00377 00378 // TODO: change this to a MythSystem on the stack? 00379 MythSystem *udevinfo = new MythSystem("udevinfo", args, flags); 00380 udevinfo->Run(4); 00381 if( udevinfo->Wait() != GENERIC_EXIT_OK ) 00382 { 00383 delete udevinfo; 00384 return ret; 00385 } 00386 00387 if (VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG)) 00388 { 00389 QTextStream estream(udevinfo->ReadAllErr()); 00390 while( !estream.atEnd() ) 00391 LOG(VB_MEDIA, LOG_DEBUG, 00392 msg + " - udevadm info error...\n" + estream.readLine()); 00393 } 00394 00395 QTextStream ostream(udevinfo->ReadAll()); 00396 QString udevLine = ostream.readLine(); 00397 if (!udevLine.startsWith("device not found in database") ) 00398 ret = udevLine; 00399 00400 delete udevinfo; 00401 #endif // HAVE_LIBUDEV 00402 #endif // linux 00403 00404 LOG(VB_MEDIA, LOG_INFO, msg + "->'" + ret + "'"); 00405 return ret; 00406 } 00407 #endif // !CONFIG_QTDBUS 00408 00409 /* 00410 * \brief Reads the list devices known to be CD or DVD devices. 00411 * \return list of CD and DVD device names. 00412 */ 00413 // pure virtual 00414 QStringList MediaMonitorUnix::GetCDROMBlockDevices(void) 00415 { 00416 QStringList l; 00417 00418 #if CONFIG_QTDBUS 00419 QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, 00420 QDBusConnection::systemBus() ); 00421 if (iface.isValid()) 00422 { 00423 // Enumerate devices 00424 typedef QList<QDBusObjectPath> QDBusObjectPathList; 00425 QDBusReply<QDBusObjectPathList> reply = iface.call("EnumerateDevices"); 00426 if (reply.isValid()) 00427 { 00428 const QDBusObjectPathList& list(reply.value()); 00429 for (QDBusObjectPathList::const_iterator it = list.begin(); 00430 it != list.end(); ++it) 00431 { 00432 if (DeviceProperty(*it, "DeviceIsRemovable").toBool()) 00433 { 00434 QString dev = DeviceProperty(*it, "DeviceFile").toString(); 00435 if (dev.startsWith("/dev/")) 00436 dev.remove(0,5); 00437 l.push_back(dev); 00438 } 00439 } 00440 } 00441 } 00442 00443 #elif defined linux 00444 QFile file("/proc/sys/dev/cdrom/info"); 00445 if (file.open(QIODevice::ReadOnly)) 00446 { 00447 QString line; 00448 QTextStream stream(&file); 00449 do 00450 { 00451 line = stream.readLine(); 00452 if (line.startsWith("drive name:")) 00453 { 00454 l = line.split('\t', QString::SkipEmptyParts); 00455 l.pop_front(); // Remove 'drive name:' field 00456 break; // file should only contain one drive table? 00457 } 00458 } 00459 while (!stream.atEnd()); 00460 file.close(); 00461 } 00462 #endif // linux 00463 00464 LOG(VB_MEDIA, LOG_DEBUG, 00465 LOC + ":GetCDROMBlockDevices()->'" + l.join(", ") + "'"); 00466 return l; 00467 } 00468 00469 static void LookupModel(MythMediaDevice* device) 00470 { 00471 QString desc; 00472 00473 #if CONFIG_QTDBUS 00474 QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, 00475 QDBusConnection::systemBus() ); 00476 if (iface.isValid()) 00477 { 00478 QDBusReply<QDBusObjectPath> reply = iface.call( 00479 "FindDeviceByDeviceFile", device->getRealDevice()); 00480 if (reply.isValid()) 00481 { 00482 desc = DeviceProperty(reply, "DriveVendor").toString(); 00483 if (!desc.isEmpty()) 00484 desc += " "; 00485 desc += DeviceProperty(reply, "DriveModel").toString(); 00486 } 00487 } 00488 00489 #elif defined linux 00490 00491 // Given something like /dev/hda1, extract hda1 00492 QString devname = device->getRealDevice().mid(5,5); 00493 00494 if (devname.startsWith("hd")) // IDE drive 00495 { 00496 QFile file("/proc/ide/" + devname.left(3) + "/model"); 00497 if (file.open(QIODevice::ReadOnly)) 00498 { 00499 QTextStream stream(&file); 00500 00501 desc.append(stream.readLine()); 00502 file.close(); 00503 } 00504 } 00505 00506 if (devname.startsWith("scd")) // scd0 doesn't appear in /sys/block, 00507 devname.replace("scd", "sr"); // use sr0 instead 00508 00509 if (devname.startsWith("sd") // SATA/USB/FireWire 00510 || devname.startsWith("sr")) // SCSI CD-ROM? 00511 { 00512 QString path = devname.prepend("/sys/block/"); 00513 path.append("/device/"); 00514 00515 QFile file(path + "vendor"); 00516 if (file.open(QIODevice::ReadOnly)) 00517 { 00518 QTextStream stream(&file); 00519 00520 desc.append(stream.readLine()); 00521 desc.append(' '); 00522 file.close(); 00523 } 00524 00525 file.setFileName(path + "model"); 00526 if (file.open(QIODevice::ReadOnly)) 00527 { 00528 QTextStream stream(&file); 00529 00530 desc.append(stream.readLine()); 00531 desc.append(' '); 00532 file.close(); 00533 } 00534 } 00535 #endif 00536 00537 LOG(VB_MEDIA, LOG_DEBUG, QString("LookupModel '%1' -> '%2'") 00538 .arg(device->getRealDevice()).arg(desc) ); 00539 device->setDeviceModel(desc.toAscii().constData()); 00540 } 00541 00545 bool MediaMonitorUnix::AddDevice(MythMediaDevice* pDevice) 00546 { 00547 if ( ! pDevice ) 00548 { 00549 LOG(VB_GENERAL, LOG_ERR, "MediaMonitorUnix::AddDevice(null)"); 00550 return false; 00551 } 00552 00553 // If the user doesn't want this device to be monitored, stop now: 00554 if (shouldIgnore(pDevice)) 00555 return false; 00556 00557 QString path = pDevice->getDevicePath(); 00558 if (!path.length()) 00559 { 00560 LOG(VB_GENERAL, LOG_ALERT, 00561 "MediaMonitorUnix::AddDevice() - empty device path."); 00562 return false; 00563 } 00564 00565 dev_t new_rdev; 00566 struct stat sb; 00567 00568 if (stat(path.toLocal8Bit().constData(), &sb) < 0) 00569 { 00570 statError(":AddDevice()", path); 00571 return false; 00572 } 00573 new_rdev = sb.st_rdev; 00574 00575 // 00576 // Check if this is a duplicate of a device we have already added 00577 // 00578 QList<MythMediaDevice*>::const_iterator itr = m_Devices.begin(); 00579 for (; itr != m_Devices.end(); ++itr) 00580 { 00581 if (stat((*itr)->getDevicePath().toLocal8Bit().constData(), &sb) < 0) 00582 { 00583 statError(":AddDevice()", (*itr)->getDevicePath()); 00584 return false; 00585 } 00586 00587 if (sb.st_rdev == new_rdev) 00588 { 00589 LOG(VB_MEDIA, LOG_INFO, 00590 LOC + ":AddDevice() - not adding " + path + 00591 "\n " 00592 "because it appears to be a duplicate of " + 00593 (*itr)->getDevicePath()); 00594 return false; 00595 } 00596 } 00597 00598 LookupModel(pDevice); 00599 00600 QMutexLocker locker(&m_DevicesLock); 00601 00602 connect(pDevice, SIGNAL(statusChanged(MythMediaStatus, MythMediaDevice*)), 00603 this, SLOT(mediaStatusChanged(MythMediaStatus, MythMediaDevice*))); 00604 m_Devices.push_back( pDevice ); 00605 m_UseCount[pDevice] = 0; 00606 LOG(VB_MEDIA, LOG_INFO, LOC + ":AddDevice() - Added " + path); 00607 00608 return true; 00609 } 00610 00611 // Given a fstab entry to a media device determine what type of device it is 00612 bool MediaMonitorUnix::AddDevice(struct fstab * mep) 00613 { 00614 if (!mep) 00615 return false; 00616 00617 QString devicePath( mep->fs_spec ); 00618 #if 0 00619 LOG(VB_GENERAL, LOG_DEBUG, "AddDevice - " + devicePath); 00620 #endif 00621 00622 MythMediaDevice* pDevice = NULL; 00623 struct stat sbuf; 00624 00625 bool is_supermount = false; 00626 bool is_cdrom = false; 00627 00628 if (stat(mep->fs_spec, &sbuf) < 0) 00629 return false; 00630 00631 // Can it be mounted? 00632 if ( ! ( ((strstr(mep->fs_mntops, "owner") && 00633 (sbuf.st_mode & S_IRUSR)) || strstr(mep->fs_mntops, "user")) && 00634 (strstr(mep->fs_vfstype, MNTTYPE_ISO9660) || 00635 strstr(mep->fs_vfstype, MNTTYPE_UDF) || 00636 strstr(mep->fs_vfstype, MNTTYPE_AUTO)) ) ) 00637 { 00638 if (strstr(mep->fs_mntops, MNTTYPE_ISO9660) && 00639 strstr(mep->fs_vfstype, MNTTYPE_SUPERMOUNT)) 00640 { 00641 is_supermount = true; 00642 } 00643 else 00644 { 00645 return false; 00646 } 00647 } 00648 00649 if (strstr(mep->fs_mntops, MNTTYPE_ISO9660) || 00650 strstr(mep->fs_vfstype, MNTTYPE_ISO9660) || 00651 strstr(mep->fs_vfstype, MNTTYPE_UDF) || 00652 strstr(mep->fs_vfstype, MNTTYPE_AUTO)) 00653 { 00654 is_cdrom = true; 00655 #if 0 00656 LOG(VB_GENERAL, LOG_DEBUG, "Device is a CDROM"); 00657 #endif 00658 } 00659 00660 if (!is_supermount) 00661 { 00662 if (is_cdrom) 00663 pDevice = MythCDROM::get(this, mep->fs_spec, 00664 is_supermount, m_AllowEject); 00665 } 00666 else 00667 { 00668 char *dev = 0; 00669 int len = 0; 00670 dev = strstr(mep->fs_mntops, SUPER_OPT_DEV); 00671 if (dev == NULL) 00672 return false; 00673 00674 dev += sizeof(SUPER_OPT_DEV)-1; 00675 while (dev[len] != ',' && dev[len] != ' ' && dev[len] != 0) 00676 len++; 00677 00678 if (dev[len] != 0) 00679 { 00680 char devstr[256]; 00681 strncpy(devstr, dev, len); 00682 devstr[len] = 0; 00683 if (is_cdrom) 00684 pDevice = MythCDROM::get(this, devstr, 00685 is_supermount, m_AllowEject); 00686 } 00687 else 00688 return false; 00689 } 00690 00691 if (pDevice) 00692 { 00693 pDevice->setMountPath(mep->fs_file); 00694 if (pDevice->testMedia() == MEDIAERR_OK) 00695 { 00696 if (AddDevice(pDevice)) 00697 return true; 00698 } 00699 pDevice->deleteLater(); 00700 } 00701 00702 return false; 00703 } 00704 00705 #if CONFIG_QTDBUS 00706 /* 00707 * DBus UDisk AddDevice handler 00708 */ 00709 void MediaMonitorUnix::deviceAdded( QDBusObjectPath o) 00710 { 00711 LOG(VB_MEDIA, LOG_INFO, LOC + ":deviceAdded " + o.path()); 00712 00713 // Don't add devices with partition tables, just the partitions 00714 if (!DeviceProperty(o, "DeviceIsPartitionTable").toBool()) 00715 { 00716 QString dev = DeviceProperty(o, "DeviceFile").toString(); 00717 00718 MythMediaDevice* pDevice; 00719 if (DeviceProperty(o, "DeviceIsRemovable").toBool()) 00720 pDevice = MythCDROM::get(this, dev.toAscii(), false, m_AllowEject); 00721 else 00722 pDevice = MythHDD::Get(this, dev.toAscii(), false, false); 00723 00724 if (pDevice && !AddDevice(pDevice)) 00725 pDevice->deleteLater(); 00726 } 00727 } 00728 00729 /* 00730 * DBus UDisk RemoveDevice handler 00731 */ 00732 void MediaMonitorUnix::deviceRemoved( QDBusObjectPath o) 00733 { 00734 LOG(VB_MEDIA, LOG_INFO, LOC + "deviceRemoved " + o.path()); 00735 #if 0 // This fails because the DeviceFile has just been deleted 00736 QString dev = DeviceProperty(o, "DeviceFile"); 00737 if (!dev.isEmpty()) 00738 RemoveDevice(dev); 00739 #else 00740 QString dev = QFileInfo(o.path()).baseName(); 00741 dev.prepend("/dev/"); 00742 RemoveDevice(dev); 00743 #endif 00744 } 00745 00746 #else //CONFIG_QTDBUS 00747 00764 bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions) 00765 { 00766 LOG(VB_MEDIA, LOG_DEBUG, 00767 LOC + ":FindPartitions(" + dev + 00768 QString(",%1").arg(checkPartitions ? " true" : " false" ) + ")"); 00769 MythMediaDevice* pDevice = NULL; 00770 00771 if (checkPartitions) 00772 { 00773 // check for partitions 00774 QDir sysfs(dev); 00775 sysfs.setFilter(QDir::Dirs); 00776 00777 bool found_partitions = false; 00778 QStringList parts = sysfs.entryList(); 00779 for (QStringList::iterator pit = parts.begin(); 00780 pit != parts.end(); ++pit) 00781 { 00782 if (*pit == "." || *pit == "..") 00783 continue; 00784 00785 // skip some sysfs dirs that are _not_ sub-partitions 00786 if (*pit == "device" || *pit == "holders" || *pit == "queue" 00787 || *pit == "slaves" || *pit == "subsystem" 00788 || *pit == "bdi" || *pit == "power") 00789 continue; 00790 00791 found_partitions |= FindPartitions( 00792 sysfs.absoluteFilePath(*pit), false); 00793 } 00794 00795 // no partitions on block device, use main device 00796 if (!found_partitions) 00797 found_partitions |= FindPartitions(sysfs.absolutePath(), false); 00798 00799 return found_partitions; 00800 } 00801 00802 QString device_file = GetDeviceFile(dev); 00803 00804 if (device_file.isEmpty()) 00805 return false; 00806 00807 QStringList cdroms = GetCDROMBlockDevices(); 00808 00809 if (cdroms.contains(dev.section('/', -1))) 00810 { 00811 // found cdrom device 00812 pDevice = MythCDROM::get( 00813 this, device_file.toAscii().constData(), false, m_AllowEject); 00814 } 00815 else 00816 { 00817 // found block or partition device 00818 pDevice = MythHDD::Get( 00819 this, device_file.toAscii().constData(), false, false); 00820 } 00821 00822 if (AddDevice(pDevice)) 00823 return true; 00824 00825 if (pDevice) 00826 pDevice->deleteLater(); 00827 00828 return false; 00829 } 00830 00836 void MediaMonitorUnix::CheckDeviceNotifications(void) 00837 { 00838 char buffer[256]; 00839 QString qBuffer; 00840 00841 if (m_fifo == -1) 00842 return; 00843 00844 int size = read(m_fifo, buffer, 255); 00845 while (size > 0) 00846 { 00847 // append buffer to QString 00848 buffer[size] = '\0'; 00849 qBuffer.append(buffer); 00850 size = read(m_fifo, buffer, 255); 00851 } 00852 const QStringList list = qBuffer.split('\n', QString::SkipEmptyParts); 00853 00854 QStringList::const_iterator it = list.begin(); 00855 for (; it != list.end(); ++it) 00856 { 00857 if ((*it).startsWith("add")) 00858 { 00859 QString dev = (*it).section(' ', 1, 1); 00860 LOG(VB_MEDIA, LOG_INFO, "Udev add " + dev); 00861 00862 if (CheckRemovable(dev)) 00863 FindPartitions(dev, true); 00864 } 00865 else if ((*it).startsWith("remove")) 00866 { 00867 QString dev = (*it).section(' ', 2, 2); 00868 LOG(VB_MEDIA, LOG_INFO, "Udev remove " + dev); 00869 RemoveDevice(dev); 00870 } 00871 } 00872 } 00873 #endif //!CONFIG_QTDBUS 00874
1.7.6.1