2 * Copyright (C) 2005-2015 Team Kodi
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 Kodi; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include "UDisksProvider.h"
22 #include "settings/AdvancedSettings.h"
23 #include "guilib/LocalizeStrings.h"
24 #include "utils/log.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "PosixMountProvider.h"
29 CUDiskDevice::CUDiskDevice(const char *DeviceKitUDI
):
30 m_DeviceKitUDI(DeviceKitUDI
)
33 m_isMountedByUs
= false;
34 m_isRemovable
= false;
35 m_isPartition
= false;
36 m_isFileSystem
= false;
37 m_isSystemInternal
= false;
43 void CUDiskDevice::Update()
45 CVariant properties
= CDBusUtil::GetAll("org.freedesktop.UDisks", m_DeviceKitUDI
.c_str(), "org.freedesktop.UDisks.Device");
47 m_isFileSystem
= properties
["IdUsage"].asString() == "filesystem";
50 m_UDI
= properties
["IdUuid"].asString();
51 m_Label
= properties
["IdLabel"].asString();
52 m_FileSystem
= properties
["IdType"].asString();
61 m_isMounted
= properties
["DeviceIsMounted"].asBoolean();
62 if (m_isMounted
&& !properties
["DeviceMountPaths"].empty())
63 m_MountPath
= properties
["DeviceMountPaths"][0].asString();
67 m_PartitionSize
= properties
["PartitionSize"].asUnsignedInteger();
68 m_isPartition
= properties
["DeviceIsPartition"].asBoolean();
69 m_isSystemInternal
= properties
["DeviceIsSystemInternal"].asBoolean();
70 m_isOptical
= properties
["DeviceIsOpticalDisc"].asBoolean();
73 CVariant isRemovable
= CDBusUtil::GetVariant("org.freedesktop.UDisks", properties
["PartitionSlave"].asString().c_str(), "org.freedesktop.UDisks.Device", "DeviceIsRemovable");
75 if ( !isRemovable
.isNull() )
76 m_isRemovable
= isRemovable
.asBoolean();
78 m_isRemovable
= false;
81 m_isRemovable
= properties
["DeviceIsRemovable"].asBoolean();
84 bool CUDiskDevice::Mount()
86 if (!m_isMounted
&& !m_isSystemInternal
&& m_isFileSystem
)
88 CLog::Log(LOGDEBUG
, "UDisks: Mounting %s", m_DeviceKitUDI
.c_str());
89 CDBusMessage
message("org.freedesktop.UDisks", m_DeviceKitUDI
.c_str(), "org.freedesktop.UDisks.Device", "FilesystemMount");
90 message
.AppendArgument("");
91 const char *array
[] = {};
92 message
.AppendArgument(array
, 0);
94 DBusMessage
*reply
= message
.SendSystem();
98 if (dbus_message_get_args (reply
, NULL
, DBUS_TYPE_STRING
, &mountPoint
, DBUS_TYPE_INVALID
))
100 m_MountPath
= mountPoint
;
101 CLog::Log(LOGDEBUG
, "UDisks: Successfully mounted %s on %s", m_DeviceKitUDI
.c_str(), mountPoint
);
102 m_isMountedByUs
= m_isMounted
= true;
109 CLog::Log(LOGDEBUG
, "UDisks: Is not able to mount %s", toString().c_str());
114 bool CUDiskDevice::UnMount()
116 if (m_isMounted
&& !m_isSystemInternal
&& m_isFileSystem
)
118 CDBusMessage
message("org.freedesktop.UDisks", m_DeviceKitUDI
.c_str(), "org.freedesktop.UDisks.Device", "FilesystemUnmount");
120 const char *array
[1];
121 message
.AppendArgument(array
, 0);
123 DBusMessage
*reply
= message
.SendSystem();
125 m_isMountedByUs
= m_isMounted
= false;
130 CLog::Log(LOGDEBUG
, "UDisks: Is not able to unmount %s", toString().c_str());
135 CMediaSource
CUDiskDevice::ToMediaShare()
138 source
.strPath
= m_MountPath
;
141 std::string strSize
= StringUtils::SizeToString(m_PartitionSize
);
142 source
.strName
= StringUtils::Format("%s %s", strSize
.c_str(), g_localizeStrings
.Get(155).c_str());
145 source
.strName
= m_Label
;
147 source
.m_iDriveType
= CMediaSource::SOURCE_TYPE_DVD
;
148 else if (m_isSystemInternal
)
149 source
.m_iDriveType
= CMediaSource::SOURCE_TYPE_LOCAL
;
151 source
.m_iDriveType
= CMediaSource::SOURCE_TYPE_REMOVABLE
;
152 source
.m_ignore
= true;
156 bool CUDiskDevice::IsApproved()
158 return (m_isFileSystem
&& m_isMounted
&& m_UDI
.length() > 0 && (m_FileSystem
.length() > 0 && m_FileSystem
!= "swap")
159 && m_MountPath
!= "/" && m_MountPath
!= "/boot") || m_isOptical
;
162 #define BOOL2SZ(b) ((b) ? "true" : "false")
164 std::string
CUDiskDevice::toString()
166 return StringUtils::Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
167 "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
169 m_DeviceKitUDI
.c_str(), BOOL2SZ(m_isFileSystem
), m_FileSystem
.c_str(),
170 BOOL2SZ(m_isSystemInternal
), BOOL2SZ(m_isMounted
),
171 BOOL2SZ(m_isRemovable
), BOOL2SZ(m_isPartition
), BOOL2SZ(m_isOptical
));
174 CUDisksProvider::CUDisksProvider()
176 dbus_error_init (&m_error
);
177 //! @todo do not use dbus_connection_pop_message() that requires the use of a
178 //! private connection
179 m_connection
= dbus_bus_get_private(DBUS_BUS_SYSTEM
, &m_error
);
183 dbus_connection_set_exit_on_disconnect(m_connection
, false);
185 dbus_bus_add_match(m_connection
, "type='signal',interface='org.freedesktop.UDisks'", &m_error
);
186 dbus_connection_flush(m_connection
);
189 if (dbus_error_is_set(&m_error
))
191 CLog::Log(LOGERROR
, "UDisks: Failed to attach to signal %s", m_error
.message
);
192 dbus_connection_close(m_connection
);
193 dbus_connection_unref(m_connection
);
198 CUDisksProvider::~CUDisksProvider()
200 DeviceMap::iterator itr
;
202 for (itr
= m_AvailableDevices
.begin(); itr
!= m_AvailableDevices
.end(); ++itr
)
203 delete m_AvailableDevices
[itr
->first
];
205 m_AvailableDevices
.clear();
209 dbus_connection_close(m_connection
);
210 dbus_connection_unref(m_connection
);
214 dbus_error_free (&m_error
);
217 void CUDisksProvider::Initialize()
219 CLog::Log(LOGDEBUG
, "Selected UDisks as storage provider");
220 m_DaemonVersion
= atoi(CDBusUtil::GetVariant("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "DaemonVersion").asString().c_str());
221 CLog::Log(LOGDEBUG
, "UDisks: DaemonVersion %i", m_DaemonVersion
);
223 CLog::Log(LOGDEBUG
, "UDisks: Querying available devices");
224 std::vector
<std::string
> devices
= EnumerateDisks();
225 for (unsigned int i
= 0; i
< devices
.size(); i
++)
226 DeviceAdded(devices
[i
].c_str(), NULL
);
229 bool CUDisksProvider::Eject(const std::string
& mountpath
)
231 DeviceMap::iterator itr
;
232 std::string
path(mountpath
);
233 URIUtils::RemoveSlashAtEnd(path
);
235 for (itr
= m_AvailableDevices
.begin(); itr
!= m_AvailableDevices
.end(); ++itr
)
237 CUDiskDevice
*device
= itr
->second
;
238 if (device
->m_MountPath
== path
)
239 return device
->UnMount();
245 std::vector
<std::string
> CUDisksProvider::GetDiskUsage()
247 CPosixMountProvider legacy
;
248 return legacy
.GetDiskUsage();
251 bool CUDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback
*callback
)
256 dbus_connection_read_write(m_connection
, 0);
257 DBusMessage
*msg
= dbus_connection_pop_message(m_connection
);
262 if (dbus_message_get_args (msg
, NULL
, DBUS_TYPE_OBJECT_PATH
, &object
, DBUS_TYPE_INVALID
))
265 if (dbus_message_is_signal(msg
, "org.freedesktop.UDisks", "DeviceAdded"))
266 DeviceAdded(object
, callback
);
267 else if (dbus_message_is_signal(msg
, "org.freedesktop.UDisks", "DeviceRemoved"))
268 DeviceRemoved(object
, callback
);
269 else if (dbus_message_is_signal(msg
, "org.freedesktop.UDisks", "DeviceChanged"))
270 DeviceChanged(object
, callback
);
272 dbus_message_unref(msg
);
278 bool CUDisksProvider::HasUDisks()
280 bool hasUDisks
= false;
281 CDBusMessage
message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
284 dbus_error_init (&error
);
285 DBusConnection
*con
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
);
288 message
.Send(con
, &error
);
290 if (!dbus_error_is_set(&error
))
293 CLog::Log(LOGDEBUG
, "UDisks: %s - %s", error
.name
, error
.message
);
295 dbus_error_free (&error
);
297 dbus_connection_unref(con
);
302 void CUDisksProvider::DeviceAdded(const char *object
, IStorageEventsCallback
*callback
)
304 if (g_advancedSettings
.CanLogComponent(LOGDBUS
))
305 CLog::Log(LOGDEBUG
, "UDisks: DeviceAdded (%s)", object
);
307 if (m_AvailableDevices
[object
])
309 CLog::Log(LOGWARNING
, "UDisks: Inconsistency found! DeviceAdded on an indexed disk");
310 delete m_AvailableDevices
[object
];
313 CUDiskDevice
*device
= NULL
;
314 device
= new CUDiskDevice(object
);
315 m_AvailableDevices
[object
] = device
;
317 if (g_advancedSettings
.m_handleMounting
)
320 if (g_advancedSettings
.CanLogComponent(LOGDBUS
))
321 CLog::Log(LOGDEBUG
, "UDisks: DeviceAdded - %s", device
->toString().c_str());
323 if (device
->m_isMounted
&& device
->IsApproved())
325 CLog::Log(LOGINFO
, "UDisks: Added %s", device
->m_MountPath
.c_str());
327 callback
->OnStorageAdded(device
->m_Label
, device
->m_MountPath
);
331 void CUDisksProvider::DeviceRemoved(const char *object
, IStorageEventsCallback
*callback
)
333 if (g_advancedSettings
.CanLogComponent(LOGDBUS
))
334 CLog::Log(LOGDEBUG
, "UDisks: DeviceRemoved (%s)", object
);
336 CUDiskDevice
*device
= m_AvailableDevices
[object
];
339 if (device
->m_isMounted
&& callback
)
340 callback
->OnStorageUnsafelyRemoved(device
->m_Label
);
342 delete m_AvailableDevices
[object
];
343 m_AvailableDevices
.erase(object
);
347 void CUDisksProvider::DeviceChanged(const char *object
, IStorageEventsCallback
*callback
)
349 if (g_advancedSettings
.CanLogComponent(LOGDBUS
))
350 CLog::Log(LOGDEBUG
, "UDisks: DeviceChanged (%s)", object
);
352 CUDiskDevice
*device
= m_AvailableDevices
[object
];
355 CLog::Log(LOGWARNING
, "UDisks: Inconsistency found! DeviceChanged on an unindexed disk");
356 DeviceAdded(object
, callback
);
360 bool mounted
= device
->m_isMounted
;
361 /* make sure to not silently remount ejected usb thumb drives
362 that user wants to eject, but make sure to mount blurays */
363 if (!mounted
&& g_advancedSettings
.m_handleMounting
&& device
->m_isOptical
)
367 if (!mounted
&& device
->m_isMounted
&& callback
)
368 callback
->OnStorageAdded(device
->m_Label
, device
->m_MountPath
);
369 else if (mounted
&& !device
->m_isMounted
&& callback
)
370 callback
->OnStorageSafelyRemoved(device
->m_Label
);
372 if (g_advancedSettings
.CanLogComponent(LOGDBUS
))
373 CLog::Log(LOGDEBUG
, "UDisks: DeviceChanged - %s", device
->toString().c_str());
377 std::vector
<std::string
> CUDisksProvider::EnumerateDisks()
379 std::vector
<std::string
> devices
;
380 CDBusMessage
message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
381 DBusMessage
*reply
= message
.SendSystem();
387 if (dbus_message_get_args (reply
, NULL
, DBUS_TYPE_ARRAY
, DBUS_TYPE_OBJECT_PATH
, &disks
, &length
, DBUS_TYPE_INVALID
))
389 for (int i
= 0; i
< length
; i
++)
390 devices
.push_back(disks
[i
]);
392 dbus_free_string_array(disks
);
399 void CUDisksProvider::GetDisks(VECSOURCES
& devices
, bool EnumerateRemovable
)
401 DeviceMap::iterator itr
;
403 for (itr
= m_AvailableDevices
.begin(); itr
!= m_AvailableDevices
.end(); ++itr
)
405 CUDiskDevice
*device
= itr
->second
;
406 if (device
&& device
->IsApproved() && device
->m_isSystemInternal
!= EnumerateRemovable
)
407 devices
.push_back(device
->ToMediaShare());