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"
28 void CDeviceKitDiskDeviceOldAPI::Update()
30 CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
32 m_isFileSystem = CStdString(properties["id-usage"].asString()) == "filesystem";
35 m_UDI = properties["id-uuid"].asString();
36 m_Label = properties["id-label"].asString();
37 m_FileSystem = properties["id-type"].asString();
45 m_isMounted = properties["device-is-mounted"].asBoolean();
46 if (m_isMounted && properties["device-mount-paths"].size() > 0)
47 m_MountPath = properties["device-mount-paths"][0].asString();
51 m_PartitionSizeGiB = properties["partition-size"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
52 m_isPartition = properties["device-is-partition"].asBoolean();
53 m_isSystemInternal = properties["device-is-system-internal"].asBoolean();
54 m_isOptical = properties["device-is-optical-disc"].asBoolean();
56 m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["partition-slave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "device-is-removable").asBoolean();
58 m_isRemovable = properties["device-is-removable"].asBoolean();
61 void CDeviceKitDiskDeviceNewAPI::Update()
63 CVariant properties = CDBusUtil::GetAll("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device");
65 m_isFileSystem = CStdString(properties["IdUsage"].asString()) == "filesystem";
68 m_UDI = properties["IdUuid"].asString();
69 m_Label = properties["IdLabel"].asString();
70 m_FileSystem = properties["IdType"].asString();
79 m_isMounted = properties["DeviceIsMounted"].asBoolean();
80 if (m_isMounted && properties["DeviceMountPaths"].size() > 0)
81 m_MountPath = properties["DeviceMountPaths"][0].asString();
85 m_PartitionSizeGiB = properties["PartitionSize"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
86 m_isPartition = properties["DeviceIsPartition"].asBoolean();
87 m_isSystemInternal = properties["DeviceIsSystemInternal"].asBoolean();
88 m_isOptical = properties["DeviceIsOpticalDisc"].asBoolean();
90 m_isRemovable = CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", properties["PartitionSlave"].asString().c_str(), "org.freedesktop.DeviceKit.Disks.Device", "DeviceIsRemovable").asBoolean();
92 m_isRemovable = properties["DeviceIsRemovable"].asBoolean();
95 CDeviceKitDiskDevice::CDeviceKitDiskDevice(const char *DeviceKitUDI)
97 m_DeviceKitUDI = DeviceKitUDI;
102 m_isMountedByUs = false;
103 m_isRemovable = false;
104 m_isPartition = false;
105 m_isFileSystem = false;
106 m_isSystemInternal = false;
108 m_PartitionSizeGiB = 0.0f;
111 bool CDeviceKitDiskDevice::Mount()
113 if (!m_isMounted && !m_isSystemInternal && m_isFileSystem)
115 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Mounting %s", m_DeviceKitUDI.c_str());
116 CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemMount");
117 message.AppendArgument("");
118 const char *array[] = {};
119 message.AppendArgument(array, 0);
121 DBusMessage *reply = message.SendSystem();
125 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &mountPoint, DBUS_TYPE_INVALID))
127 m_MountPath = mountPoint;
128 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Sucessfully mounted %s on %s", m_DeviceKitUDI.c_str(), mountPoint);
129 m_isMountedByUs = m_isMounted = true;
136 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to mount %s", toString().c_str());
141 bool CDeviceKitDiskDevice::UnMount()
143 if (m_isMounted && !m_isSystemInternal && m_isFileSystem)
145 CDBusMessage message("org.freedesktop.DeviceKit.Disks", m_DeviceKitUDI.c_str(), "org.freedesktop.DeviceKit.Disks.Device", "FilesystemUnmount");
147 const char *array[1];
148 message.AppendArgument(array, 0);
150 DBusMessage *reply = message.SendSystem();
152 m_isMountedByUs = m_isMounted = false;
157 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Is not able to unmount %s", toString().c_str());
162 CMediaSource CDeviceKitDiskDevice::ToMediaShare()
165 source.strPath = m_MountPath;
167 source.strName.Format("%.1f GB %s", m_PartitionSizeGiB, g_localizeStrings.Get(155).c_str());
169 source.strName = m_Label;
171 source.m_iDriveType = CMediaSource::SOURCE_TYPE_DVD;
172 else if (m_isSystemInternal)
173 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
175 source.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
176 source.m_ignore = true;
180 bool CDeviceKitDiskDevice::IsApproved()
182 return (m_isFileSystem && m_isMounted && m_UDI.length() > 0 && (m_FileSystem.length() > 0 && !m_FileSystem.Equals("swap")) && !m_MountPath.Equals("/")) || m_isOptical;
185 #define BOOL2SZ(b) ((b) ? "true" : "false")
187 CStdString CDeviceKitDiskDevice::toString()
190 str.Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
191 "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
193 m_DeviceKitUDI.c_str(), BOOL2SZ(m_isFileSystem), m_FileSystem,
194 BOOL2SZ(m_isSystemInternal), BOOL2SZ(m_isMounted),
195 BOOL2SZ(m_isRemovable), BOOL2SZ(m_isPartition), BOOL2SZ(m_isOptical));
200 CDeviceKitDisksProvider::CDeviceKitDisksProvider()
202 dbus_error_init (&m_error);
203 // TODO: do not use dbus_connection_pop_message() that requires the use of a
204 // private connection
205 m_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_error);
206 dbus_connection_set_exit_on_disconnect(m_connection, false);
208 dbus_bus_add_match(m_connection, "type='signal',interface='org.freedesktop.DeviceKit.Disks'", &m_error);
209 dbus_connection_flush(m_connection);
210 if (dbus_error_is_set(&m_error))
212 CLog::Log(LOGERROR, "DeviceKit.Disks: Failed to attach to signal %s", m_error.message);
213 dbus_connection_close(m_connection);
214 dbus_connection_unref(m_connection);
219 CDeviceKitDisksProvider::~CDeviceKitDisksProvider()
221 DeviceMap::iterator itr;
223 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
224 delete m_AvailableDevices[itr->first];
226 m_AvailableDevices.clear();
230 dbus_connection_close(m_connection);
231 dbus_connection_unref(m_connection);
235 dbus_error_free (&m_error);
238 void CDeviceKitDisksProvider::Initialize()
240 CLog::Log(LOGDEBUG, "Selected DeviceKit.Disks as storage provider");
241 m_DaemonVersion = atoi(CDBusUtil::GetVariant("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "DaemonVersion").asString().c_str());
242 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DaemonVersion %i", m_DaemonVersion);
244 CLog::Log(LOGDEBUG, "DeviceKit.Disks: Querying available devices");
245 std::vector<CStdString> devices = EnumerateDisks();
246 for (unsigned int i = 0; i < devices.size(); i++)
247 DeviceAdded(devices[i].c_str(), NULL);
250 bool CDeviceKitDisksProvider::Eject(CStdString mountpath)
252 DeviceMap::iterator itr;
253 CStdString path(mountpath);
254 URIUtils::RemoveSlashAtEnd(path);
256 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
258 CDeviceKitDiskDevice *device = itr->second;
259 if (device->m_MountPath.Equals(path))
260 return device->UnMount();
266 std::vector<CStdString> CDeviceKitDisksProvider::GetDiskUsage()
268 std::vector<CStdString> devices;
269 DeviceMap::iterator itr;
271 for(itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
273 CDeviceKitDiskDevice *device = itr->second;
274 if (device->m_isMounted)
277 str.Format("%s %.1f GiB", device->m_MountPath.c_str(), device->m_PartitionSizeGiB);
278 devices.push_back(str);
285 bool CDeviceKitDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
290 dbus_connection_read_write(m_connection, 0);
291 DBusMessage *msg = dbus_connection_pop_message(m_connection);
296 if (dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &object, DBUS_TYPE_INVALID))
299 if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceAdded"))
300 DeviceAdded(object, callback);
301 else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceRemoved"))
302 DeviceRemoved(object, callback);
303 else if (dbus_message_is_signal(msg, "org.freedesktop.DeviceKit.Disks", "DeviceChanged"))
304 DeviceChanged(object, callback);
306 dbus_message_unref(msg);
312 bool CDeviceKitDisksProvider::HasDeviceKitDisks()
314 bool hasDeviceKitDisks = false;
315 CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
318 dbus_error_init (&error);
319 DBusConnection *con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
322 message.Send(con, &error);
324 if (!dbus_error_is_set(&error))
325 hasDeviceKitDisks = true;
327 CLog::Log(LOGDEBUG, "DeviceKit.Disks: %s - %s", error.name, error.message);
329 dbus_error_free (&error);
331 dbus_connection_unref(con);
333 return hasDeviceKitDisks;
336 void CDeviceKitDisksProvider::DeviceAdded(const char *object, IStorageEventsCallback *callback)
338 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded (%s)", object);
340 if (m_AvailableDevices[object])
342 CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceAdded on an indexed disk");
343 delete m_AvailableDevices[object];
346 CDeviceKitDiskDevice *device = NULL;
347 if (m_DaemonVersion >= 7)
348 device = new CDeviceKitDiskDeviceNewAPI(object);
350 device = new CDeviceKitDiskDeviceOldAPI(object);
351 m_AvailableDevices[object] = device;
353 if (g_advancedSettings.m_handleMounting)
356 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceAdded - %s", device->toString().c_str());
357 if (device->m_isMounted && device->IsApproved())
359 CLog::Log(LOGNOTICE, "DeviceKit.Disks: Added %s", device->m_MountPath.c_str());
361 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
365 void CDeviceKitDisksProvider::DeviceRemoved(const char *object, IStorageEventsCallback *callback)
367 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceRemoved (%s)", object);
369 CDeviceKitDiskDevice *device = m_AvailableDevices[object];
372 if (device->m_isMounted && callback)
373 callback->OnStorageUnsafelyRemoved(device->m_Label);
375 delete m_AvailableDevices[object];
376 m_AvailableDevices.erase(object);
380 void CDeviceKitDisksProvider::DeviceChanged(const char *object, IStorageEventsCallback *callback)
382 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged (%s)", object);
384 CDeviceKitDiskDevice *device = m_AvailableDevices[object];
387 CLog::Log(LOGWARNING, "DeviceKit.Disks: Inconsistency found! DeviceChanged on an unindexed disk");
388 DeviceAdded(object, callback);
392 bool mounted = device->m_isMounted;
394 if (!mounted && device->m_isMounted && callback)
395 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
396 else if (mounted && !device->m_isMounted && callback)
397 callback->OnStorageSafelyRemoved(device->m_Label);
399 CLog::Log(LOGDEBUG, "DeviceKit.Disks: DeviceChanged - %s", device->toString().c_str());
403 std::vector<CStdString> CDeviceKitDisksProvider::EnumerateDisks()
405 std::vector<CStdString> devices;
406 CDBusMessage message("org.freedesktop.DeviceKit.Disks", "/org/freedesktop/DeviceKit/Disks", "org.freedesktop.DeviceKit.Disks", "EnumerateDevices");
407 DBusMessage *reply = message.SendSystem();
413 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &disks, &length, DBUS_TYPE_INVALID))
415 for (int i = 0; i < length; i++)
416 devices.push_back(disks[i]);
418 dbus_free_string_array(disks);
425 void CDeviceKitDisksProvider::GetDisks(VECSOURCES& devices, bool EnumerateRemovable)
427 DeviceMap::iterator itr;
429 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
431 CDeviceKitDiskDevice *device = itr->second;
432 if (device && device->IsApproved() && device->m_isSystemInternal != EnumerateRemovable)
433 devices.push_back(device->ToMediaShare());