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 "UDisksProvider.h"
23 #include "settings/AdvancedSettings.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "utils/log.h"
26 #include "utils/URIUtils.h"
28 CUDiskDevice::CUDiskDevice(const char *DeviceKitUDI)
30 m_DeviceKitUDI = DeviceKitUDI;
35 m_isMountedByUs = false;
36 m_isRemovable = false;
37 m_isPartition = false;
38 m_isFileSystem = false;
39 m_isSystemInternal = false;
41 m_PartitionSizeGiB = 0.0f;
45 void CUDiskDevice::Update()
47 CVariant properties = CDBusUtil::GetAll("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device");
49 m_isFileSystem = CStdString(properties["IdUsage"].asString()) == "filesystem";
52 m_UDI = properties["IdUuid"].asString();
53 m_Label = properties["IdLabel"].asString();
54 m_FileSystem = properties["IdType"].asString();
63 m_isMounted = properties["DeviceIsMounted"].asBoolean();
64 if (m_isMounted && properties["DeviceMountPaths"].size() > 0)
65 m_MountPath = properties["DeviceMountPaths"][0].asString();
69 m_PartitionSizeGiB = properties["PartitionSize"].asUnsignedInteger() / 1024.0 / 1024.0 / 1024.0;
70 m_isPartition = properties["DeviceIsPartition"].asBoolean();
71 m_isSystemInternal = properties["DeviceIsSystemInternal"].asBoolean();
72 m_isOptical = properties["DeviceIsOpticalDisc"].asBoolean();
75 CVariant isRemovable = CDBusUtil::GetVariant("org.freedesktop.UDisks", properties["PartitionSlave"].asString().c_str(), "org.freedesktop.UDisks.Device", "DeviceIsRemovable");
77 if ( !isRemovable.isNull() )
78 m_isRemovable = isRemovable.asBoolean();
80 m_isRemovable = false;
83 m_isRemovable = properties["DeviceIsRemovable"].asBoolean();
86 bool CUDiskDevice::Mount()
88 if (!m_isMounted && !m_isSystemInternal && m_isFileSystem)
90 CLog::Log(LOGDEBUG, "UDisks: Mounting %s", m_DeviceKitUDI.c_str());
91 CDBusMessage message("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device", "FilesystemMount");
92 message.AppendArgument("");
93 const char *array[] = {};
94 message.AppendArgument(array, 0);
96 DBusMessage *reply = message.SendSystem();
100 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &mountPoint, DBUS_TYPE_INVALID))
102 m_MountPath = mountPoint;
103 CLog::Log(LOGDEBUG, "UDisks: Sucessfully mounted %s on %s", m_DeviceKitUDI.c_str(), mountPoint);
104 m_isMountedByUs = m_isMounted = true;
111 CLog::Log(LOGDEBUG, "UDisks: Is not able to mount %s", toString().c_str());
116 bool CUDiskDevice::UnMount()
118 if (m_isMounted && !m_isSystemInternal && m_isFileSystem)
120 CDBusMessage message("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device", "FilesystemUnmount");
122 const char *array[1];
123 message.AppendArgument(array, 0);
125 DBusMessage *reply = message.SendSystem();
127 m_isMountedByUs = m_isMounted = false;
132 CLog::Log(LOGDEBUG, "UDisks: Is not able to unmount %s", toString().c_str());
137 CMediaSource CUDiskDevice::ToMediaShare()
140 source.strPath = m_MountPath;
142 source.strName.Format("%.1f GB %s", m_PartitionSizeGiB, g_localizeStrings.Get(155).c_str());
144 source.strName = m_Label;
146 source.m_iDriveType = CMediaSource::SOURCE_TYPE_DVD;
147 else if (m_isSystemInternal)
148 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
150 source.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
151 source.m_ignore = true;
155 bool CUDiskDevice::IsApproved()
157 return (m_isFileSystem && m_isMounted && m_UDI.length() > 0 && (m_FileSystem.length() > 0 && !m_FileSystem.Equals("swap")) && !m_MountPath.Equals("/")) || m_isOptical;
160 #define BOOL2SZ(b) ((b) ? "true" : "false")
162 CStdString CUDiskDevice::toString()
165 str.Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
166 "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
168 m_DeviceKitUDI.c_str(), BOOL2SZ(m_isFileSystem), m_FileSystem,
169 BOOL2SZ(m_isSystemInternal), BOOL2SZ(m_isMounted),
170 BOOL2SZ(m_isRemovable), BOOL2SZ(m_isPartition), BOOL2SZ(m_isOptical));
175 CUDisksProvider::CUDisksProvider()
177 dbus_error_init (&m_error);
178 // TODO: do not use dbus_connection_pop_message() that requires the use of a
179 // private connection
180 m_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_error);
184 dbus_connection_set_exit_on_disconnect(m_connection, false);
186 dbus_bus_add_match(m_connection, "type='signal',interface='org.freedesktop.UDisks'", &m_error);
187 dbus_connection_flush(m_connection);
190 if (dbus_error_is_set(&m_error))
192 CLog::Log(LOGERROR, "UDisks: Failed to attach to signal %s", m_error.message);
193 dbus_connection_close(m_connection);
194 dbus_connection_unref(m_connection);
199 CUDisksProvider::~CUDisksProvider()
201 DeviceMap::iterator itr;
203 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
204 delete m_AvailableDevices[itr->first];
206 m_AvailableDevices.clear();
210 dbus_connection_close(m_connection);
211 dbus_connection_unref(m_connection);
215 dbus_error_free (&m_error);
218 void CUDisksProvider::Initialize()
220 CLog::Log(LOGDEBUG, "Selected UDisks as storage provider");
221 m_DaemonVersion = atoi(CDBusUtil::GetVariant("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "DaemonVersion").asString().c_str());
222 CLog::Log(LOGDEBUG, "UDisks: DaemonVersion %i", m_DaemonVersion);
224 CLog::Log(LOGDEBUG, "UDisks: Querying available devices");
225 std::vector<CStdString> devices = EnumerateDisks();
226 for (unsigned int i = 0; i < devices.size(); i++)
227 DeviceAdded(devices[i].c_str(), NULL);
230 bool CUDisksProvider::Eject(CStdString mountpath)
232 DeviceMap::iterator itr;
233 CStdString path(mountpath);
234 URIUtils::RemoveSlashAtEnd(path);
236 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
238 CUDiskDevice *device = itr->second;
239 if (device->m_MountPath.Equals(path))
240 return device->UnMount();
246 std::vector<CStdString> CUDisksProvider::GetDiskUsage()
248 std::vector<CStdString> devices;
249 DeviceMap::iterator itr;
251 for(itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
253 CUDiskDevice *device = itr->second;
254 if (device->m_isMounted)
257 str.Format("%s %.1f GiB", device->m_MountPath.c_str(), device->m_PartitionSizeGiB);
258 devices.push_back(str);
265 bool CUDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
270 dbus_connection_read_write(m_connection, 0);
271 DBusMessage *msg = dbus_connection_pop_message(m_connection);
276 if (dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &object, DBUS_TYPE_INVALID))
279 if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceAdded"))
280 DeviceAdded(object, callback);
281 else if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceRemoved"))
282 DeviceRemoved(object, callback);
283 else if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceChanged"))
284 DeviceChanged(object, callback);
286 dbus_message_unref(msg);
292 bool CUDisksProvider::HasUDisks()
294 bool hasUDisks = false;
295 CDBusMessage message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
298 dbus_error_init (&error);
299 DBusConnection *con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
302 message.Send(con, &error);
304 if (!dbus_error_is_set(&error))
307 CLog::Log(LOGDEBUG, "UDisks: %s - %s", error.name, error.message);
309 dbus_error_free (&error);
311 dbus_connection_unref(con);
316 void CUDisksProvider::DeviceAdded(const char *object, IStorageEventsCallback *callback)
318 CLog::Log(LOGDEBUG, "UDisks: DeviceAdded (%s)", object);
320 if (m_AvailableDevices[object])
322 CLog::Log(LOGWARNING, "UDisks: Inconsistency found! DeviceAdded on an indexed disk");
323 delete m_AvailableDevices[object];
326 CUDiskDevice *device = NULL;
327 device = new CUDiskDevice(object);
328 m_AvailableDevices[object] = device;
330 if (g_advancedSettings.m_handleMounting)
333 CLog::Log(LOGDEBUG, "UDisks: DeviceAdded - %s", device->toString().c_str());
334 if (device->m_isMounted && device->IsApproved())
336 CLog::Log(LOGNOTICE, "UDisks: Added %s", device->m_MountPath.c_str());
338 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
342 void CUDisksProvider::DeviceRemoved(const char *object, IStorageEventsCallback *callback)
344 CLog::Log(LOGDEBUG, "UDisks: DeviceRemoved (%s)", object);
346 CUDiskDevice *device = m_AvailableDevices[object];
349 if (device->m_isMounted && callback)
350 callback->OnStorageUnsafelyRemoved(device->m_Label);
352 delete m_AvailableDevices[object];
353 m_AvailableDevices.erase(object);
357 void CUDisksProvider::DeviceChanged(const char *object, IStorageEventsCallback *callback)
359 CLog::Log(LOGDEBUG, "UDisks: DeviceChanged (%s)", object);
361 CUDiskDevice *device = m_AvailableDevices[object];
364 CLog::Log(LOGWARNING, "UDisks: Inconsistency found! DeviceChanged on an unindexed disk");
365 DeviceAdded(object, callback);
369 bool mounted = device->m_isMounted;
371 if (!mounted && device->m_isMounted && callback)
372 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
373 else if (mounted && !device->m_isMounted && callback)
374 callback->OnStorageSafelyRemoved(device->m_Label);
376 CLog::Log(LOGDEBUG, "UDisks: DeviceChanged - %s", device->toString().c_str());
380 std::vector<CStdString> CUDisksProvider::EnumerateDisks()
382 std::vector<CStdString> devices;
383 CDBusMessage message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
384 DBusMessage *reply = message.SendSystem();
390 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &disks, &length, DBUS_TYPE_INVALID))
392 for (int i = 0; i < length; i++)
393 devices.push_back(disks[i]);
395 dbus_free_string_array(disks);
402 void CUDisksProvider::GetDisks(VECSOURCES& devices, bool EnumerateRemovable)
404 DeviceMap::iterator itr;
406 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
408 CUDiskDevice *device = itr->second;
409 if (device && device->IsApproved() && device->m_isSystemInternal != EnumerateRemovable)
410 devices.push_back(device->ToMediaShare());