HostHardwareFreeBSD.cpp revision 5979821e2c16d1fcec5b9a3ef64e13246fc9a93a
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/* $Id$ */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/** @file
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Classes for handling hardware detection under FreeBSD.
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/*
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Copyright (C) 2008-2013 Oracle Corporation
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync *
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * available from http://www.virtualbox.org. This file is free software;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * General Public License (GPL) as published by the Free Software
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#define LOG_GROUP LOG_GROUP_MAIN
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/*******************************************************************************
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync* Header Files *
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync*******************************************************************************/
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
2d97f8baccdd684bc0a8a15eb86bbe9ff2b85374vboxsync#include <HostHardwareLinux.h>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
866306ba031a2f258907507dd4abb3b84b6983e7vboxsync#include <VBox/log.h>
866306ba031a2f258907507dd4abb3b84b6983e7vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#include <iprt/dir.h>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#include <iprt/env.h>
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync#include <iprt/file.h>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#include <iprt/mem.h>
0593edaa1761266cd29c8534b4090646737d3c99vboxsync#include <iprt/param.h>
0593edaa1761266cd29c8534b4090646737d3c99vboxsync#include <iprt/path.h>
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync#include <iprt/string.h>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync#ifdef RT_OS_FREEBSD
bb4f31aac6155757fe15ef9fe0bf843ed9a14441vboxsync# include <sys/param.h>
bb4f31aac6155757fe15ef9fe0bf843ed9a14441vboxsync# include <sys/types.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <sys/stat.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <unistd.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <stdio.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <sys/ioctl.h>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync# include <fcntl.h>
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync# include <cam/cam.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <cam/cam_ccb.h>
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync# include <cam/scsi/scsi_pass.h>
3238841f4d74fd0e37778c270ae81b177a98e21bvboxsync#endif /* RT_OS_FREEBSD */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync#include <vector>
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/******************************************************************************
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync* Typedefs and Defines *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync******************************************************************************/
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsyncstatic int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync bool isDVD, bool *pfSuccess);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsyncstatic int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/** Find the length of a string, ignoring trailing non-ascii or control
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync * characters */
abb14a9d49aa819cc2296b1daf7c416118d39f1evboxsyncstatic size_t strLenStripped(const char *pcsz)
abb14a9d49aa819cc2296b1daf7c416118d39f1evboxsync{
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync size_t cch = 0;
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync for (size_t i = 0; pcsz[i] != '\0'; ++i)
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync if (pcsz[i] > 32 && pcsz[i] < 127)
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync cch = i;
0d9f0399d4356c471af5e68c30b51c73f7909487vboxsync return cch + 1;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync}
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic void strLenRemoveTrailingWhiteSpace(char *psz, size_t cchStr)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync{
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync while ( (cchStr > 0)
d89903d4817e25634b9f9e877e1c54bb83886115vboxsync && (psz[cchStr -1] == ' '))
9d58ed91e29fc16c33e0e8f0530a1b8c58b98462vboxsync psz[--cchStr] = '\0';
9d58ed91e29fc16c33e0e8f0530a1b8c58b98462vboxsync}
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/**
890b5e4f0265eb78919f6a41d1ccaa89eba51768vboxsync * Initialise the device description for a DVD drive based on
d3b1e232c566c55799a7bfc83f66b045c4d82657vboxsync * vendor and model name strings.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @param pcszVendor the vendor ID string
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @param pcszModel the product ID string
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @param pszDesc where to store the description string (optional)
d645696bf70e804f18f661a9b1b8b79c32a1b331vboxsync * @param cchDesc the size of the buffer in @pszDesc
dccbbd8ec5b45b567312112e7edd5c7130d56262vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/* static */
d645696bf70e804f18f661a9b1b8b79c32a1b331vboxsyncvoid dvdCreateDeviceString(const char *pcszVendor, const char *pcszModel,
3f72ab7ee9d1539bfa4ed19972430194627b9273vboxsync char *pszDesc, size_t cchDesc)
3f72ab7ee9d1539bfa4ed19972430194627b9273vboxsync{
3f72ab7ee9d1539bfa4ed19972430194627b9273vboxsync AssertPtrReturnVoid(pcszVendor);
3f72ab7ee9d1539bfa4ed19972430194627b9273vboxsync AssertPtrReturnVoid(pcszModel);
a99c525910b735565952ae4e13e8bed173255d40vboxsync AssertPtrNullReturnVoid(pszDesc);
a99c525910b735565952ae4e13e8bed173255d40vboxsync AssertReturnVoid(!pszDesc || cchDesc > 0);
a99c525910b735565952ae4e13e8bed173255d40vboxsync size_t cchVendor = strLenStripped(pcszVendor);
a99c525910b735565952ae4e13e8bed173255d40vboxsync size_t cchModel = strLenStripped(pcszModel);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
f92fba8b6d97160b7c58689eff6c3848702bd7bavboxsync /* Construct the description string as "Vendor Product" */
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync if (pszDesc)
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync {
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync if (cchVendor > 0)
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync RTStrPrintf(pszDesc, cchDesc, "%.*s %s", cchVendor, pcszVendor,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync cchModel > 0 ? pcszModel : "(unknown drive model)");
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync else
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RTStrPrintf(pszDesc, cchDesc, "%s", pcszModel);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync }
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync}
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncint VBoxMainDriveInfo::updateDVDs ()
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync{
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync LogFlowThisFunc(("entered\n"));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync int rc = VINF_SUCCESS;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync bool fSuccess = false; /* Have we succeeded in finding anything yet? */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync try
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync mDVDList.clear ();
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync /* Always allow the user to override our auto-detection using an
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * environment variable. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (RT_SUCCESS(rc) && !fSuccess)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync rc = getDriveInfoFromEnv("VBOX_CDROM", &mDVDList, true /* isDVD */,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync &fSuccess);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (RT_SUCCESS(rc) && !fSuccess)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync rc = getDVDInfoFromCAM(&mDVDList, &fSuccess);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync }
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync catch(std::bad_alloc &e)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync rc = VERR_NO_MEMORY;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync }
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync LogFlowThisFunc(("rc=%Rrc\n", rc));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync return rc;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync}
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
df3a016ea59e69ab2758221fd91e62a9782b144evboxsyncint VBoxMainDriveInfo::updateFloppies ()
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync{
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync LogFlowThisFunc(("entered\n"));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync int rc = VINF_SUCCESS;
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync bool fSuccess = false; /* Have we succeeded in finding anything yet? */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync try
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync mFloppyList.clear ();
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* Always allow the user to override our auto-detection using an
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * environment variable. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (RT_SUCCESS(rc) && !fSuccess)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync rc = getDriveInfoFromEnv("VBOX_FLOPPY", &mFloppyList, false /* isDVD */,
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync &fSuccess);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync }
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync catch(std::bad_alloc &e)
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync {
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync rc = VERR_NO_MEMORY;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync }
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync LogFlowThisFunc(("rc=%Rrc\n", rc));
73a750ff6ce8ed53244049d291856a1eea296654vboxsync return rc;
73a750ff6ce8ed53244049d291856a1eea296654vboxsync}
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync/**
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Search for available CD/DVD drives using the CAM layer.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync *
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns iprt status code
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pList the list to append the drives found to
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pfSuccess this will be set to true if we found at least one drive
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * and to false otherwise. Optional.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync{
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync int rc = VINF_SUCCESS;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync RTFILE FileXpt;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync rc = RTFileOpen(&FileXpt, "/dev/xpt0", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync if (RT_SUCCESS(rc))
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync {
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync union ccb DeviceCCB;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct dev_match_pattern DeviceMatchPattern;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct dev_match_result *paMatches = NULL;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RT_ZERO(DeviceCCB);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RT_ZERO(DeviceMatchPattern);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* We want to get all devices. */
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync DeviceCCB.ccb_h.func_code = XPT_DEV_MATCH;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.ccb_h.path_id = CAM_XPT_PATH_ID;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.ccb_h.target_id = CAM_TARGET_WILDCARD;
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync DeviceCCB.ccb_h.target_lun = CAM_LUN_WILDCARD;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* Setup the pattern */
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync DeviceMatchPattern.type = DEV_MATCH_DEVICE;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync DeviceMatchPattern.pattern.device_pattern.path_id = CAM_XPT_PATH_ID;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync DeviceMatchPattern.pattern.device_pattern.target_id = CAM_TARGET_WILDCARD;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync DeviceMatchPattern.pattern.device_pattern.target_lun = CAM_LUN_WILDCARD;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync DeviceMatchPattern.pattern.device_pattern.flags = DEV_MATCH_INQUIRY;
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync#if __FreeBSD_version >= 900000
060664c5bfb70021bf92e01127d02b178b8c20acvboxsync# define INQ_PAT data.inq_pat
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#else
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync #define INQ_PAT inq_pat
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#endif
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceMatchPattern.pattern.device_pattern.INQ_PAT.type = T_CDROM;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceMatchPattern.pattern.device_pattern.INQ_PAT.media_type = SIP_MEDIA_REMOVABLE | SIP_MEDIA_FIXED;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceMatchPattern.pattern.device_pattern.INQ_PAT.vendor[0] = '*'; /* Matches anything */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceMatchPattern.pattern.device_pattern.INQ_PAT.product[0] = '*'; /* Matches anything */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceMatchPattern.pattern.device_pattern.INQ_PAT.revision[0] = '*'; /* Matches anything */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync#undef INQ_PAT
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.cdm.num_patterns = 1;
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync DeviceCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.cdm.patterns = &DeviceMatchPattern;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync /*
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * Allocate the buffer holding the matches.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * We will allocate for 10 results and call
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * CAM multiple times if we have more results.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync paMatches = (struct dev_match_result *)RTMemAllocZ(10 * sizeof(struct dev_match_result));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (paMatches)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.cdm.num_matches = 0;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.cdm.match_buf_len = 10 * sizeof(struct dev_match_result);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync DeviceCCB.cdm.matches = paMatches;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
83204c5c9e83c7825a8e0537821a199459b783c8vboxsync do
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &DeviceCCB, sizeof(union ccb), NULL);
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync if (RT_FAILURE(rc))
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync Log(("Error while querying available CD/DVD devices rc=%Rrc\n", rc));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync break;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync }
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync for (unsigned i = 0; i < DeviceCCB.cdm.num_matches; i++)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (paMatches[i].type == DEV_MATCH_DEVICE)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* We have the drive now but need the appropriate device node */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct device_match_result *pDevResult = &paMatches[i].result.device_result;
df3a016ea59e69ab2758221fd91e62a9782b144evboxsync union ccb PeriphCCB;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct dev_match_pattern PeriphMatchPattern;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct dev_match_result aPeriphMatches[2];
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync struct periph_match_result *pPeriphResult = NULL;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync unsigned iPeriphMatch = 0;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RT_ZERO(PeriphCCB);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RT_ZERO(PeriphMatchPattern);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync RT_ZERO(aPeriphMatches);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* This time we only want the specific nodes for the device. */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.ccb_h.func_code = XPT_DEV_MATCH;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.ccb_h.path_id = paMatches[i].result.device_result.path_id;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.ccb_h.target_id = paMatches[i].result.device_result.target_id;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.ccb_h.target_lun = paMatches[i].result.device_result.target_lun;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync /* Setup the pattern */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphMatchPattern.type = DEV_MATCH_PERIPH;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphMatchPattern.pattern.periph_pattern.path_id = paMatches[i].result.device_result.path_id;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphMatchPattern.pattern.periph_pattern.target_id = paMatches[i].result.device_result.target_id;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphMatchPattern.pattern.periph_pattern.target_lun = paMatches[i].result.device_result.target_lun;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync PeriphMatchPattern.pattern.periph_pattern.flags = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET |
6a762861f4545ff60f0cb6e4d0a947793adc2f74vboxsync PERIPH_MATCH_LUN;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.cdm.num_patterns = 1;
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync PeriphCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync PeriphCCB.cdm.patterns = &PeriphMatchPattern;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync PeriphCCB.cdm.num_matches = 0;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync PeriphCCB.cdm.match_buf_len = sizeof(aPeriphMatches);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync PeriphCCB.cdm.matches = aPeriphMatches;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
7a6ba152515c963d275e7c1371ba39155ec6cf58vboxsync do
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
337640774b62333151a0c5cc6407afcb25d93a37vboxsync rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &PeriphCCB, sizeof(union ccb), NULL);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync if (RT_FAILURE(rc))
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync {
dccbbd8ec5b45b567312112e7edd5c7130d56262vboxsync Log(("Error while querying available periph devices rc=%Rrc\n", rc));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync break;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync }
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
41738f3838049e665b571d59d971cc5c74efb6dcvboxsync for (iPeriphMatch = 0; iPeriphMatch < PeriphCCB.cdm.num_matches; iPeriphMatch++)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync {
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync if ( (aPeriphMatches[iPeriphMatch].type == DEV_MATCH_PERIPH)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync && (!strcmp(aPeriphMatches[iPeriphMatch].result.periph_result.periph_name, "cd")))
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync {
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pPeriphResult = &aPeriphMatches[iPeriphMatch].result.periph_result;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync break; /* We found the periph device */
ae9f3922b0becc4f4b4fca43422314700a4ed8a7vboxsync }
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync }
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync if (iPeriphMatch < PeriphCCB.cdm.num_matches)
625f0ce802a913c7685bc8ae837583bea69ebf8avboxsync break;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync } while ( (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
d89903d4817e25634b9f9e877e1c54bb83886115vboxsync && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));
dfff275f489de72e78be4fb4fbc3a2780f0ee2aavboxsync
9d58ed91e29fc16c33e0e8f0530a1b8c58b98462vboxsync if (pPeriphResult)
dfff275f489de72e78be4fb4fbc3a2780f0ee2aavboxsync {
9d58ed91e29fc16c33e0e8f0530a1b8c58b98462vboxsync char szPath[RTPATH_MAX];
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync char szDesc[256];
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync
587f936a5f1c792ede2dcb60a7769780a3487c6fvboxsync RTStrPrintf(szPath, sizeof(szPath), "/dev/%s%d",
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pPeriphResult->periph_name, pPeriphResult->unit_number);
12bda05d421d110736c4d6127a36e9c438072dadvboxsync
12bda05d421d110736c4d6127a36e9c438072dadvboxsync /* Remove trailing white space. */
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.vendor,
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync sizeof(pDevResult->inq_data.vendor));
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.product,
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync sizeof(pDevResult->inq_data.product));
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync dvdCreateDeviceString(pDevResult->inq_data.vendor,
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pDevResult->inq_data.product,
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync szDesc, sizeof(szDesc));
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync pList->push_back(DriveInfo(szPath, "", szDesc));
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync if (pfSuccess)
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync *pfSuccess = true;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync }
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync }
ae9f3922b0becc4f4b4fca43422314700a4ed8a7vboxsync }
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync } while ( (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
ae9f3922b0becc4f4b4fca43422314700a4ed8a7vboxsync && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
de4903f1d13565a610af0e58c490a8fc9873e3e9vboxsync RTMemFree(paMatches);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync }
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync else
2f0e6b8d79026c7efad10a34945eb120097d7f54vboxsync rc = VERR_NO_MEMORY;
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync RTFileClose(FileXpt);
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync }
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
3238841f4d74fd0e37778c270ae81b177a98e21bvboxsync return rc;
3238841f4d74fd0e37778c270ae81b177a98e21bvboxsync}
ba00a478700c77b6b1435cd8a7e7cb64d84f8d93vboxsync
f92fba8b6d97160b7c58689eff6c3848702bd7bavboxsync/**
f92fba8b6d97160b7c58689eff6c3848702bd7bavboxsync * Extract the names of drives from an environment variable and add them to a
342d1c2e846281e0bcbde2e97218273216b3fb32vboxsync * list if they are valid.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @returns iprt status code
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * @param pcszVar the name of the environment variable. The variable
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * value should be a list of device node names, separated
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * by ':' characters.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync * @param pList the list to append the drives found to
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * @param isDVD are we looking for DVD drives or for floppies?
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * @param pfSuccess this will be set to true if we found at least one drive
9b5a120b694c2603a7a3dccbd6cc519164943b17vboxsync * and to false otherwise. Optional.
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync */
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsyncstatic int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync bool isDVD, bool *pfSuccess)
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync{
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync AssertPtrReturn(pcszVar, VERR_INVALID_POINTER);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync AssertPtrReturn(pList, VERR_INVALID_POINTER);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER);
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync LogFlowFunc(("pcszVar=%s, pList=%p, isDVD=%d, pfSuccess=%p\n", pcszVar,
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync pList, isDVD, pfSuccess));
9f4747a43944848d911353b1bcc99f41aaa5bf81vboxsync int rc = VINF_SUCCESS;
bool success = false;
char *pszFreeMe = RTEnvDupEx(RTENV_DEFAULT, pcszVar);
try
{
const char *pcszCurrent = pszFreeMe;
while (pcszCurrent && *pcszCurrent != '\0')
{
const char *pcszNext = strchr(pcszCurrent, ':');
char szPath[RTPATH_MAX], szReal[RTPATH_MAX];
char szDesc[256], szUdi[256];
if (pcszNext)
RTStrPrintf(szPath, sizeof(szPath), "%.*s",
pcszNext - pcszCurrent - 1, pcszCurrent);
else
RTStrPrintf(szPath, sizeof(szPath), "%s", pcszCurrent);
if (RT_SUCCESS(RTPathReal(szPath, szReal, sizeof(szReal))))
{
szUdi[0] = '\0'; /** @todo r=bird: missing a call to devValidateDevice() here and szUdi wasn't
* initialized because of that. Need proper fixing. */
pList->push_back(DriveInfo(szReal, szUdi, szDesc));
success = true;
}
pcszCurrent = pcszNext ? pcszNext + 1 : NULL;
}
if (pfSuccess != NULL)
*pfSuccess = success;
}
catch(std::bad_alloc &e)
{
rc = VERR_NO_MEMORY;
}
RTStrFree(pszFreeMe);
LogFlowFunc(("rc=%Rrc, success=%d\n", rc, success));
return rc;
}
#if 0
int VBoxMainUSBDeviceInfo::UpdateDevices ()
{
LogFlowThisFunc(("entered\n"));
int rc = VINF_SUCCESS;
bool success = false; /* Have we succeeded in finding anything yet? */
try
{
bool halSuccess = false;
mDeviceList.clear();
#if defined(RT_OS_LINUX)
#ifdef VBOX_WITH_DBUS
if ( RT_SUCCESS(rc)
&& RT_SUCCESS(RTDBusLoadLib())
&& (!success || testing()))
rc = getUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);
/* Try the old API if the new one *succeeded* as only one of them will
* pick up devices anyway. */
if (RT_SUCCESS(rc) && halSuccess && (!success || testing()))
rc = getOldUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);
if (!success)
success = halSuccess;
#endif /* VBOX_WITH_DBUS defined */
#endif /* RT_OS_LINUX */
}
catch(std::bad_alloc &e)
{
rc = VERR_NO_MEMORY;
}
LogFlowThisFunc(("rc=%Rrc\n", rc));
return rc;
}
struct VBoxMainHotplugWaiter::Context
{
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
/** The connection to DBus */
RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> mConnection;
/** Semaphore which is set when a device is hotplugged and reset when
* it is read. */
volatile bool mTriggered;
/** A flag to say that we wish to interrupt the current wait. */
volatile bool mInterrupt;
/** Constructor */
Context() : mTriggered(false), mInterrupt(false) {}
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
};
/* This constructor sets up a private connection to the DBus daemon, connects
* to the hal service and installs a filter which sets the mTriggered flag in
* the Context structure when a device (not necessarily USB) is added or
* removed. */
VBoxMainHotplugWaiter::VBoxMainHotplugWaiter ()
{
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
int rc = VINF_SUCCESS;
mContext = new Context;
if (RT_SUCCESS(RTDBusLoadLib()))
{
for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mContext->mConnection; ++i)
{
rc = halInitPrivate (&mContext->mConnection);
}
if (!mContext->mConnection)
rc = VERR_NOT_SUPPORTED;
DBusMessage *pMessage;
while ( RT_SUCCESS(rc)
&& (pMessage = dbus_connection_pop_message (mContext->mConnection.get())) != NULL)
dbus_message_unref (pMessage); /* empty the message queue. */
if ( RT_SUCCESS(rc)
&& !dbus_connection_add_filter (mContext->mConnection.get(),
dbusFilterFunction,
(void *) &mContext->mTriggered, NULL))
rc = VERR_NO_MEMORY;
if (RT_FAILURE(rc))
mContext->mConnection.reset();
}
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
}
/* Destructor */
VBoxMainHotplugWaiter::~VBoxMainHotplugWaiter ()
{
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
if (!!mContext->mConnection)
dbus_connection_remove_filter (mContext->mConnection.get(), dbusFilterFunction,
(void *) &mContext->mTriggered);
delete mContext;
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
}
/* Currently this is implemented using a timed out wait on our private DBus
* connection. Because the connection is private we don't have to worry about
* blocking other users. */
int VBoxMainHotplugWaiter::Wait(RTMSINTERVAL cMillies)
{
int rc = VINF_SUCCESS;
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
if (!mContext->mConnection)
rc = VERR_NOT_SUPPORTED;
bool connected = true;
mContext->mTriggered = false;
mContext->mInterrupt = false;
unsigned cRealMillies;
if (cMillies != RT_INDEFINITE_WAIT)
cRealMillies = cMillies;
else
cRealMillies = DBUS_POLL_TIMEOUT;
while ( RT_SUCCESS(rc) && connected && !mContext->mTriggered
&& !mContext->mInterrupt)
{
connected = dbus_connection_read_write_dispatch (mContext->mConnection.get(),
cRealMillies);
if (mContext->mInterrupt)
LogFlowFunc(("wait loop interrupted\n"));
if (cMillies != RT_INDEFINITE_WAIT)
mContext->mInterrupt = true;
}
if (!connected)
rc = VERR_TRY_AGAIN;
#else /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
rc = VERR_NOT_IMPLEMENTED;
#endif /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
return rc;
}
/* Set a flag to tell the Wait not to resume next time it times out. */
void VBoxMainHotplugWaiter::Interrupt()
{
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
LogFlowFunc(("\n"));
mContext->mInterrupt = true;
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
}
#endif