2 * Copyright (C) 2005-2009 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
21 #include "DeviceKitDisksProvider.h"
23 #include "settings/AdvancedSettings.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "utils/log.h"
26 #include "utils/URIUtils.h"
27 #include "PosixMountProvider.h"
29 void CDeviceKitDiskDeviceOldAPI::Update()
31 CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
33 m_isFileSystem = CStdString(properties["id-usage"].asString()) == "filesystem";
36 m_UDI = properties["id-uuid"].asString();
37 m_Label = properties["id-label"].asString();
38 m_FileSystem = properties["id-type"].asString();
46 m_isMounted = properties["device-is-mounted"].asBoolean();
47 if (m_isMounted && properties["device-mount-paths"].size() > 0)
48 m_MountPath = properties["device-mount-paths"][0].asString();
52 m_PartitionSizeGiB = properties["partition-size"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
53 m_isPartition = properties["device-is-partition"].asBoolean();
54 m_isSystemInternal = properties["device-is-system-internal"].asBoolean();
55 m_isOptical = properties["device-is-optical-disc"].asBoolean();
57 m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["partition-slave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "device-is-removable").asBoolean();
59 m_isRemovable = properties["device-is-removable"].asBoolean();
62 void CDeviceKitDiskDeviceNewAPI::Update()
64 CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
66 m_isFileSystem = CStdString(properties["IdUsage"].asString()) == "filesystem";
69 m_UDI = properties["IdUuid"].asString();
70 m_Label = properties["IdLabel"].asString();
71 m_FileSystem = properties["IdType"].asString();
80 m_isMounted = properties["DeviceIsMounted"].asBoolean();
81 if (m_isMounted && properties["DeviceMountPaths"].size() > 0)
82 m_MountPath = properties["DeviceMountPaths"][0].asString();
86 m_PartitionSizeGiB = properties["PartitionSize"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
87 m_isPartition = properties["DeviceIsPartition"].asBoolean();
88 m_isSystemInternal = properties["DeviceIsSystemInternal"].asBoolean();
89 m_isOptical = properties["DeviceIsOpticalDisc"].asBoolean();
91 m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["PartitionSlave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "DeviceIsRemovable").asBoolean();
93 m_isRemovable = properties["DeviceIsRemovable"].asBoolean();
96 CDeviceKitDiskDevice::CDeviceKitDiskDevice(const char *DeviceKitUDI)
98 m_DeviceKitUDI = DeviceKitUDI;
103 m_isMountedByUs = false;
104 m_isRemovable = false;
105 m_isPartition = false;
106 m_isFileSystem = false;
107 m_isSystemInternal = false;
109 m_PartitionSizeGiB = 0.0f;
112 bool CDeviceKitDiskDevice::Mount()
114 if (!m_isMounted && !m_isSystemInternal && m_isFileSystem)
116 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Mounting %s", m_DeviceKitUDI.c_str());
117 CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemMount");
118 message.AppendArgument("");
119 const char *array[] = {};
120 message.AppendArgument(array, 0);
122 DBusMessage *reply = message.SendSystem();
126 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &mountPoint, DBUS_TYPE_INVALID))
128 m_MountPath = mountPoint;
129 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Sucessfully mounted %s on %s", m_DeviceKitUDI.c_str(), mountPoint);
130 m_isMountedByUs = m_isMounted = true;
137 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to mount %s", toString().c_str());
142 bool CDeviceKitDiskDevice::UnMount()
144 if (m_isMounted && !m_isSystemInternal && m_isFileSystem)
146 CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemUnmount");
148 const char *array[1];
149 message.AppendArgument(array, 0);
151 DBusMessage *reply = message.SendSystem();
153 m_isMountedByUs = m_isMounted = false;
158 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to unmount %s", toString().c_str());
163 CMediaSource CDeviceKitDiskDevice::ToMediaShare()
166 source.strPath = m_MountPath;
168 source.strName.Format("%.1f GB %s", m_PartitionSizeGiB, g_localizeStrings.Get(155).c_str());
170 source.strName = m_Label;
172 source.m_iDriveType = CMediaSource::SOURCE_TYPE_DVD;
173 else if (m_isSystemInternal)
174 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
176 source.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
177 source.m_ignore = true;
181 bool CDeviceKitDiskDevice::IsApproved()
183 return (m_isFileSystem && m_isMounted && m_UDI.length() > 0 && (m_FileSystem.length() > 0 && !m_FileSystem.Equals("swap")) && !m_MountPath.Equals("/")) || m_isOptical;
186 #define BOOL2SZ(b) ((b) ? "true" : "false")
188 CStdString CDeviceKitDiskDevice::toString()
191 str.Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
192 "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
194 m_DeviceKitUDI.c_str(), BOOL2SZ(m_isFileSystem), m_FileSystem,
195 BOOL2SZ(m_isSystemInternal), BOOL2SZ(m_isMounted),
196 BOOL2SZ(m_isRemovable), BOOL2SZ(m_isPartition), BOOL2SZ(m_isOptical));
201 CDeviceKitDisksProvider::CDeviceKitDisksProvider()
203 dbus_error_init (&m_error);
204 // TODO: do not use dbus_connection_pop_message() that requires the use of a
205 // private connection
206 m_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_error);
207 dbus_connection_set_exit_on_disconnect(m_connection, false);
209 dbus_bus_add_match(m_connection, "type='signal',interface='org.freedesktop.DeviceKit.Disks'", &m_error);
210 dbus_connection_flush(m_connection);
211 if (dbus_error_is_set(&m_error))
213 CLog::Log(LOGERROR, "DeviceKit.Disks: Failed to attach to signal %s", m_error.message);
214 dbus_connection_close(m_connection);
215 dbus_connection_unref(m_connection);
220 CDeviceKitDisksProvider::~CDeviceKitDisksProvider()
222 DeviceMap::iterator itr;
224 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
225 delete m_AvailableDevices[itr->first];
227 m_AvailableDevices.clear();
231 dbus_connection_close(m_connection);
232 dbus_connection_unref(m_connection);
236 dbus_error_free (&m_error);
239 void CDeviceKitDisksProvider::Initialize()
241 CLog::Log(LOGDEBUG, "Selected DeviceKit.Disks as storage provider");
242 m_DaemonVersion = atoi(CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "DaemonVersion").asString().c_str());
243 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DaemonVersion %i", m_DaemonVersion);
245 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Querying available devices");
246 std::vector<CStdString> devices = EnumerateDisks();
247 for (unsigned int i = 0; i < devices.size(); i++)
248 DeviceAdded(devices[i].c_str(), NULL);
251 bool CDeviceKitDisksProvider::Eject(CStdString mountpath)
253 DeviceMap::iterator itr;
254 CStdString path(mountpath);
255 URIUtils::RemoveSlashAtEnd(path);
257 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
259 CDeviceKitDiskDevice *device = itr->second;
260 if (device->m_MountPath.Equals(path))
261 return device->UnMount();
267 std::vector<CStdString> CDeviceKitDisksProvider::GetDiskUsage()
269 CPosixMountProvider legacy;
270 return legacy.GetDiskUsage();
273 bool CDeviceKitDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
278 dbus_connection_read_write(m_connection, 0);
279 DBusMessage *msg = dbus_connection_pop_message(m_connection);
284 if (dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &object, DBUS_TYPE_INVALID))
287 if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceAdded"))
288 DeviceAdded(object, callback);
289 else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceRemoved"))
290 DeviceRemoved(object, callback);
291 else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceChanged"))
292 DeviceChanged(object, callback);
294 dbus_message_unref(msg);
300 bool CDeviceKitDisksProvider::HasDeviceKitDisks()
302 bool hasDeviceKitDisks = false;
303 CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
306 dbus_error_init (&error);
307 DBusConnection *con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
310 message.Send(con, &error);
312 if (!dbus_error_is_set(&error))
313 hasDeviceKitDisks = true;
315 CLog::Log(LOGDEBUG, "DeviceKit.Disks: %s - %s", error.name, error.message);
317 dbus_error_free (&error);
319 dbus_connection_unref(con);
321 return hasDeviceKitDisks;
324 void CDeviceKitDisksProvider::DeviceAdded(const char *object, IStorageEventsCallback *callback)
326 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded (%s)", object);
328 if (m_AvailableDevices[object])
330 CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceAdded on an indexed disk");
331 delete m_AvailableDevices[object];
334 CDeviceKitDiskDevice *device = NULL;
335 if (m_DaemonVersion >= 7)
336 device = new CDeviceKitDiskDeviceNewAPI(object);
338 device = new CDeviceKitDiskDeviceOldAPI(object);
339 m_AvailableDevices[object] = device;
341 if (g_advancedSettings.m_handleMounting)
344 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded - %s", device->toString().c_str());
345 if (device->m_isMounted && device->IsApproved())
347 CLog::Log(LOGNOTICE, "DeviceKit.Disks: Added %s", device->m_MountPath.c_str());
349 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
353 void CDeviceKitDisksProvider::DeviceRemoved(const char *object, IStorageEventsCallback *callback)
355 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceRemoved (%s)", object);
357 CDeviceKitDiskDevice *device = m_AvailableDevices[object];
360 if (device->m_isMounted && callback)
361 callback->OnStorageUnsafelyRemoved(device->m_Label);
363 delete m_AvailableDevices[object];
364 m_AvailableDevices.erase(object);
368 void CDeviceKitDisksProvider::DeviceChanged(const char *object, IStorageEventsCallback *callback)
370 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged (%s)", object);
372 CDeviceKitDiskDevice *device = m_AvailableDevices[object];
375 CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceChanged on an unindexed disk");
376 DeviceAdded(object, callback);
380 bool mounted = device->m_isMounted;
382 if (!mounted && device->m_isMounted && callback)
383 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
384 else if (mounted && !device->m_isMounted && callback)
385 callback->OnStorageSafelyRemoved(device->m_Label);
387 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged - %s", device->toString().c_str());
391 std::vector<CStdString> CDeviceKitDisksProvider::EnumerateDisks()
393 std::vector<CStdString> devices;
394 CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
395 DBusMessage *reply = message.SendSystem();
401 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &disks, &length, DBUS_TYPE_INVALID))
403 for (int i = 0; i < length; i++)
404 devices.push_back(disks[i]);
406 dbus_free_string_array(disks);
413 void CDeviceKitDisksProvider::GetDisks(VECSOURCES& devices, bool EnumerateRemovable)
415 DeviceMap::iterator itr;
417 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
419 CDeviceKitDiskDevice *device = itr->second;
420 if (device && device->IsApproved() && device->m_isSystemInternal != EnumerateRemovable)
421 devices.push_back(device->ToMediaShare());