VirtualBox

source: vbox/trunk/src/VBox/Main/linux/HostHardwareLinux.cpp@ 14991

Last change on this file since 14991 was 14991, checked in by vboxsync, 16 years ago

Main: rework the Linux host drive code to use libdbus-1 directly instead of libhal

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 25.1 KB
Line 
1/* $Id: HostHardwareLinux.cpp 14991 2008-12-04 15:17:33Z vboxsync $ */
2/** @file
3 * Classes for handling hardware detection under Linux. Please feel free to
4 * expand these to work for other systems (Solaris!) or to add new ones for
5 * other systems.
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#define LOG_GROUP LOG_GROUP_MAIN
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29
30#include <HostHardwareLinux.h>
31
32#include <VBox/log.h>
33
34#include <iprt/env.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37
38#ifdef RT_OS_LINUX
39# include <sys/types.h>
40# include <sys/stat.h>
41# include <unistd.h>
42# include <sys/ioctl.h>
43# include <fcntl.h>
44# include <mntent.h>
45/* bird: This is a hack to work around conflicts between these linux kernel headers
46 * and the GLIBC tcpip headers. They have different declarations of the 4
47 * standard byte order functions. */
48// # define _LINUX_BYTEORDER_GENERIC_H
49# include <linux/cdrom.h>
50# ifdef VBOX_WITH_DBUS
51# include <dbus/dbus.h>
52/* These are defined by the dbus headers and by VBox header files. */
53# undef TRUE
54# undef FALSE
55# endif
56# include <errno.h>
57#endif /* RT_OS_LINUX */
58
59/*******************************************************************************
60* Global Variables *
61*******************************************************************************/
62
63bool g_testHostHardwareLinux = false;
64static bool testing () { return g_testHostHardwareLinux; }
65
66/*******************************************************************************
67* Defines and Typedefs *
68*******************************************************************************/
69
70typedef VBoxMainDriveInfo::DriveInfoList DriveInfoList;
71typedef VBoxMainDriveInfo::DriveInfo DriveInfo;
72
73static bool validateDevice(const char *deviceNode, bool isDVD);
74static int getDriveInfoFromEnv(const char *pszVar, DriveInfoList *pList,
75 bool isDVD, bool *pfSuccess);
76static int getDVDInfoFromMTab(char *mountTable, DriveInfoList *pList);
77static int halInit(DBusConnection **ppConnection);
78static int halFindDeviceStringMatch (DBusConnection *pConnection,
79 const char *pszKey, const char *pszValue,
80 DBusMessage **ppMessage);
81static int halGetPropertyStrings (DBusConnection *pConnection,
82 const char *pszUdi, size_t cKeys,
83 const char **papszKeys, char **papszValues,
84 DBusMessage **ppMessage);
85static int getDriveInfoFromHal(DriveInfoList *pList, bool isDVD,
86 bool *pfSuccess);
87
88/**
89 * Updates the list of host DVD drives.
90 *
91 * @returns iprt status code
92 */
93int VBoxMainDriveInfo::updateDVDs ()
94{
95 LogFlowThisFunc (("entered\n"));
96 int rc = VINF_SUCCESS;
97 bool success = false; /* Have we succeeded in finding anything yet? */
98 try
99 {
100 mDVDList.clear ();
101#if defined(RT_OS_LINUX)
102#ifdef VBOX_WITH_DBUS
103 if (RT_SUCCESS (rc) && (!success || testing()))
104 rc = getDriveInfoFromHal(&mDVDList, true /* isDVD */, &success);
105#endif /* VBOX_WITH_DBUS defined */
106 // On Linux without hal, the situation is much more complex. We will take a
107 // heuristical approach and also allow the user to specify a list of host
108 // CDROMs using an environment variable.
109 // The general strategy is to try some known device names and see of they
110 // exist. At last, we'll enumerate the /etc/fstab file (luckily there's an
111 // API to parse it) for CDROM devices. Ok, let's start!
112 if (RT_SUCCESS (rc) && (!success || testing()))
113 rc = getDriveInfoFromEnv ("VBOX_CDROM", &mDVDList, true /* isDVD */,
114 &success);
115 if (RT_SUCCESS (rc) && (!success || testing()))
116 {
117 // this is a good guess usually
118 if (validateDevice("/dev/cdrom", true))
119 mDVDList.push_back (DriveInfo ("/dev/cdrom"));
120
121 // check the mounted drives
122 rc = getDVDInfoFromMTab((char*)"/etc/mtab", &mDVDList);
123
124 // check the drives that can be mounted
125 if (RT_SUCCESS (rc))
126 rc = getDVDInfoFromMTab((char*)"/etc/fstab", &mDVDList);
127 }
128#endif
129 }
130 catch (std::bad_alloc)
131 {
132 rc = VERR_NO_MEMORY;
133 }
134 LogFlowThisFunc (("rc=%Rrc\n", rc));
135 return rc;
136}
137
138/**
139 * Updates the list of host floppy drives.
140 *
141 * @returns iprt status code
142 */
143int VBoxMainDriveInfo::updateFloppies ()
144{
145 LogFlowThisFunc (("entered\n"));
146 int rc = VINF_SUCCESS;
147 bool success = false; /* Have we succeeded in finding anything yet? */
148 try
149 {
150 mFloppyList.clear ();
151#if defined(RT_OS_LINUX)
152#ifdef VBOX_WITH_DBUS
153 if (RT_SUCCESS (rc) && (!success || testing()))
154 rc = getDriveInfoFromHal(&mFloppyList, false /* isDVD */, &success);
155#endif /* VBOX_WITH_DBUS defined */
156 // As with the CDROMs, on Linux we have to take a multi-level approach
157 // involving parsing the mount tables. As this is not bulletproof, we'll
158 // give the user the chance to override the detection by an environment
159 // variable and skip the detection.
160 if (RT_SUCCESS (rc) && (!success || testing()))
161 rc = getDriveInfoFromEnv ("VBOX_FLOPPY", &mFloppyList, false /* isDVD */,
162 &success);
163
164 if (RT_SUCCESS (rc) && (!success || testing()))
165 {
166 // we assume that a floppy is always /dev/fd[x] with x from 0 to 7
167 char devName[10];
168 for (int i = 0; i <= 7; i++)
169 {
170 sprintf(devName, "/dev/fd%d", i);
171 if (validateDevice(devName, false))
172 mFloppyList.push_back (DriveInfo (devName));
173 }
174 }
175#endif
176 }
177 catch (std::bad_alloc)
178 {
179 rc = VERR_NO_MEMORY;
180 }
181 LogFlowThisFunc (("rc=%Rrc\n", rc));
182 return rc;
183}
184
185#ifdef RT_OS_LINUX
186/**
187 * Helper function to check whether the given device node is a valid drive
188 */
189/* static */
190bool validateDevice(const char *deviceNode, bool isDVD)
191{
192 AssertReturn(VALID_PTR (deviceNode), VERR_INVALID_POINTER);
193 LogFlowFunc (("deviceNode=%s, isDVD=%d\n", deviceNode, isDVD));
194 struct stat statInfo;
195 bool retValue = false;
196
197 // sanity check
198 if (!deviceNode)
199 {
200 return false;
201 }
202
203 // first a simple stat() call
204 if (stat(deviceNode, &statInfo) < 0)
205 {
206 return false;
207 } else
208 {
209 if (isDVD)
210 {
211 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
212 {
213 int fileHandle;
214 // now try to open the device
215 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
216 if (fileHandle >= 0)
217 {
218 cdrom_subchnl cdChannelInfo;
219 cdChannelInfo.cdsc_format = CDROM_MSF;
220 // this call will finally reveal the whole truth
221#ifdef RT_OS_LINUX
222 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
223 (errno == EIO) || (errno == ENOENT) ||
224 (errno == EINVAL) || (errno == ENOMEDIUM))
225#endif
226 {
227 retValue = true;
228 }
229 close(fileHandle);
230 }
231 }
232 } else
233 {
234 // floppy case
235 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
236 {
237 /// @todo do some more testing, maybe a nice IOCTL!
238 retValue = true;
239 }
240 }
241 }
242 LogFlowFunc (("retValue=%d\n", retValue));
243 return retValue;
244}
245#else /* !RT_OS_LINUX */
246# error Port me! Copying code over from HostImpl.cpp should be most of the job though.
247#endif /* !RT_OS_LINUX */
248
249/**
250 * Extract the names of drives from an environment variable and add them to a
251 * list if they are valid.
252 * @returns iprt status code
253 * @param pszVar the name of the environment variable. The variable
254 * value should be a list of device node names, separated
255 * by ':' characters.
256 * @param pList the list to append the drives found to
257 * @param isDVD are we looking for DVD drives or for floppies?
258 * @param pfSuccess this will be set to true if we found at least one drive
259 * and to false otherwise. Optional.
260 */
261/* static */
262int getDriveInfoFromEnv(const char *pszVar, DriveInfoList *pList,
263 bool isDVD, bool *pfSuccess)
264{
265 AssertReturn( VALID_PTR (pszVar) && VALID_PTR (pList)
266 && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
267 VERR_INVALID_POINTER);
268 LogFlowFunc (("pszVar=%s, pList=%p, isDVD=%d, pfSuccess=%p\n", pszVar,
269 pList, isDVD, pfSuccess));
270 int rc = VINF_SUCCESS;
271 bool success = false;
272 RTMemAutoPtr<char, RTStrFree> drive;
273 const char *pszValue = RTEnvGet (pszVar);
274 if (pszValue != NULL)
275 {
276 drive = RTStrDup (pszValue);
277 if (!drive)
278 rc = VERR_NO_MEMORY;
279 }
280 if (pszValue != NULL && RT_SUCCESS (rc))
281 {
282 char *pDrive = drive.get();
283 char *pDriveNext = strchr (pDrive, ':');
284 while (pDrive != NULL && *pDrive != '\0')
285 {
286 if (pDriveNext != NULL)
287 *pDriveNext = '\0';
288 if (validateDevice(pDrive, isDVD))
289 {
290 pList->push_back (DriveInfo (pDrive));
291 success = true;
292 }
293 if (pDriveNext != NULL)
294 {
295 pDrive = pDriveNext + 1;
296 pDriveNext = strchr (pDrive, ':');
297 }
298 else
299 pDrive = NULL;
300 }
301 }
302 if (pfSuccess != NULL)
303 *pfSuccess = success;
304 LogFlowFunc (("rc=%Rrc, success=%d\n", rc, success));
305 return rc;
306}
307
308#ifdef RT_OS_LINUX
309/**
310 * Helper function to parse the given mount file and add found entries
311 */
312/* static */
313int getDVDInfoFromMTab(char *mountTable, DriveInfoList *pList)
314{
315 AssertReturn(VALID_PTR (mountTable) && VALID_PTR (pList),
316 VERR_INVALID_POINTER);
317#ifdef RT_OS_LINUX
318 LogFlowFunc (("mountTable=%s, pList=%p\n", mountTable, pList));
319 int rc = VINF_SUCCESS;
320 FILE *mtab = setmntent(mountTable, "r");
321 if (mtab)
322 {
323 struct mntent *mntent;
324 RTMemAutoPtr <char, RTStrFree> mnt_type, mnt_dev;
325 char *tmp;
326 while (RT_SUCCESS (rc) && (mntent = getmntent(mtab)))
327 {
328 mnt_type = RTStrDup (mntent->mnt_type);
329 mnt_dev = RTStrDup (mntent->mnt_fsname);
330 if (!mnt_type || !mnt_dev)
331 rc = VERR_NO_MEMORY;
332 // supermount fs case
333 if (RT_SUCCESS (rc) && strcmp(mnt_type.get(), "supermount") == 0)
334 {
335 tmp = strstr(mntent->mnt_opts, "fs=");
336 if (tmp)
337 {
338 mnt_type = RTStrDup(tmp + strlen("fs="));
339 if (!mnt_type)
340 rc = VERR_NO_MEMORY;
341 else
342 {
343 tmp = strchr(mnt_type.get(), ',');
344 if (tmp)
345 *tmp = '\0';
346 }
347 }
348 tmp = strstr(mntent->mnt_opts, "dev=");
349 if (tmp)
350 {
351 mnt_dev = RTStrDup(tmp + strlen("dev="));
352 if (!mnt_dev)
353 rc = VERR_NO_MEMORY;
354 else
355 {
356 tmp = strchr(mnt_dev.get(), ',');
357 if (tmp)
358 *tmp = '\0';
359 }
360 }
361 }
362 // use strstr here to cover things fs types like "udf,iso9660"
363 if (RT_SUCCESS (rc) && strstr(mnt_type.get(), "iso9660") == 0)
364 {
365 if (validateDevice(mnt_dev.get(), true))
366 {
367 bool insert = true;
368 struct stat srcInfo;
369 if (stat (mnt_dev.get(), &srcInfo) < 0)
370 insert = false;
371 for (DriveInfoList::const_iterator it = pList->begin();
372 insert && it != pList->end(); ++it)
373 {
374 struct stat destInfo;
375 if ( (stat (it->mDevice.c_str(), &destInfo) == 0)
376 && (srcInfo.st_rdev == destInfo.st_rdev))
377 insert = false;
378 }
379 if (insert)
380 pList->push_back (DriveInfo (mnt_dev.get()));
381 }
382 }
383 }
384 endmntent(mtab);
385 }
386 return rc;
387#endif
388}
389
390#endif /* RT_OS_LINUX */
391
392#if defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)
393/* Linux, load libdbus statically */
394
395/** Wrapper class around DBusError for automatic cleanup */
396class autoDBusError
397{
398 DBusError mError;
399public:
400 autoDBusError () { dbus_error_init (&mError); }
401 ~autoDBusError ()
402 {
403 if (dbus_error_is_set (&mError))
404 dbus_error_free (&mError);
405 }
406 DBusError &get () { return mError; }
407 bool IsSet () { return dbus_error_is_set (&mError); }
408 bool HasName (const char *pszName)
409 {
410 return dbus_error_has_name (&mError, pszName);
411 }
412 void FlowLog ()
413 {
414 if (IsSet ())
415 LogFlow(("DBus error %s: %s\n", mError.name, mError.message));
416 }
417};
418
419/**
420 * Helper function for setting up a connection to hal
421 * @returns iprt status code
422 * @param ppConnection where to store the connection handle
423 */
424/* static */
425int halInit (DBusConnection **ppConnection)
426{
427 AssertReturn(VALID_PTR (ppConnection), VERR_INVALID_POINTER);
428 LogFlowFunc (("ppConnection=%p\n", ppConnection));
429 int rc = VINF_SUCCESS;
430 bool halSuccess = true;
431 autoDBusError dbusError;
432
433 RTMemAutoPtr <DBusConnection, dbus_connection_unref> dbusConnection;
434 dbusConnection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbusError.get());
435 if (!dbusConnection)
436 halSuccess = false;
437 if (halSuccess)
438 {
439 dbus_connection_set_exit_on_disconnect (dbusConnection.get(), false);
440 halSuccess = dbus_bus_name_has_owner (dbusConnection.get(),
441 "org.freedesktop.Hal", &dbusError.get());
442 }
443 if (halSuccess)
444 {
445 dbus_bus_add_match (dbusConnection.get(),
446 "type='signal',"
447 "interface='org.freedesktop.Hal.Manager',"
448 "sender='org.freedesktop.Hal',"
449 "path='/org/freedesktop/Hal/Manager'", &dbusError.get());
450 halSuccess = !dbusError.IsSet();
451 }
452 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
453 rc = VERR_NO_MEMORY;
454 *ppConnection = halSuccess ? dbusConnection.release() : NULL;
455 LogFlowFunc(("rc=%Rrc, *ppConnection=%p\n", rc, *ppConnection));
456 dbusError.FlowLog();
457 return rc;
458}
459
460/**
461 * Find the UDIs of hal entries that contain Key=Value property.
462 * @returns iprt status code
463 * @param pConnection an initialised connection DBus
464 * @param pszKey the property key
465 * @param pszValue the property value
466 * @param ppMessage where to store the return DBus message. This must be
467 * parsed to get at the UDIs. NOT optional. The caller
468 * is responsible for freeing this.
469 */
470/* static */
471int halFindDeviceStringMatch (DBusConnection *pConnection, const char *pszKey,
472 const char *pszValue, DBusMessage **ppMessage)
473{
474 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszKey)
475 && VALID_PTR (pszValue) && VALID_PTR (ppMessage),
476 VERR_INVALID_POINTER);
477 LogFlowFunc (("pConnection=%p, pszKey=%s, pszValue=%s, ppMessage=%p\n",
478 pConnection, pszKey, pszValue, ppMessage));
479 int rc = VINF_SUCCESS;
480 bool halSuccess = true;
481 autoDBusError dbusError;
482 RTMemAutoPtr <DBusMessage, dbus_message_unref> message;
483 DBusMessage *pReply = NULL;
484 if (halSuccess && RT_SUCCESS (rc))
485 {
486 message = dbus_message_new_method_call ("org.freedesktop.Hal",
487 "/org/freedesktop/Hal/Manager",
488 "org.freedesktop.Hal.Manager",
489 "FindDeviceStringMatch");
490 if (!message)
491 rc = VERR_NO_MEMORY;
492 }
493 if (halSuccess && RT_SUCCESS (rc))
494 {
495 DBusMessageIter iterAppend;
496 dbus_message_iter_init_append (message.get(), &iterAppend);
497 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszKey);
498 dbus_message_iter_append_basic (&iterAppend, DBUS_TYPE_STRING, &pszValue);
499 pReply = dbus_connection_send_with_reply_and_block (pConnection,
500 message.get(), -1,
501 &dbusError.get());
502 if (pReply == NULL)
503 halSuccess = false;
504 }
505 *ppMessage = pReply;
506 LogFlowFunc (("rc=%Rrc, *ppMessage=%p\n", rc, *ppMessage));
507 dbusError.FlowLog();
508 return rc;
509}
510
511/**
512 * Read a set of string properties for a device. If some of the properties are
513 * not of type DBUS_TYPE_STRING then a NULL pointer will be returned for them.
514 * @returns iprt status code
515 * @param pConnection an initialised connection DBus
516 * @param pszUdi the Udi of the device
517 * @param cProps the number of property values to look up
518 * @param papszKeys the keys of the properties to be looked up
519 * @param papszValues where to store the values of the properties. The
520 * strings returned will be valid until the message
521 * returned in @a ppMessage is freed. Undefined if
522 * the message is NULL.
523 * @param ppMessage where to store the return DBus message. The caller
524 * is responsible for freeing this once they have
525 * finished with the value strings. NOT optional.
526 */
527/* static */
528int halGetPropertyStrings (DBusConnection *pConnection, const char *pszUdi,
529 size_t cProps, const char **papszKeys,
530 char **papszValues, DBusMessage **ppMessage)
531{
532 AssertReturn( VALID_PTR (pConnection) && VALID_PTR (pszUdi)
533 && VALID_PTR (papszKeys) && VALID_PTR (papszValues)
534 && VALID_PTR (ppMessage),
535 VERR_INVALID_POINTER);
536 LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, ppMessage=%p\n",
537 pConnection, pszUdi, cProps, papszKeys, papszValues, ppMessage));
538 int rc = VINF_SUCCESS;
539 bool halSuccess = true;
540 autoDBusError dbusError;
541 RTMemAutoPtr <DBusMessage, dbus_message_unref> message, reply;
542 DBusMessageIter iterGet, iterProps, iterKey, iterValue;
543
544 /* Initialise the return array to NULLs */
545 for (size_t i = 0; i < cProps; ++i)
546 papszValues[i] = NULL;
547 message = dbus_message_new_method_call ("org.freedesktop.Hal", pszUdi,
548 "org.freedesktop.Hal.Device",
549 "GetAllProperties");
550 if (!message)
551 rc = VERR_NO_MEMORY;
552 if (halSuccess && RT_SUCCESS (rc))
553 {
554 reply = dbus_connection_send_with_reply_and_block (pConnection,
555 message.get(), -1,
556 &dbusError.get());
557 if (!reply)
558 halSuccess = false;
559 }
560 if (halSuccess && RT_SUCCESS (rc))
561 {
562 dbus_message_iter_init (reply.get(), &iterGet);
563 if ( dbus_message_iter_get_arg_type (&iterGet) != DBUS_TYPE_ARRAY
564 && dbus_message_iter_get_element_type (&iterGet) != DBUS_TYPE_DICT_ENTRY)
565 halSuccess = false;
566 }
567 if (halSuccess && RT_SUCCESS (rc))
568 dbus_message_iter_recurse (&iterGet, &iterProps);
569 while ( halSuccess && RT_SUCCESS (rc)
570 && dbus_message_iter_get_arg_type (&iterProps)
571 == DBUS_TYPE_DICT_ENTRY)
572 {
573 const char *pszKey;
574 DBusMessageIter iterEntry, iterValue;
575 dbus_message_iter_recurse (&iterProps, &iterEntry);
576 dbus_message_iter_get_basic (&iterEntry, &pszKey);
577 dbus_message_iter_next (&iterEntry);
578 dbus_message_iter_recurse (&iterEntry, &iterValue);
579 for (size_t i = 0; i < cProps; ++i)
580 if (strcmp (pszKey, papszKeys[i]) == 0)
581 {
582 if (dbus_message_iter_get_arg_type (&iterValue) == DBUS_TYPE_STRING)
583 dbus_message_iter_get_basic (&iterValue, &papszValues[i]);
584 }
585 dbus_message_iter_next (&iterProps);
586 }
587 if (RT_SUCCESS (rc) && halSuccess)
588 *ppMessage = reply.release();
589 else
590 *ppMessage = NULL;
591 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
592 rc = VERR_NO_MEMORY;
593 LogFlowFunc (("rc=%Rrc, *ppMessage=%p\n", rc, *ppMessage));
594 dbusError.FlowLog();
595 return rc;
596}
597
598/**
599 * Helper function to query the hal subsystem for information about drives
600 * attached to the system.
601 * @returns iprt status code
602 * @param pList where to add information about the drives detected
603 * @param isDVD are we looking for DVDs or floppies?
604 * @param pfSuccess will be set to true if all interactions with hal
605 * succeeded and to false otherwise. Optional.
606 *
607 * @returns IPRT status code
608 */
609/* static */
610int getDriveInfoFromHal(DriveInfoList *pList, bool isDVD, bool *pfSuccess)
611{
612 AssertReturn(VALID_PTR (pList) && (pfSuccess == NULL || VALID_PTR (pfSuccess)),
613 VERR_INVALID_POINTER);
614 LogFlowFunc (("pList=%p, isDVD=%d, pfSuccess=%p\n", pList, isDVD, pfSuccess));
615 DBusConnection *pConnection;
616 autoDBusError dbusError;
617 DBusMessage *pReply;
618 RTMemAutoPtr <DBusMessage, dbus_message_unref> message, replyFind, replyGet;
619 DBusMessageIter iterFind, iterUdis;
620 bool halSuccess = true; /* Did something go wrong with hal or DBus? */
621 int rc = VINF_SUCCESS; /* Did a fatal error occur? */
622
623 rc = halInit (&pConnection);
624 RTMemAutoPtr <DBusConnection, dbus_connection_unref> dbusConnection;
625 dbusConnection = pConnection;
626 if (!dbusConnection)
627 halSuccess = false;
628 if (halSuccess && RT_SUCCESS (rc))
629 {
630 rc = halFindDeviceStringMatch (pConnection, "storage.drive_type",
631 isDVD ? "cdrom" : "floppy", &pReply);
632 replyFind = pReply;
633 if (!replyFind)
634 halSuccess = false;
635 }
636 if (halSuccess && RT_SUCCESS (rc))
637 {
638 dbus_message_iter_init (replyFind.get(), &iterFind);
639 if (dbus_message_iter_get_arg_type (&iterFind) != DBUS_TYPE_ARRAY)
640 halSuccess = false;
641 }
642 if (halSuccess && RT_SUCCESS (rc))
643 dbus_message_iter_recurse (&iterFind, &iterUdis);
644 for (; halSuccess && RT_SUCCESS (rc)
645 && dbus_message_iter_get_arg_type (&iterUdis) == DBUS_TYPE_STRING;
646 dbus_message_iter_next(&iterUdis))
647 {
648 /* Now get all properties from the iterator */
649 const char *pszUdi;
650 dbus_message_iter_get_basic (&iterUdis, &pszUdi);
651 static const char *papszKeys[] =
652 { "block.device", "info.product", "info.vendor" };
653 char *papszValues[RT_ELEMENTS (papszKeys)];
654 rc = halGetPropertyStrings (pConnection, pszUdi, RT_ELEMENTS (papszKeys),
655 papszKeys, papszValues, &pReply);
656 replyGet = pReply;
657 std::string description;
658 const char *pszDevice = papszValues[0], *pszProduct = papszValues[1],
659 *pszVendor = papszValues[2];
660 if (!!replyGet && pszDevice)
661 {
662 if ((pszVendor != NULL) && (pszVendor[0] != '\0'))
663 (description += pszVendor) += " ";
664 if ((pszProduct != NULL && pszProduct[0] != '\0'))
665 description += pszProduct;
666 pList->push_back (DriveInfo (pszDevice, pszUdi, description));
667 }
668 }
669 if (dbusError.HasName (DBUS_ERROR_NO_MEMORY))
670 rc = VERR_NO_MEMORY;
671 if (pfSuccess != NULL)
672 *pfSuccess = halSuccess;
673 LogFlow (("rc=%Rrc, halSuccess=%d\n", rc, halSuccess));
674 dbusError.FlowLog();
675 return rc;
676}
677#endif /* RT_OS_LINUX && VBOX_WITH_DBUS */
678
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette