Ticket #9519: 1056-mediamonitor-unix-dbus.diff

File 1056-mediamonitor-unix-dbus.diff, 15.7 KB (added by Lawrence Rust <lvr@…>, 9 years ago)
  • mythtv/libs/libmyth/libmyth.pro

    diff --git /mythtv/libs/libmyth/libmyth.pro mythtv/libs/libmyth/libmyth.pro
    index add2903..680aeae 100644
    using_pulse { 
    145145unix:!cygwin {
    146146    SOURCES += mediamonitor-unix.cpp
    147147    HEADERS += mediamonitor-unix.h
     148    using_qtdbus: CONFIG += qdbus
    148149}
    149150
    150151linux:DEFINES += linux
  • mythtv/libs/libmyth/mediamonitor-unix.cpp

    diff --git mythtv/libs/libmyth/mediamonitor-unix.cpp mythtv/libs/libmyth/mediamonitor-unix.cpp
    index 19e2226..cb14b61 100644
     
    11// -*- Mode: c++ -*-
     2#include "config.h"
    23
    34// Standard C headers
    45#include <cstdio>
     
    1819
    1920// C++ headers
    2021#include <iostream>
     22#include <memory>
    2123
    2224using namespace std;
    2325
    2426// Qt headers
     27#if CONFIG_QTDBUS
     28#include <QtDBus>
     29#include <QDBusConnection>
     30#endif
    2531#include <QList>
    2632#include <QTextStream>
    2733#include <QDir>
    extern "C" { 
    6672#endif
    6773#define SUPER_OPT_DEV "dev="
    6874
     75#if CONFIG_QTDBUS
     76// DBus UDisk service - http://hal.freedesktop.org/docs/udisks/
     77#define UDISKS_SVC      "org.freedesktop.UDisks"
     78#define UDISKS_PATH     "/org/freedesktop/UDisks"
     79#define UDISKS_IFACE    "org.freedesktop.UDisks"
     80#define UDISKS_DEVADD   "DeviceAdded"
     81#define UDISKS_DEVRMV   "DeviceRemoved"
     82#define UDISKS_DEVSIG   "o" // OBJECT_PATH
     83#endif
     84
    6985const char * MediaMonitorUnix::kUDEV_FIFO = "/tmp/mythtv_media";
    7086
    7187
    static void statError(const QString &methodName, const QString devPath) 
    91107
    92108MediaMonitorUnix::MediaMonitorUnix(QObject* par,
    93109                                   unsigned long interval, bool allowEject)
    94                 : MediaMonitor(par, interval, allowEject)
     110                : MediaMonitor(par, interval, allowEject), m_fifo(-1)
    95111{
    96112    CheckFileSystemTable();
    97113    CheckMountable();
    MediaMonitorUnix::MediaMonitorUnix(QObject* par, 
    100116}
    101117
    102118
     119#if !CONFIG_QTDBUS
    103120void MediaMonitorUnix::deleteLater(void)
    104121{
    105122    if (m_fifo >= 0)
    void MediaMonitorUnix::deleteLater(void) 
    110127    }
    111128    MediaMonitor::deleteLater();
    112129}
     130#endif // !CONFIG_QTDBUS
    113131
    114132
    115133// Loop through the file system table and add any supported devices.
    bool MediaMonitorUnix::CheckFileSystemTable(void) 
    136154    return true;
    137155}
    138156
     157#if CONFIG_QTDBUS
     158// Get a device property by name
     159static QVariant DeviceProperty(const QDBusObjectPath& o, const char kszProperty[])
     160{
     161    QVariant v;
     162
     163    QDBusInterface iface(UDISKS_SVC, o.path(), UDISKS_IFACE".Device",
     164        QDBusConnection::systemBus() );
     165    if (iface.isValid())
     166        v = iface.property(kszProperty);
     167
     168    return v;
     169}
     170#endif
     171
    139172/**
    140173 *  \brief Search /sys/block for valid removable media devices.
    141174 *
    bool MediaMonitorUnix::CheckFileSystemTable(void) 
    149182 */
    150183bool MediaMonitorUnix::CheckMountable(void)
    151184{
    152 #ifdef linux
     185#if CONFIG_QTDBUS
     186    // Listen on DBus for UDisk add/remove device messages
     187    QDBusConnection::systemBus().connect(
     188        UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVADD, UDISKS_DEVSIG,
     189        this, SLOT(deviceAdded(QDBusObjectPath)) );
     190    QDBusConnection::systemBus().connect(
     191        UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVRMV, UDISKS_DEVSIG,
     192        this, SLOT(deviceRemoved(QDBusObjectPath)) );
     193
     194    // Connect to UDisks
     195    QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
     196        QDBusConnection::systemBus() );
     197    if (!iface.isValid())
     198    {
     199        VERBOSE(VB_IMPORTANT, LOC + ":CheckMountable: DBus interface error: " +
     200            iface.lastError().message() );
     201        return false;
     202    }
     203
     204    // Enumerate devices
     205    typedef QList<QDBusObjectPath> QDBusObjectPathList;
     206    QDBusReply<QDBusObjectPathList> reply = iface.call("EnumerateDevices");
     207    if (!reply.isValid())
     208    {
     209        VERBOSE(VB_IMPORTANT, LOC + ":CheckMountable DBus EnumerateDevices error: " +
     210            reply.error().message() );
     211        return false;
     212    }
     213
     214    // Parse the returned device array
     215    const QDBusObjectPathList& list(reply.value());
     216    for (QDBusObjectPathList::const_iterator it = list.begin();
     217        it != list.end(); ++it)
     218    {
     219        if (!DeviceProperty(*it, "DeviceIsSystemInternal").toBool() &&
     220            !DeviceProperty(*it, "DeviceIsPartitionTable").toBool() )
     221        {
     222            QString dev = DeviceProperty(*it, "DeviceFile").toString();
     223
     224            // ignore floppies, too slow
     225            if (dev.startsWith("/dev/fd"))
     226                continue;
     227
     228            MythMediaDevice* pDevice;
     229            if (DeviceProperty(*it, "DeviceIsRemovable").toBool())
     230                pDevice = MythCDROM::get(this, dev.toAscii(), false, m_AllowEject);
     231            else
     232                pDevice = MythHDD::Get(this, dev.toAscii(), false, false);
     233
     234            if (pDevice && !AddDevice(pDevice))
     235                pDevice->deleteLater();
     236        }
     237    }
     238    return true;
     239
     240#elif defined linux
     241    // NB needs script in /etc/udev/rules.d
    153242    mkfifo(kUDEV_FIFO, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    154243    m_fifo = open(kUDEV_FIFO, O_RDONLY | O_NONBLOCK);
    155244
    bool MediaMonitorUnix::CheckMountable(void) 
    174263        sysfs.cdUp();
    175264    }
    176265    return true;
    177 #else // if !linux
     266#else // linux
    178267    return false;
    179 #endif // !linux
     268#endif
    180269}
    181270
     271#if !CONFIG_QTDBUS
    182272/**
    183273 * \brief  Is /sys/block/dev a removable device?
    184274 */
    QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs) 
    227317#ifdef linux
    228318  #if HAVE_LIBUDEV
    229319    // Use libudev to determine the name
    230     ret = "";
    231320    struct udev *udev = udev_new();
    232321    if (udev != NULL)
    233322    {
    QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs) 
    239328
    240329            if (name != NULL)
    241330                ret = tr(name);
     331            else
     332            {
     333                // This can happen when udev sends an AddDevice for a block
     334                // device with partitions.  FindPartition locates a partition
     335                // in sysfs but udev hasn't created the devnode for it yet.
     336                // Udev will send another AddDevice for the partition later.
     337                VERBOSE(VB_MEDIA+VB_EXTRA, msg + " devnode not (yet) known");
     338            }
    242339
    243340            udev_device_unref(device);
    244341        }
     342        else
     343        {
     344            VERBOSE(VB_IMPORTANT, msg + " udev_device_new_from_syspath returned NULL");
     345            ret = "";
     346        }
     347
    245348        udev_unref(udev);
    246349    }
     350    else
     351        VERBOSE(VB_IMPORTANT, "MediaMonitorUnix::GetDeviceFile udev_new failed");
    247352  #else   // HAVE_LIBUDEV
    248353    // Use udevadm info to determine the name
    249354    QStringList  args;
    QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs) 
    254359    if( VERBOSE_LEVEL_CHECK(VB_MEDIA|VB_EXTRA) )
    255360        flags |= kMSStdErr;
    256361
    257     MythSystem *udevinfo = new MythSystem("udevinfo", args, flags);
     362    // NB Debian renamed udevinfo to udevadm starting with sid
     363    std::auto_ptr<MythSystem> udevinfo(new MythSystem("udevadm", args, flags));
    258364    udevinfo->Run(4);
    259365    if( udevinfo->Wait() != GENERIC_EXIT_OK )
    260     {
    261         delete udevinfo;
    262366        return ret;
    263     }
    264367
    265368    if (VERBOSE_LEVEL_CHECK(VB_MEDIA|VB_EXTRA))
    266369    {
    QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs) 
    271374    }
    272375
    273376    QTextStream ostream(udevinfo->ReadAll());
    274     ret = ostream.readLine();
    275     if( ret.startsWith("device not found in database") )
    276     {
    277         delete udevinfo;
    278         return ret;
    279     }
     377    QString s = ostream.readLine();
     378    if (!s.startsWith("device not found in database") )
     379        ret = s;
    280380
    281     delete udevinfo;
    282381  #endif // HAVE_LIBUDEV
    283382#endif // linux
    284383
    285384    VERBOSE(VB_MEDIA, msg + "->'" + ret + "'");
    286385    return ret;
    287386}
     387#endif // !CONFIG_QTDBUS
    288388
    289389/*
    290390 *  \brief Reads the list devices known to be CD or DVD devices.
    291391 *  \return list of CD and DVD device names.
    292392 */
     393// pure virtual
    293394QStringList MediaMonitorUnix::GetCDROMBlockDevices(void)
    294395{
    295396    QStringList l;
    296397
    297 #ifdef linux
     398#if CONFIG_QTDBUS
     399    QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
     400        QDBusConnection::systemBus() );
     401    if (iface.isValid())
     402    {
     403        // Enumerate devices
     404        typedef QList<QDBusObjectPath> QDBusObjectPathList;
     405        QDBusReply<QDBusObjectPathList> reply = iface.call("EnumerateDevices");
     406        if (reply.isValid())
     407        {
     408            const QDBusObjectPathList& list(reply.value());
     409            for (QDBusObjectPathList::const_iterator it = list.begin();
     410                it != list.end(); ++it)
     411            {
     412                if (DeviceProperty(*it, "DeviceIsRemovable").toBool())
     413                {
     414                    QString dev = DeviceProperty(*it, "DeviceFile").toString();
     415                    if (dev.startsWith("/dev/"))
     416                        dev.remove(0,5);
     417                    l.push_back(dev);
     418                }
     419            }
     420        }
     421    }
     422
     423#elif defined linux
    298424    QFile file("/proc/sys/dev/cdrom/info");
    299425    if (file.open(QIODevice::ReadOnly))
    300426    {
    QStringList MediaMonitorUnix::GetCDROMBlockDevices(void) 
    315441    }
    316442#endif // linux
    317443
    318     VERBOSE(VB_MEDIA, LOC + ":GetCDROMBlockDevices()->'" + l.join(", ") + "'");
     444    VERBOSE(VB_MEDIA+VB_EXTRA,
     445        LOC + ":GetCDROMBlockDevices()->'" + l.join(", ") + "'");
    319446    return l;
    320447}
    321448
    322449static void LookupModel(MythMediaDevice* device)
    323450{
    324451    QString   desc;
    325     QString   devname = device->getRealDevice();
    326452
     453#if CONFIG_QTDBUS
     454    QDBusInterface iface(UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
     455        QDBusConnection::systemBus() );
     456    if (iface.isValid())
     457    {
     458        QDBusReply<QDBusObjectPath> reply = iface.call(
     459            "FindDeviceByDeviceFile", device->getRealDevice());
     460        if (reply.isValid())
     461        {
     462            desc = DeviceProperty(reply, "DriveVendor").toString();
     463            if (!desc.isEmpty())
     464                desc += " ";
     465            desc += DeviceProperty(reply, "DriveModel").toString();
     466        }
     467    }
     468
     469#elif defined linux
    327470
    328471    // Given something like /dev/hda1, extract hda1
    329     devname = devname.mid(5,5);
     472    QString devname = device->getRealDevice().mid(5,5);
    330473
    331 
    332 #ifdef linux
    333474    if (devname.startsWith("hd"))  // IDE drive
    334475    {
    335476        QFile  file("/proc/ide/" + devname.left(3) + "/model");
    static void LookupModel(MythMediaDevice* device) 
    373514    }
    374515#endif
    375516
     517    VERBOSE(VB_MEDIA+VB_EXTRA, QString("LookupModel '%1' -> '%2'").
     518        arg(device->getRealDevice()).arg(desc) );
    376519    device->setDeviceModel(desc.toAscii().constData());
    377520}
    378521
    bool MediaMonitorUnix::AddDevice(struct fstab * mep) 
    534677    return false;
    535678}
    536679
     680#if CONFIG_QTDBUS
     681/*
     682 * DBus UDisk AddDevice handler
     683 */
     684void MediaMonitorUnix::deviceAdded( QDBusObjectPath o)
     685{
     686    VERBOSE(VB_MEDIA, LOC + ":deviceAdded " + o.path());
     687
     688    // Don't add devices with partition tables, just the partitions
     689    if (!DeviceProperty(o, "DeviceIsPartitionTable").toBool())
     690    {
     691        QString dev = DeviceProperty(o, "DeviceFile").toString();
     692
     693        MythMediaDevice* pDevice;
     694        if (DeviceProperty(o, "DeviceIsRemovable").toBool())
     695            pDevice = MythCDROM::get(this, dev.toAscii(), false, m_AllowEject);
     696        else
     697            pDevice = MythHDD::Get(this, dev.toAscii(), false, false);
     698
     699        if (pDevice && !AddDevice(pDevice))
     700            pDevice->deleteLater();
     701    }
     702}
     703
     704/*
     705 * DBus UDisk RemoveDevice handler
     706 */
     707void MediaMonitorUnix::deviceRemoved( QDBusObjectPath o)
     708{
     709    VERBOSE(VB_MEDIA, LOC + "deviceRemoved " + o.path());
     710#if 0 // This fails because the DeviceFile has just been deleted
     711    QString dev = DeviceProperty(o, "DeviceFile");
     712    if (!dev.isEmpty())
     713        RemoveDevice(dev);
     714#else
     715    QString dev = QFileInfo(o.path()).baseName();
     716    dev.prepend("/dev/");
     717    RemoveDevice(dev);
     718#endif
     719}
     720
     721#else //CONFIG_QTDBUS
     722
    537723/**
    538724 *  \brief Creates MythMedia instances for sysfs removable media devices.
    539725 *
    bool MediaMonitorUnix::AddDevice(struct fstab * mep) 
    552738 */
    553739bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions)
    554740{
     741    VERBOSE(VB_MEDIA+VB_EXTRA, LOC + ":FindPartitions(" + dev + QString(",%1").
     742        arg(checkPartitions ? " true" : " false" ) + ")");
    555743    MythMediaDevice* pDevice = NULL;
    556744
    557745    if (checkPartitions)
    bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions) 
    570758
    571759            // skip some sysfs dirs that are _not_ sub-partitions
    572760            if (*pit == "device" || *pit == "holders" || *pit == "queue"
    573                                  || *pit == "slaves"  || *pit == "subsystem")
     761                                 || *pit == "slaves"  || *pit == "subsystem"
     762                                 || *pit == "bdi"     || *pit == "power")
    574763                continue;
    575764
    576765            found_partitions |= FindPartitions(
    bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions) 
    586775
    587776    QString device_file = GetDeviceFile(dev);
    588777
    589     if (device_file.isNull())
     778    if (device_file.isEmpty())
    590779        return false;
    591780
    592781    QStringList cdroms = GetCDROMBlockDevices();
    void MediaMonitorUnix::CheckDeviceNotifications(void) 
    623812    char buffer[256];
    624813    QString qBuffer = "";
    625814
    626     if (!m_fifo)
     815    if (-1 == m_fifo)
    627816        return;
    628817
     818    // NB This needs /etc/udev/rules.d/mythtv.rules:
     819    //  SUBSYSTEM=="block", RUN+="/etc/udev/scripts/mythtv_udev_monitor.sh"
     820    // And /etc/udev/scripts/mythtv_udev_monitor.sh:
     821    //  MYTH_FIFO=/tmp/mythtv_media
     822    //  if [ -p $MYTH_FIFO ] && /bin/ps -C mythfrontend > /dev/null ; then
     823    //      echo $ACTION /sys$DEVPATH $DEVNAME > $MYTH_FIFO
     824    //  fi
    629825    int size = read(m_fifo, buffer, 255);
    630826    while (size > 0)
    631827    {
    void MediaMonitorUnix::CheckDeviceNotifications(void) 
    642838        if ((*it).startsWith("add"))
    643839        {
    644840            QString dev = (*it).section(' ', 1, 1);
     841            VERBOSE(VB_MEDIA, "Udev add " + dev);
    645842
    646843            if (CheckRemovable(dev))
    647844                FindPartitions(dev, true);
    648845        }
    649846        else if ((*it).startsWith("remove"))
    650847        {
    651             RemoveDevice((*it).section(' ', 2, 2));
     848            QString dev = (*it).section(' ', 2, 2);
     849            VERBOSE(VB_MEDIA, "Udev remove " + dev);
     850            RemoveDevice(dev);
    652851        }
    653852    }
    654853}
     854#endif //!CONFIG_QTDBUS
     855
  • mythtv/libs/libmyth/mediamonitor-unix.h

    diff --git mythtv/libs/libmyth/mediamonitor-unix.h mythtv/libs/libmyth/mediamonitor-unix.h
    index df81532..2f63b8c 100644
     
    11#ifndef MYTH_MEDIA_MONITOR_UNIX_H
    22#define MYTH_MEDIA_MONITOR_UNIX_H
    33
     4#include "config.h"
     5
     6#include <QString>
     7#if CONFIG_QTDBUS
     8#include <QtDBus>
     9#endif
     10
     11#include "mythmediamonitor.h"
     12
    413class MediaMonitorUnix : public MediaMonitor
    514{
     15#if CONFIG_QTDBUS
     16    Q_OBJECT
     17  public slots:
     18    Q_NOREPLY void deviceAdded(QDBusObjectPath);
     19    Q_NOREPLY void deviceRemoved(QDBusObjectPath);
     20#endif
     21
    622  public:
    723    MediaMonitorUnix(QObject *par, unsigned long interval, bool allowEject);
     24#if !CONFIG_QTDBUS
    825    virtual void deleteLater(void);
     26#endif
    927
    1028  protected:
    1129    ~MediaMonitorUnix() {}
    1230
    13     void CheckDevices(void);
    14     void CheckDeviceNotifications(void);
     31#if !CONFIG_QTDBUS
     32    virtual void CheckDeviceNotifications(void);
     33#endif
    1534    bool CheckFileSystemTable(void);
    1635    bool CheckMountable(void);
     36#if !CONFIG_QTDBUS
    1737    bool CheckRemovable(const QString &dev);
    1838    bool FindPartitions(const QString &dev, bool checkPartitions);
     39#endif
    1940
    2041    virtual bool AddDevice(MythMediaDevice* pDevice);
    2142    bool AddDevice(struct fstab* mep);
    2243
     44#if !CONFIG_QTDBUS
    2345    QString GetDeviceFile(const QString &sysfs);
     46#endif
    2447
    25     QStringList GetCDROMBlockDevices(void);
     48    virtual QStringList GetCDROMBlockDevices(void);
    2649
    2750  protected:
    2851    int                          m_fifo;