in source/code/scxsystemlib/disk/staticphysicaldiskinstance.cpp [1564:2295]
void StaticPhysicalDiskInstance::Update()
{
static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eWarning, SCXCoreLib::eTrace);
/*
* In some cases, we must modify the device ID (m_device) that was
* passed to us by provider (for example, the provider never passes
* the raw device name, but we need that). Rather than changing the
* real device, and then potentially running into problems if the
* device ID doesn't match with the device ID from other sources,
* we make a copy of the device in m_rawDevice. Then we can change
* this, as needed, for various platforms.
*
* The m_rawDevice is for internal use only, and never shared via a
* Get() method.
*/
if (m_rawDevice.length() == 0)
{
m_rawDevice = m_device;
}
#if defined(linux)
// Open the device (Note: We must have privileges for this to work).
if (!m_deps->open(StrToUTF8(m_rawDevice).c_str(), O_RDONLY | O_NONBLOCK))
{
throw SCXErrnoOpenException(m_rawDevice, errno, SCXSRCLOCATION);
}
// Clear properties. It is important to clear all the properties here because when we collect data from the
// hardware we may do so only if property is not set already. So if all of the properties are not cleared here
// that may prevent the code from resetting the particular property with fresh data from the hardware.
Clear();
// For many properties we have two interfaces available: SCSI with SG_ ioctls and ATA with HDIO_ ioctls.
// Often ATA drives are also available through SCSI interface by using SCSI translation. The approach we use
// is to try any interface available for particular property and keep the best data we get. Determining the
// actual device type is not 100% reliable. Often ATA drives are named sdX instead of hdX. Also ATA drives
// may be exposed through SCSI interface and it seems that emulation flag may be inaccurate regardless of the
// translation. Considering all that the approach we take is to first the SCSI ioctls and decide it is SCSI drive
// unless ATA ioctls work as well. In that case we assume it is ATA drive and SCSI was just translation layer.
// If neither works we check the drive name to determine if it is a virtual drive.
// Be nice, see if we have SG_IO before using it. We can be nice because it appears that if SG_GET_VERSION_NUM
// fails, then SG_IO also always fails. If that changes then this if should be removed and functions using
// SG_IO should be called regardless of SG_GET_VERSION_NUM call.
int ver = 0;
if (m_deps->ioctl(SG_GET_VERSION_NUM, &ver) == 0 )
{
// We have SCSI ioctl working. However it might also be just ATA translation. We also have to check
// HDIO_ ioctls. For now we will assume it is SCSI drive.
m_intType = eDiskIfcSCSI;
// SG_IO is available only on versions 3.0 and above.
if(ver >= 30000)
{
// We have SG_IO.
unsigned char rsp_buff[255];
// Refer to "SCSI Primary Commands - 4" (SPC-4), chapter 6.4.1, available at www.t10.org/members/w_spc4.htm.
// Do standard INQUIRY, which is page code 0, EVPD 0. SqInq() function uses SG_IO.
if (SqInq(0, 0, rsp_buff, sizeof (rsp_buff)) == true)
{
// Byte 15:8 of Standard INQUIRY data is "T10 VENDOR IDENTIFICATION", we use it as manufacturer.
string manufacturer(reinterpret_cast<const char *>(rsp_buff) + 8, 8);
// Trim string to first 0.
manufacturer = manufacturer.c_str();
// Trim the whitespaces. It is necessary because if property is not available it may not be just.
// empty string but a string of 'space' characters.
m_manufacturer = StrTrim(StrFromUTF8(manufacturer));
// Treat PRODUCT REVISION LEVEL as firmware revision.
// PRODUCT REVISION LEVEL has 4 bytes, starting at byte 32.
string fwRev(reinterpret_cast<const char *>(rsp_buff) + 32, 4);
fwRev = fwRev.c_str();
m_Properties.firmwareRevision = StrTrim(StrFromUTF8(fwRev));
// Treat PRODUCT IDENTIFICATION as model.
// PRODUCT IDENTIFICATION has 16 bytes starting at byte 16 */
string model(reinterpret_cast<const char *>(rsp_buff) + 16, 16);
model = model.c_str();
m_model = StrTrim(StrFromUTF8(model));
// Find out if media is removable.
// RMB bit 7 byte 1 indicate removable or not.
if (filterbit<unsigned char>(rsp_buff[1], 7))
{
// Removable media other than floppy.
m_Properties.mediaType = mediaTypeNames[1];
m_Properties.capabilities[eDiskCapSupportsRemovableMedia] = eDiskCapSupportsRemovableMedia;
}
else
{
// Fixed hard disk media.
m_Properties.mediaType = mediaTypeNames[2];
}
}
// Refer to "SCSI Primary Commands - 4" (SPC-4), chapter 7.7.1, available at www.t10.org/members/w_spc4.htm.
// Page code 80h is to get Unit Serial Number, optional. SqInq() function uses SG_IO.
if (SqInq(0x80, 1, rsp_buff, sizeof(rsp_buff)))
{
string serialNumber(reinterpret_cast<const char *>(rsp_buff) + 4, rsp_buff[3]);
// Trim string to first 0.
serialNumber = serialNumber.c_str();
// Trim the whitespaces. It is necessary because if property is not available it may not be just
// empty string but a string of 'space' characters.
m_Properties.serialNumber = StrTrim(StrFromUTF8(serialNumber));
}
// Set the m_Properties.availability. Since this is our first attempt we do not have to check if this
// property is also set. Also, this is more advanced way of getting power state so we give it a priority.
// CheckSCSIPowerMode() function also uses SG_IO.
}
CheckSCSIPowerMode();
}
// Rest of the SCSI. Also update disk type to SCSI unless it is already set to SCSI in the previous code.
// We do not put this function inside SG_GET_VERSION_NUM block since SG_GET_VERSION_NUM is the upper SG layer
// of the SCSI functionality while UpdateSCSIAttributes() uses SCSI_IOCTL_ that is middle layer SCSI. It is
// unclear if SG_GET_VERSION_NUM can be used to check if SCSI_IOCTL_ is available. To be sure we decouple the two.
UpdateSCSIAttributes();
// Now be nice with HDIO_, first check if we have HDIO_ interface. We can be nice because it appears that if
// HDIO_GET_32BIT fails then other HDIO_ ioctl-s also fail. However if that changes then other HDIO_
// ioctl-s should be called regardless of HDIO_GET_32BIT. Note, even if HDIO_GET_32BIT succeeds other
// HDIO_ ioctl-s like HDIO_GET_IDENTITY may still sometimes fail.
int io32bit = 0;
if (m_deps->ioctl(HDIO_GET_32BIT, &io32bit) == 0)
{
// We have HDIO_ ioctl. It is most likely ATA drive regardless of SCSI test that happened before since SCSI
// could be only translation layer. It seems that SCSI is not available through HDIO_ ioctls (usually and
// for now).
m_intType = eDiskIfcIDE;
struct hd_driveid hdid;
memset(&hdid, 0, sizeof(hdid));
if (m_deps->ioctl(HDIO_GET_IDENTITY, &hdid) == 0)
{
string serialNumberHDIO(reinterpret_cast<char*>(hdid.serial_no), sizeof(hdid.serial_no));
// Trim string to first 0.
serialNumberHDIO = serialNumberHDIO.c_str();
// Trim the whitespaces. It is necessary because if property is not available it may not be just
// empty string but a string of 'space' characters.
wstring serialNumber = StrTrim(StrFromUTF8(serialNumberHDIO));
// Check if we have a better serial number. Sometimes one set of ioctl-s gives less info than the other
// so we will usually go by size when determining what data is better.
if (serialNumber.size() > m_Properties.serialNumber.size())
{
m_Properties.serialNumber = serialNumber;
}
// Try to get firmware revision.
string fwRevHDIO(reinterpret_cast<char*>(hdid.fw_rev), sizeof(hdid.fw_rev));
fwRevHDIO = fwRevHDIO.c_str();
wstring fwRev = StrTrim(StrFromUTF8(fwRevHDIO));
if (fwRev.size() > m_Properties.firmwareRevision.size())
{
m_Properties.firmwareRevision = fwRev;
}
// Try to get model name.
string modelHDIO(reinterpret_cast<char*>(hdid.model), sizeof(hdid.model));
modelHDIO = modelHDIO.c_str();
wstring model = StrTrim(StrFromUTF8(modelHDIO));
if (model.size() > m_model.size())
{
m_model = model;
}
// Get the power management capabilities. NOTE: right now we do not get power management caps by
// using SCSI interface, however if at some point latter we do implement that we will have to
// decide what data to use, SCSI or IDE. Right now we simply set power management using IDE if data is
// available from HDIO_GET_IDENTITY.
// First check if power management is supported.
// If bit 3 of word 82 is set to one, the Power Management feature set is supported.
m_Properties.powermanagementSupported = filterbit<unsigned short>(hdid.command_set_1, 3);
// Collect check power management capabilities.
if (!m_Properties.powermanagementSupported)
{
m_Properties.powerManagementCapabilities.push_back(eNotSupported);
}
else
{
// Word 85 bit 3, 1 = Power Management feature set enabled.
if (filterbit<unsigned short>(hdid.cfs_enable_1, 3))
{
m_Properties.powerManagementCapabilities.push_back(eEnabled);
}
else
{
m_Properties.powerManagementCapabilities.push_back(eDisabled);
}
// If bit 5 of word 86 is set to one, the Power-Up In Standby feature set has been enabled via the
// SET FEATURES command.
if(filterbit<unsigned short>(hdid.cfs_enable_2, 5))
{
m_Properties.powerManagementCapabilities.push_back(ePowerSavingModesEnteredAutomatically);
}
}
// Find out if media is removable. We give priority to SCSI INQUIRE command, so we will update this
// property only if it was not done already.
if(m_Properties.mediaType == mediaTypeNames[3])
{
// Media type is "Format is unknown" which means it was not already set by SCSI.
if (filterbit<unsigned short>(hdid.config, 7))
{
m_Properties.mediaType = mediaTypeNames[1];
m_Properties.capabilities[eDiskCapSupportsRemovableMedia] = eDiskCapSupportsRemovableMedia;
}
else
{
m_Properties.mediaType = mediaTypeNames[2];
}
}
}
else
{
std::wstringstream out;
out << L"On device \"" << m_device << L"\" ioctl(HDIO_GET_32BIT) succeeded but "
L"ioctl(HDIO_GET_IDENTITY) failed with errno = " <<
StrFrom(errno) << L".";
SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
}
// See if availability property is already set. If it is then don't do anything because CheckSCSIPowerMode()
// has priority so we want to keep it if it succeeded. CheckSCSIPowerMode() has priority because it is done
// by using SCSI INQUIRE command which seems to be more advanced. Also, if CheckATAPowerMode() fails it
// resets the availability to eDiskAvaUnknown so we lose data if it is already set by CheckSCSIPowerMode().
if (m_Properties.availability == eDiskAvaUnknown)
{
// OK, availability is not already set, set it now.
CheckATAPowerMode();
}
}
// We tried ioctl's. If we still don't have the disk type then try to determine from the disk name.
// Determining ATA or SCSI from name is unreliable and there is a trend to have all disks named sdX.
// We try to determine only if drive is virtual.
if (m_intType == eDiskIfcUnknown)
{
if (GetId().substr(0, 3) == L"vxd")
{
m_intType = eDiskIfcVirtual;
}
}
// Determine remaining properties.
if (!m_cdDrive)
{
// Not CD or DVD, get geometry.
DiskSizeAndGeometryFromKernel();
}
CheckSupportWriting();
UpdateDiskSignature();
ParsePartitions();
// Not all the code paths detect power management capabilities. For example SCSI or virtual drives are not checked
// for this property. In the case there are no power management capabilities, powermanagementSupported must contain
// eNotSupported.
if (m_Properties.powerManagementCapabilities.empty())
{
m_Properties.powerManagementCapabilities.push_back(eNotSupported);
}
// Close the handle to the drive.
if (0 != m_deps->close())
{
// Can't imagine that we can't close the fd, but if so, we don't want to miss that.
throw SCXErrnoException(L"close", errno, SCXSRCLOCATION);
}
#elif defined(aix)
int res;
/*
* On AIX, we use the ODM interface (Object Data Model). We query the
* ODM for various information that we need. The ODM is populated at
* boot time with the hardware that the system contains (plus a bunch
* of other stuff).
*/
std::wstring id = GetId();
size_t slashpos;
if ( (slashpos = id.rfind('/')) != std::wstring::npos )
{
id = id.substr(slashpos+1);
}
std::wstring criteria = L"name=" + id;
bool fIsVirtualDisk = false;
// Get the CuDv object to give us the interface type
// This also tells us if this is a virtual disk ...
//
// If it's a virtual disk, minimal information is avalable, so we do
// the best we can do and provide reasonable defaults for the rest.
struct CuDv dvData;
memset(&dvData, '\0', sizeof(dvData));
switch (LookupODM(CuDv_CLASS, criteria, &dvData))
{
case 0: /* Huh? Criteria failed??? We're broken ... */
throw SCXInternalErrorException(StrAppend(L"Invalid ODM (CuDv) criteria: ", criteria), SCXSRCLOCATION);
break;
case 1: /* Success case */
{
// The interface, found in PdDvLn_Lvalue, is of the form:
// <class>/<subclass>/<type>
// The <subclass> will be a string like "scsi", or "iscsi",
// or "ide" (perhaps on AIX for x86).
std::vector<wstring> parts;
StrTokenize(StrFromUTF8(dvData.PdDvLn_Lvalue), parts, L"/");
if (0 == StrCompare(parts[1], L"scsi", true)
|| 0 == StrCompare(parts[1], L"iscsi", true))
{
m_intType = eDiskIfcSCSI;
}
else if (0 == StrCompare(parts[1], L"ide", true))
{
m_intType = eDiskIfcIDE;
}
else if (0 == StrCompare(parts[1], L"vscsi", true))
{
m_intType = eDiskIfcSCSI;
fIsVirtualDisk = true;
}
else if (0 == StrCompare(parts[1], L"vide", true))
{
m_intType = eDiskIfcIDE;
fIsVirtualDisk = true;
}
else if (0 == StrCompare(parts[1], L"advm", true))
{
m_intType = eDiskIfcVirtual;
fIsVirtualDisk = true;
}
break;
}
default:
/* Ignore all other values (just case -1) */
break;
}
if ( ! fIsVirtualDisk )
{
// Get the VPD data, which gives us manufacturer and model
struct CuVPD vpdData;
memset(&vpdData, '\0', sizeof(vpdData));
switch (LookupODM(CuVPD_CLASS, criteria, &vpdData))
{
case 0: /* Huh? Criteria failed??? We're broken ... */
throw SCXInternalErrorException(L"Invalid ODM (CuVPD) criteria: " + criteria, SCXSRCLOCATION);
break;
case 1: /* Success case */
DecodeVPD(&vpdData);
break;
default:
/* Ignore all other values (just case -1) */
break;
}
// Next get the CuAt object, which gives us the size
// Note: On some devices, this isn't available ...
wstring attrCriteria = criteria + L" and attribute=size_in_mb";
struct CuAt atData;
memset(&atData, '\0', sizeof(atData));
if (1 == LookupODM(CuAt_CLASS, attrCriteria, &atData))
{
m_sizeInBytes = atol(atData.value);
m_sizeInBytes *= 1024 * 1024; /* Get from MB to bytes */
}
}
else
{
// Note: CuAt is present for virtual disks but doesn't have the size_in_mb attribute.
// CuVPD isn't available at all for firtual disks (thus our defaults here)
m_manufacturer = L"IBM"; // Obviously
m_model = L"Virtual"; // Reasonabe value (sort of)
m_sizeInBytes = 0; // Not able to determinate
}
#elif defined(hpux)
/*
* Open the device (Note: we must have privileges for this to work)
*
* Note: We usually get a device like "/dev/disk/disk3". While we can open
* this device, the ioctl()'s we call won't work unless we have the raw device
* open.
*
* As a result, we bag the device we received and construct our own given the
* name of the device.
*/
if (m_rawDevice == m_device)
{ // Happens first time called
if (wstring::npos != m_rawDevice.find(L"/dsk/"))
{
m_rawDevice = SCXCoreLib::StrAppend(L"/dev/rdsk/", GetId());
}
else
{
m_rawDevice = SCXCoreLib::StrAppend(L"/dev/rdisk/", GetId());
}
}
if (!m_deps->open(StrToUTF8(m_rawDevice).c_str(), O_RDONLY))
{
throw SCXErrnoOpenException(m_rawDevice, errno, SCXSRCLOCATION);
}
/* Look up the disk manufacturer and model */
#if defined(hpux) && (PF_MAJOR==11) && (PF_MINOR<31)
//
// Need to use old-style structures for HP-UX 11i v2
//
struct inquiry_2 scsiData;
memset(&scsiData, 0, sizeof(scsiData));
if (0 == m_deps->ioctl(int(SIOC_INQUIRY), &scsiData))
{
/* We got space-filled strings in our structure - null terminate 'em */
char vendorID[sizeof(scsiData.vendor_id)+1], productID[sizeof(scsiData.product_id)+1];
memset(vendorID, '\0', sizeof(vendorID));
memset(productID, '\0', sizeof(productID));
memcpy(vendorID, scsiData.vendor_id, sizeof(vendorID)-1);
memcpy(productID, scsiData.product_id, sizeof(productID)-1);
m_manufacturer = StrTrim(StrFromUTF8(vendorID));
m_model = StrTrim(StrFromUTF8(productID));
}
else
{
SCX_LOGERROR(m_log, L"System error getting drive inquiry data, errno=" + StrFrom(errno));
}
/* Look up capacity, interface type, etc */
disk_describe_type diskDescr;
memset(&diskDescr, 0, sizeof(diskDescr));
if (0 == m_deps->ioctl(int(DIOC_DESCRIBE), &diskDescr))
{
/* Set SCSI if we know that's what we've got (20=SCSI) */
if (20 == diskDescr.intf_type)
{
m_intType = eDiskIfcSCSI;
}
/* Capacity and sector size */
m_sizeInBytes = static_cast<scxulong> (diskDescr.maxsva);
m_sectorSize = diskDescr.lgblksz;
if (0 == m_sectorSize)
{
/* Hmm, didn't get a sector size - let's make a reasonable guess */
m_sizeInBytes *= 512;
}
else
{
m_sizeInBytes *= m_sectorSize;
}
}
else
{
SCX_LOGERROR(m_log, L"System error getting drive description, errno=" + StrFrom(errno));
}
#else
inquiry_3_t scsiData;
memset(&scsiData, 0, sizeof(scsiData));
if (0 == m_deps->ioctl(int(SIOC_INQUIRY), &scsiData))
{
/* We got space-filled strings in our structure - null terminate 'em */
char vendorID[sizeof(scsiData.vendor_id)+1], productID[sizeof(scsiData.product_id)+1];
memset(vendorID, '\0', sizeof(vendorID));
memset(productID, '\0', sizeof(productID));
memcpy(vendorID, scsiData.vendor_id, sizeof(vendorID)-1);
memcpy(productID, scsiData.product_id, sizeof(productID)-1);
m_manufacturer = StrTrim(StrFromUTF8(vendorID));
m_model = StrTrim(StrFromUTF8(productID));
}
else
{
SCX_LOGERROR(m_log, L"System error getting drive inquiry data, errno=" + StrFrom(errno));
}
/* Look up capacity, interface type, etc */
disk_describe_type_ext_t diskDescr;
memset(&diskDescr, 0, sizeof(diskDescr));
if (0 == m_deps->ioctl(int(DIOC_DESCRIBE_EXT), &diskDescr))
{
/* Set SCSI if we know that's what we've got (20=SCSI) */
if (20 == diskDescr.intf_type)
{
m_intType = eDiskIfcSCSI;
}
/* Capacity and sector size */
m_sizeInBytes = static_cast<scxulong> (diskDescr.maxsva_high);
m_sizeInBytes = (m_sizeInBytes << 32) + diskDescr.maxsva_low;
m_sectorSize = diskDescr.lgblksz;
if (0 == m_sectorSize)
{
/* Hmm, didn't get a sector size - let's make a reasonable guess */
m_sizeInBytes *= 512;
}
else
{
m_sizeInBytes *= m_sectorSize;
}
}
else
{
SCX_LOGERROR(m_log, L"System error getting drive description, errno=" + StrFrom(errno));
}
#endif
/* Close the handle to the drive */
if (0 != m_deps->close())
{
/* Can't imagine that we can't close the device, but if so, we don't want to miss that */
throw SCXErrnoException(L"close", errno, SCXSRCLOCATION);
}
#elif defined(sun)
/*
* Open the device (Note: We must have privileges for this to work)
*
* Note: We usually get a device like "/dev/dsk/c0d0", but this won't
* work. We try once (just in case), but if that fails, we build our
* own path to look like: "/dev/rdsk/c0d0s0". If that fails too, then
* we just bag it.
*/
SCX_LOGHYSTERICAL(m_log, L"Update(): trying disk device " + m_rawDevice );
if (!m_deps->open((const char *)StrToUTF8(m_rawDevice).c_str(), (int)O_RDONLY))
{
/* Reconstruct the path from the name and try again */
/* Note that we need to check several slices if the disk does not use all of them. */
for (int i = 0; i<=15; ++i)
{
m_rawDevice = L"/dev/rdsk/" + GetId() + StrAppend(L"s", i);
SCX_LOGHYSTERICAL(m_log, L"Update(): re-trying disk device " + m_rawDevice );
if (!m_deps->open((const char *)StrToUTF8(m_rawDevice).c_str(), (int)O_RDONLY))
{
if ((EIO != errno && ENXIO != errno) || 15 <= i) // EIO _or_ ENXIO is received if the slice is not used.
{
throw SCXErrnoOpenException(m_rawDevice, errno, SCXSRCLOCATION);
}
}
else //the raw file has been opened
{
/*for raw device /dev/rdsk/cntndnsn
Where:
cn controller n
tn SCSI target id n (0-6)
dn SCSI LUN n (0-7 normally; some HBAs support LUNs to 15
or 32. See the specific manpage for details)
referece: http://www.s-gms.ms.edus.si/cgi-bin/man-cgi?sd+7D
*/
size_t pos = GetId().find_first_of('c');
if( pos != wstring::npos )
{
m_Properties.SCSIBus=StrToUInt(GetId().substr(pos+1,1));
}
pos = GetId().find_first_of('t');
if( pos != wstring::npos )
{
m_Properties.SCSITargetId=StrToUInt(GetId().substr(pos+1,1));
}
pos = GetId().find_first_of('d');
if( pos != wstring::npos )
{
m_Properties.SCSILogicalUnit=StrToUInt(GetId().substr(pos+1,1));
}
break;
}
}
}
SCX_LOGHYSTERICAL(m_log, L"Update(): opened disk device " + m_rawDevice );
/*
Look up the size of the disk.
We also use this call to determine if this is a disk at all. On Sun,
we get called for all sorts of devices that may not be hard drives at
all ...
*/
struct dk_minfo dkmedia;
memset(&dkmedia, '\0', sizeof(dkmedia));
if (0 == m_deps->ioctl(int(DKIOCGMEDIAINFO), &dkmedia))
{
m_sizeInBytes = static_cast<scxulong> (dkmedia.dki_capacity) * dkmedia.dki_lbsize;
// verify that media is supported
if ( dkmedia.dki_media_type != DK_FIXED_DISK ){
// close the descriptor - strange, but we don't use helper class
// with 'close-in-dtor' here
m_deps->close();
// this exception means that disk is not of interest (CD, tape, etc)
throw SCXNotSupportedException(m_rawDevice + L" has unsupported type " + StrFrom(dkmedia.dki_media_type)
, SCXSRCLOCATION);
}
else //the device is fixed disk
{
//For fixed disk drives, MediaLoaded will always be TRUE
m_Properties.mediaLoaded=true;
//"Fixed hard disk media"
m_Properties.mediaType=mediaTypeNames[2];
}
}
else
{
std::wstringstream out;
out << L"On device \"" << m_device << L"\" ioctl(DKIOCGMEDIAINFO) failed with errno = " <<
StrFrom(errno) << L".";
SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
}
/* Look up the drive interface type */
struct dk_cinfo dkinfo;
memset(&dkinfo, '\0', sizeof(dkinfo));
if (0 == m_deps->ioctl(int(DKIOCINFO), &dkinfo))
{
switch (dkinfo.dki_ctype)
{
case DKC_DIRECT:
m_intType = eDiskIfcIDE;
break;
case DKC_SCSI_CCS:
m_intType = eDiskIfcSCSI;
break;
}
}
else
{
SCX_LOGTRACE(m_log, L"System error getting disk interface information, errno=" + StrFrom(errno));
}
/* Look up the drive's sector size */
struct vtoc dkvtoc;
memset(&dkvtoc, '\0', sizeof(dkvtoc));
if (0 == m_deps->ioctl(int(DKIOCGVTOC), &dkvtoc))
{
m_sectorSize = dkvtoc.v_sectorsz;
//m_Properties.partitions=dkvtoc.v_nparts;
int validPartitionNumber=0;
for(int i=0;i<dkvtoc.v_nparts;i++)
{
if(dkvtoc.v_part[i].p_tag>0)
{
validPartitionNumber++;
}
}
m_Properties.partitions = validPartitionNumber;
}
else
{
std::wstringstream out;
out << L"On device \"" << m_device << L"\" ioctl(DKIOCGVTOC) failed with errno = " <<
StrFrom(errno) << L".";
SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
}
/* Look up drive geometry information */
struct dk_geom dkgeom;
memset(&dkgeom, '\0', sizeof(dkgeom));
if (0 == m_deps->ioctl(int(DKIOCGGEOM), &dkgeom))
{
m_totalCylinders = dkgeom.dkg_pcyl;
m_totalHeads = dkgeom.dkg_nhead;
//on http://wwwcgi.rdg.ac.uk:8081/cgi-bin/cgiwrap/wsi14/poplog/man/7I/dkio,
//dkg_nsect means /* # of sectors per track*/
m_Properties.sectorsPerTrack = dkgeom.dkg_nsect;
}
else
{
std::wstringstream out;
out << L"On device \"" << m_device << L"\" ioctl(DKIOCGGEOM) failed with errno = " <<
StrFrom(errno) << L".";
SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
}
GetDiskGeometry(m_sizeInBytes, m_sectorSize, m_totalCylinders, m_totalHeads, m_Properties.sectorsPerTrack);
/* Close the handle to the drive */
if (0 != m_deps->close())
{
/* Can't imagine that we can't close the device, but if so, we don't want to miss that */
throw SCXErrnoException(L"close", errno, SCXSRCLOCATION);
}
#else
#error Implementation for Update() method not provided for platform
#endif
}