MythTV  0.26-pre
mediamonitor-unix.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends