xbmc: add patch to support udev mounts

Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
Stephan Raue 2013-08-22 14:29:07 +02:00
parent b9018e1c95
commit ea88d59d26

View File

@ -0,0 +1,367 @@
From 9295c3ffac97c64cebee88229ee6ac8376f150ae Mon Sep 17 00:00:00 2001
From: davilla <davilla@4pi.com>
Date: Fri, 20 Apr 2012 13:23:19 -0400
Subject: [PATCH] [aml] fixed, add UDevProvider to handle usb disk add/remove
storage handling
---
xbmc/storage/linux/LinuxStorageProvider.h | 5 +
xbmc/storage/linux/Makefile | 9 +-
xbmc/storage/linux/UDevProvider.cpp | 241 ++++++++++++++++++++++++++++++
xbmc/storage/linux/UDevProvider.h | 55 +++++++
4 files changed, 306 insertions(+), 4 deletions(-)
create mode 100644 xbmc/storage/linux/UDevProvider.cpp
create mode 100644 xbmc/storage/linux/UDevProvider.h
diff --git a/xbmc/storage/linux/LinuxStorageProvider.h b/xbmc/storage/linux/LinuxStorageProvider.h
index 1f14548..740b282 100644
--- a/xbmc/storage/linux/LinuxStorageProvider.h
+++ b/xbmc/storage/linux/LinuxStorageProvider.h
@@ -21,6 +21,7 @@
#include "storage/IStorageProvider.h"
#include "HALProvider.h"
#include "DeviceKitDisksProvider.h"
+#include "UDevProvider.h"
#include "UDisksProvider.h"
#include "PosixMountProvider.h"
@@ -41,6 +42,10 @@ class CLinuxStorageProvider : public IStorageProvider
if (m_instance == NULL)
m_instance = new CHALProvider();
#endif
+#ifdef HAVE_LIBUDEV
+ if (m_instance == NULL)
+ m_instance = new CUDevProvider();
+#endif
if (m_instance == NULL)
m_instance = new CPosixMountProvider();
diff --git a/xbmc/storage/linux/Makefile b/xbmc/storage/linux/Makefile
index 9be601d..325f84d 100644
--- a/xbmc/storage/linux/Makefile
+++ b/xbmc/storage/linux/Makefile
@@ -1,8 +1,9 @@
-SRCS=DeviceKitDisksProvider.cpp \
- HALProvider.cpp \
- UDisksProvider.cpp \
+SRCS = DeviceKitDisksProvider.cpp
+SRCS += UDisksProvider.cpp
+SRCS += HALProvider.cpp
+SRCS += UDevProvider.cpp
-LIB=storage_linux.a
+LIB = storage_linux.a
include ../../../Makefile.include
-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/storage/linux/UDevProvider.cpp b/xbmc/storage/linux/UDevProvider.cpp
new file mode 100644
index 0000000..21b6b50
--- /dev/null
+++ b/xbmc/storage/linux/UDevProvider.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "UDevProvider.h"
+
+#ifdef HAVE_LIBUDEV
+
+#include "linux/PosixMountProvider.h"
+#include "utils/log.h"
+#include "utils/URIUtils.h"
+
+extern "C" {
+#include <libudev.h>
+#include <poll.h>
+}
+
+static const char *get_mountpoint(const char *devnode)
+{
+ static char buf[4096];
+ const char *delim = " ";
+ const char *mountpoint = NULL;
+ FILE *fp = fopen("/proc/mounts", "r");
+
+ while (fgets(buf, sizeof (buf), fp))
+ {
+ const char *node = strtok(buf, delim);
+ if (strcmp(node, devnode) == 0)
+ {
+ mountpoint = strtok(NULL, delim);
+ break;
+ }
+ }
+
+ if (mountpoint != NULL)
+ {
+ // If mount point contain characters like space, it is converted to
+ // "\040". This situation should be handled.
+ char *c1, *c2;
+ for (c1 = c2 = (char*)mountpoint; *c2; ++c1)
+ {
+ if (*c2 == '\\')
+ {
+ *c1 = (((c2[1] - '0') << 6) | ((c2[2] - '0') << 3) | (c2[3] - '0'));
+ c2 += 4;
+ continue;
+ }
+ if (c1 != c2)
+ *c1 = *c2;
+ ++c2;
+ }
+ *c1 = *c2;
+ }
+
+ fclose(fp);
+ return mountpoint;
+}
+
+CUDevProvider::CUDevProvider()
+{
+ m_udev = NULL;
+ m_udevMon = NULL;
+}
+
+void CUDevProvider::Initialize()
+{
+ CLog::Log(LOGDEBUG, "Selected UDev as storage provider");
+
+ m_udev = udev_new();
+ if (!m_udev)
+ {
+ CLog::Log(LOGERROR, "%s - failed to allocate udev context", __FUNCTION__);
+ return;
+ }
+ /* set up a devices monitor that listen for any device change */
+ m_udevMon = udev_monitor_new_from_netlink(m_udev, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "block", "disk");
+ udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "block", "partition");
+ udev_monitor_enable_receiving(m_udevMon);
+
+ PumpDriveChangeEvents(NULL);
+}
+
+void CUDevProvider::Stop()
+{
+ udev_monitor_unref(m_udevMon);
+ udev_unref(m_udev);
+}
+
+void CUDevProvider::GetDisks(VECSOURCES& disks, bool removable)
+{
+ // enumerate existing block devices
+ struct udev_enumerate *u_enum = udev_enumerate_new(m_udev);
+ if (u_enum == NULL)
+ {
+ fprintf(stderr, "Error: udev_enumerate_new(udev)\n");
+ return;
+ }
+
+ udev_enumerate_add_match_subsystem(u_enum, "block");
+ udev_enumerate_add_match_property(u_enum, "DEVTYPE", "disk");
+ udev_enumerate_add_match_property(u_enum, "DEVTYPE", "partition");
+ udev_enumerate_scan_devices(u_enum);
+
+ struct udev_list_entry *u_list_ent;
+ struct udev_list_entry *u_first_list_ent;
+ u_first_list_ent = udev_enumerate_get_list_entry(u_enum);
+ udev_list_entry_foreach(u_list_ent, u_first_list_ent)
+ {
+ const char *name = udev_list_entry_get_name(u_list_ent);
+ struct udev *context = udev_enumerate_get_udev(u_enum);
+ struct udev_device *device = udev_device_new_from_syspath(context, name);
+ if (device == NULL)
+ continue;
+
+ // filter out devices that are not mounted
+ const char *mountpoint = get_mountpoint(udev_device_get_devnode(device));
+ if (!mountpoint)
+ {
+ udev_device_unref(device);
+ continue;
+ }
+
+ // filter out things mounted on /tmp
+ if (strstr(mountpoint, "/tmp"))
+ {
+ udev_device_unref(device);
+ continue;
+ }
+
+ // look for usb devices on the usb bus or mounted on /media/usbX (sdcards)
+ const char *bus = udev_device_get_property_value(device, "ID_BUS");
+ if (removable &&
+ ((bus && strstr(bus, "usb")) ||
+ (mountpoint && strstr(mountpoint, "usb"))))
+ {
+ const char *label = udev_device_get_property_value(device, "ID_FS_LABEL");
+ if (!label)
+ label = URIUtils::GetFileName(mountpoint);
+
+ CMediaSource share;
+ share.strName = label;
+ share.strPath = mountpoint;
+ share.m_ignore = true;
+ share.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
+ AddOrReplace(disks, share);
+ }
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(u_enum);
+}
+
+void CUDevProvider::GetLocalDrives(VECSOURCES &localDrives)
+{
+ GetDisks(localDrives, false);
+}
+
+void CUDevProvider::GetRemovableDrives(VECSOURCES &removableDrives)
+{
+ GetDisks(removableDrives, true);
+}
+
+bool CUDevProvider::Eject(CStdString mountpath)
+{
+ return false;
+}
+
+std::vector<CStdString> CUDevProvider::GetDiskUsage()
+{
+ CPosixMountProvider legacy;
+ return legacy.GetDiskUsage();
+}
+
+bool CUDevProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
+{
+ bool changed = false;
+
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(udev_monitor_get_fd(m_udevMon), &readfds);
+
+ // non-blocking, check the file descriptor for received data
+ struct timeval tv = {0};
+ int count = select(udev_monitor_get_fd(m_udevMon) + 1, &readfds, NULL, NULL, &tv);
+ if (count < 0)
+ return false;
+
+ if (FD_ISSET(udev_monitor_get_fd(m_udevMon), &readfds))
+ {
+ struct udev_device *dev = udev_monitor_receive_device(m_udevMon);
+ if (!dev)
+ return false;
+
+ const char *action = udev_device_get_action(dev);
+ const char *devtype = udev_device_get_devtype(dev);
+ if (action)
+ {
+ const char *label = udev_device_get_property_value(dev, "ID_FS_LABEL");
+ const char *mountpoint = get_mountpoint(udev_device_get_devnode(dev));
+ if (!label)
+ label = URIUtils::GetFileName(mountpoint);
+
+ if (!strcmp(action, "add") && !strcmp(devtype, "partition"))
+ {
+ CLog::Log(LOGNOTICE, "UDev: Added %s", mountpoint);
+ if (callback)
+ callback->OnStorageAdded(label, mountpoint);
+ changed = true;
+ }
+ if (!strcmp(action, "remove") && !strcmp(devtype, "partition"))
+ {
+ CLog::Log(LOGNOTICE, "UDev: Removed %s", mountpoint);
+ if (callback)
+ callback->OnStorageSafelyRemoved(label);
+ changed = true;
+ }
+ }
+ udev_device_unref(dev);
+ }
+
+ return changed;
+}
+
+#endif
diff --git a/xbmc/storage/linux/UDevProvider.h b/xbmc/storage/linux/UDevProvider.h
new file mode 100644
index 0000000..6b51e2a
--- /dev/null
+++ b/xbmc/storage/linux/UDevProvider.h
@@ -0,0 +1,55 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "storage/IStorageProvider.h"
+
+#ifdef HAVE_LIBUDEV
+
+struct udev;
+struct udev_monitor;
+
+class CUDevProvider : public IStorageProvider
+{
+public:
+ CUDevProvider();
+ virtual ~CUDevProvider() { }
+
+ virtual void Initialize();
+ virtual void Stop();
+
+ virtual void GetLocalDrives(VECSOURCES &localDrives);
+ virtual void GetRemovableDrives(VECSOURCES &removableDrives);
+
+ virtual bool Eject(CStdString mountpath);
+
+ virtual std::vector<CStdString> GetDiskUsage();
+
+ virtual bool PumpDriveChangeEvents(IStorageEventsCallback *callback);
+
+private:
+ void GetDisks(VECSOURCES& devices, bool removable);
+
+ struct udev *m_udev;
+ struct udev_monitor *m_udevMon;
+};
+
+#endif
--
1.8.1.6