@@ -1,4 +1,5 @@
// -*- Mode: c++ -*-
#include " config.h"
// Standard C headers
#include < cstdio>
Expand All
@@ -22,6 +23,10 @@
using namespace std ;
// Qt headers
#if CONFIG_QTDBUS
#include < QtDBus>
#include < QDBusConnection>
#endif
#include < QList>
#include < QTextStream>
#include < QDir>
Expand Down
Expand Up
@@ -66,6 +71,16 @@ extern "C" {
#endif
#define SUPER_OPT_DEV " dev="
#if CONFIG_QTDBUS
// DBus UDisk service - http://hal.freedesktop.org/docs/udisks/
#define UDISKS_SVC " org.freedesktop.UDisks"
#define UDISKS_PATH " /org/freedesktop/UDisks"
#define UDISKS_IFACE " org.freedesktop.UDisks"
#define UDISKS_DEVADD " DeviceAdded"
#define UDISKS_DEVRMV " DeviceRemoved"
#define UDISKS_DEVSIG " o" // OBJECT_PATH
#endif
const char * MediaMonitorUnix::kUDEV_FIFO = " /tmp/mythtv_media" ;
Expand All
@@ -91,7 +106,7 @@ static void statError(const QString &methodName, const QString devPath)
MediaMonitorUnix::MediaMonitorUnix (QObject* par,
unsigned long interval, bool allowEject)
: MediaMonitor(par, interval, allowEject)
: MediaMonitor(par, interval, allowEject), m_fifo(- 1 )
{
CheckFileSystemTable ();
CheckMountable ();
Expand All
@@ -100,6 +115,7 @@ MediaMonitorUnix::MediaMonitorUnix(QObject* par,
}
#if !CONFIG_QTDBUS
void MediaMonitorUnix::deleteLater (void )
{
if (m_fifo >= 0 )
Expand All
@@ -110,6 +126,7 @@ void MediaMonitorUnix::deleteLater(void)
}
MediaMonitor::deleteLater ();
}
#endif // !CONFIG_QTDBUS
// Loop through the file system table and add any supported devices.
Expand All
@@ -136,6 +153,21 @@ bool MediaMonitorUnix::CheckFileSystemTable(void)
return true ;
}
#if CONFIG_QTDBUS
// Get a device property by name
static QVariant DeviceProperty (const QDBusObjectPath& o, const char kszProperty[])
{
QVariant v;
QDBusInterface iface (UDISKS_SVC, o.path (), UDISKS_IFACE" .Device" ,
QDBusConnection::systemBus () );
if (iface.isValid ())
v = iface.property (kszProperty);
return v;
}
#endif
/* *
* \brief Search /sys/block for valid removable media devices.
*
Expand All
@@ -149,7 +181,63 @@ bool MediaMonitorUnix::CheckFileSystemTable(void)
*/
bool MediaMonitorUnix::CheckMountable (void )
{
#ifdef linux
#if CONFIG_QTDBUS
// Listen on DBus for UDisk add/remove device messages
QDBusConnection::systemBus ().connect (
UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVADD, UDISKS_DEVSIG,
this , SLOT (deviceAdded (QDBusObjectPath)) );
QDBusConnection::systemBus ().connect (
UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE, UDISKS_DEVRMV, UDISKS_DEVSIG,
this , SLOT (deviceRemoved (QDBusObjectPath)) );
// Connect to UDisks
QDBusInterface iface (UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
QDBusConnection::systemBus () );
if (!iface.isValid ())
{
VERBOSE (VB_IMPORTANT, LOC + " :CheckMountable: DBus interface error: " +
iface.lastError ().message () );
return false ;
}
// Enumerate devices
typedef QList<QDBusObjectPath> QDBusObjectPathList;
QDBusReply<QDBusObjectPathList> reply = iface.call (" EnumerateDevices" );
if (!reply.isValid ())
{
VERBOSE (VB_IMPORTANT, LOC + " :CheckMountable DBus EnumerateDevices error: " +
reply.error ().message () );
return false ;
}
// Parse the returned device array
const QDBusObjectPathList& list (reply.value ());
for (QDBusObjectPathList::const_iterator it = list.begin ();
it != list.end (); ++it)
{
if (!DeviceProperty (*it, " DeviceIsSystemInternal" ).toBool () &&
!DeviceProperty (*it, " DeviceIsPartitionTable" ).toBool () )
{
QString dev = DeviceProperty (*it, " DeviceFile" ).toString ();
// ignore floppies, too slow
if (dev.startsWith (" /dev/fd" ))
continue ;
MythMediaDevice* pDevice;
if (DeviceProperty (*it, " DeviceIsRemovable" ).toBool ())
pDevice = MythCDROM::get (this , dev.toAscii (), false , m_AllowEject);
else
pDevice = MythHDD::Get (this , dev.toAscii (), false , false );
if (pDevice && !AddDevice (pDevice))
pDevice->deleteLater ();
}
}
return true ;
#elif defined linux
// NB needs script in /etc/udev/rules.d
mkfifo (kUDEV_FIFO , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
m_fifo = open (kUDEV_FIFO , O_RDONLY | O_NONBLOCK);
Expand All
@@ -174,11 +262,12 @@ bool MediaMonitorUnix::CheckMountable(void)
sysfs.cdUp ();
}
return true ;
#else // if ! linux
#else // linux
return false ;
#endif // !linux
#endif
}
#if !CONFIG_QTDBUS
/* *
* \brief Is /sys/block/dev a removable device?
*/
Expand Down
Expand Up
@@ -227,7 +316,7 @@ QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs)
#ifdef linux
#if HAVE_LIBUDEV
// Use libudev to determine the name
ret = " " ;
ret. clear () ;
struct udev *udev = udev_new ();
if (udev != NULL )
{
Expand All
@@ -239,11 +328,27 @@ QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs)
if (name != NULL )
ret = tr (name);
else
{
// This can happen when udev sends an AddDevice for a block
// device with partitions. FindPartition locates a partition
// in sysfs but udev hasn't created the devnode for it yet.
// Udev will send another AddDevice for the partition later.
VERBOSE (VB_MEDIA+VB_EXTRA, msg + " devnode not (yet) known" );
}
udev_device_unref (device);
}
else
{
VERBOSE (VB_IMPORTANT, msg + " udev_device_new_from_syspath returned NULL" );
ret = " " ;
}
udev_unref (udev);
}
else
VERBOSE (VB_IMPORTANT, " MediaMonitorUnix::GetDeviceFile udev_new failed" );
#else // HAVE_LIBUDEV
// Use udevadm info to determine the name
QStringList args;
Expand Down
Expand Up
@@ -271,12 +376,9 @@ QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs)
}
QTextStream ostream (udevinfo->ReadAll ());
ret = ostream.readLine ();
if ( ret.startsWith (" device not found in database" ) )
{
delete udevinfo;
return ret;
}
QString udevLine = ostream.readLine ();
if (!udevLine.startsWith (" device not found in database" ) )
ret = udevLine;
delete udevinfo;
#endif // HAVE_LIBUDEV
Expand All
@@ -285,16 +387,43 @@ QString MediaMonitorUnix::GetDeviceFile(const QString &sysfs)
VERBOSE (VB_MEDIA, msg + " ->'" + ret + " '" );
return ret;
}
#endif // !CONFIG_QTDBUS
/*
* \brief Reads the list devices known to be CD or DVD devices.
* \return list of CD and DVD device names.
*/
// pure virtual
QStringList MediaMonitorUnix::GetCDROMBlockDevices (void )
{
QStringList l;
#ifdef linux
#if CONFIG_QTDBUS
QDBusInterface iface (UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
QDBusConnection::systemBus () );
if (iface.isValid ())
{
// Enumerate devices
typedef QList<QDBusObjectPath> QDBusObjectPathList;
QDBusReply<QDBusObjectPathList> reply = iface.call (" EnumerateDevices" );
if (reply.isValid ())
{
const QDBusObjectPathList& list (reply.value ());
for (QDBusObjectPathList::const_iterator it = list.begin ();
it != list.end (); ++it)
{
if (DeviceProperty (*it, " DeviceIsRemovable" ).toBool ())
{
QString dev = DeviceProperty (*it, " DeviceFile" ).toString ();
if (dev.startsWith (" /dev/" ))
dev.remove (0 ,5 );
l.push_back (dev);
}
}
}
}
#elif defined linux
QFile file (" /proc/sys/dev/cdrom/info" );
if (file.open (QIODevice::ReadOnly))
{
Expand All
@@ -315,21 +444,36 @@ QStringList MediaMonitorUnix::GetCDROMBlockDevices(void)
}
#endif // linux
VERBOSE (VB_MEDIA, LOC + " :GetCDROMBlockDevices()->'" + l.join (" , " ) + " '" );
VERBOSE (VB_MEDIA+VB_EXTRA,
LOC + " :GetCDROMBlockDevices()->'" + l.join (" , " ) + " '" );
return l;
}
static void LookupModel (MythMediaDevice* device)
{
QString desc;
QString devname = device->getRealDevice ();
#if CONFIG_QTDBUS
QDBusInterface iface (UDISKS_SVC, UDISKS_PATH, UDISKS_IFACE,
QDBusConnection::systemBus () );
if (iface.isValid ())
{
QDBusReply<QDBusObjectPath> reply = iface.call (
" FindDeviceByDeviceFile" , device->getRealDevice ());
if (reply.isValid ())
{
desc = DeviceProperty (reply, " DriveVendor" ).toString ();
if (!desc.isEmpty ())
desc += " " ;
desc += DeviceProperty (reply, " DriveModel" ).toString ();
}
}
#elif defined linux
// Given something like /dev/hda1, extract hda1
devname = devname .mid (5 ,5 );
QString devname = device-> getRealDevice () .mid (5 ,5 );
#ifdef linux
if (devname .startsWith (" hd" )) // IDE drive
{
QFile file (" /proc/ide/" + devname .left (3 ) + " /model" );
Expand Down
Expand Up
@@ -373,6 +517,8 @@ static void LookupModel(MythMediaDevice* device)
}
#endif
VERBOSE (VB_MEDIA+VB_EXTRA, QString (" LookupModel '%1' -> '%2'" ).
arg (device->getRealDevice ()).arg (desc) );
device->setDeviceModel (desc.toAscii ().constData ());
}
Expand Down
Expand Up
@@ -534,6 +680,49 @@ bool MediaMonitorUnix::AddDevice(struct fstab * mep)
return false ;
}
#if CONFIG_QTDBUS
/*
* DBus UDisk AddDevice handler
*/
void MediaMonitorUnix::deviceAdded ( QDBusObjectPath o)
{
VERBOSE (VB_MEDIA, LOC + " :deviceAdded " + o.path ());
// Don't add devices with partition tables, just the partitions
if (!DeviceProperty (o, " DeviceIsPartitionTable" ).toBool ())
{
QString dev = DeviceProperty (o, " DeviceFile" ).toString ();
MythMediaDevice* pDevice;
if (DeviceProperty (o, " DeviceIsRemovable" ).toBool ())
pDevice = MythCDROM::get (this , dev.toAscii (), false , m_AllowEject);
else
pDevice = MythHDD::Get (this , dev.toAscii (), false , false );
if (pDevice && !AddDevice (pDevice))
pDevice->deleteLater ();
}
}
/*
* DBus UDisk RemoveDevice handler
*/
void MediaMonitorUnix::deviceRemoved ( QDBusObjectPath o)
{
VERBOSE (VB_MEDIA, LOC + " deviceRemoved " + o.path ());
#if 0 // This fails because the DeviceFile has just been deleted
QString dev = DeviceProperty(o, "DeviceFile");
if (!dev.isEmpty())
RemoveDevice(dev);
#else
QString dev = QFileInfo (o.path ()).baseName ();
dev.prepend (" /dev/" );
RemoveDevice (dev);
#endif
}
#else // CONFIG_QTDBUS
/* *
* \brief Creates MythMedia instances for sysfs removable media devices.
*
Expand All
@@ -552,6 +741,8 @@ bool MediaMonitorUnix::AddDevice(struct fstab * mep)
*/
bool MediaMonitorUnix::FindPartitions (const QString &dev, bool checkPartitions)
{
VERBOSE (VB_MEDIA+VB_EXTRA, LOC + " :FindPartitions(" + dev + QString (" ,%1" ).
arg (checkPartitions ? " true" : " false" ) + " )" );
MythMediaDevice* pDevice = NULL ;
if (checkPartitions)
Expand All
@@ -570,7 +761,8 @@ bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions)
// skip some sysfs dirs that are _not_ sub-partitions
if (*pit == " device" || *pit == " holders" || *pit == " queue"
|| *pit == " slaves" || *pit == " subsystem" )
|| *pit == " slaves" || *pit == " subsystem"
|| *pit == " bdi" || *pit == " power" )
continue ;
found_partitions |= FindPartitions (
Expand All
@@ -586,7 +778,7 @@ bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions)
QString device_file = GetDeviceFile (dev);
if (device_file.isNull ())
if (device_file.isEmpty ())
return false ;
QStringList cdroms = GetCDROMBlockDevices ();
Expand Down
Expand Up
@@ -621,9 +813,9 @@ bool MediaMonitorUnix::FindPartitions(const QString &dev, bool checkPartitions)
void MediaMonitorUnix::CheckDeviceNotifications (void )
{
char buffer[256 ];
QString qBuffer = " " ;
QString qBuffer;
if (! m_fifo)
if (m_fifo == - 1 )
return ;
int size = read (m_fifo, buffer, 255 );
Expand All
@@ -642,13 +834,18 @@ void MediaMonitorUnix::CheckDeviceNotifications(void)
if ((*it).startsWith (" add" ))
{
QString dev = (*it).section (' ' , 1 , 1 );
VERBOSE (VB_MEDIA, " Udev add " + dev);
if (CheckRemovable (dev))
FindPartitions (dev, true );
}
else if ((*it).startsWith (" remove" ))
{
RemoveDevice ((*it).section (' ' , 2 , 2 ));
QString dev = (*it).section (' ' , 2 , 2 );
VERBOSE (VB_MEDIA, " Udev remove " + dev);
RemoveDevice (dev);
}
}
}
#endif // !CONFIG_QTDBUS