/**
       Discover physical disks.

       Logical disks are identified by the /etc/mnttab file (by design). Physical
       disks discovered will be those "hosting" the logical disks found. If ever
       seen in that file, the disk will be discovered. If the disk is removed it
       will be marked as offline.

       How to identify physical disks from logical disks:

       Linux --

       Logical disks are named things like /dev/hda0, /dev/hda1 and so on.
       The numeric value in the end of the name is the partition/logical ID
       of the physical disk. In the example above both logical disks are on
       physical disk /dev/hda.

       For LVM partitions on Linux have two entries for the same device.  An LVM
       device entry is stored in the /dev/mapper directory with a name in the form
       <logical-volume-group>-<logical-volume>.  There is also a device mapper (dm)
       device entry stored in the /dev directory in the form dm-<id>.  This is a
       1-to-1 relationship and the <id> is equal to the device minor ID that both
       device entries have in common.  Discovery of the physical device(s) that
       contain the LVM partition is done by mapping the LVM device to the dm device,
       then looking at the dm devices slave entries in Sysfs, and then finally
       performing the same conversion from a logical Linux partition name to a
       physical drive name that is done for all other partitions.

       Solaris --

       Logical disks are named things like /dev/dsk/c1t0d0s0, /dev/dsk/c1t0d0s1
       and so on. The last letter/numeric pair is the partition/logical ID
       of the physical disk. In the example above both logical disks are on
       physical disk /dev/dsk/c1t0d0.

       HPUX --

       Logical disks are logical volumes with names like /dev/vg00/lvol3.
       /dev/vg00 in the example name is the volume group name. Using the /etc/lvmtab
       file the volume group can be translated to a partition named /dev/disk/disk3_p2
       (or /dev/dsk/c2t0d0s2 using a naming standard deprecated as of HPUX 11.3). The
       old naming standard works like the one for solaris while the new one identifies
       the physical disk as /dev/disk/disk3 in the example above.

       AIX --

       TODO: Document how disks are enumerated on AIX.
    */
    void StatisticalPhysicalDiskEnumeration::FindPhysicalDisks()
    {
        for (EntityIterator iter=Begin(); iter!=End(); iter++)
        {
            SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance> disk = *iter;
            disk->m_online = false;
        }

        m_deps->RefreshMNTTab();
        for (std::vector<MntTabEntry>::const_iterator it = m_deps->GetMNTTab().begin();
             it != m_deps->GetMNTTab().end(); it++)
        {
            if ( ! m_deps->FileSystemIgnored(it->fileSystem) &&
                 ! m_deps->DeviceIgnored(it->device) &&
                 m_deps->LinkToPhysicalExists(it->fileSystem, it->device, it->mountPoint) )
            {
                std::map<std::wstring, std::wstring> devices = m_deps->GetPhysicalDevices(it->device);
                if (devices.size() == 0)
                {
                    static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eError, SCXCoreLib::eTrace);
                    std::wstringstream               out;

                    out << L"Unable to locate physical devices for: " << it->device;
                    SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
                    continue;
                }
                for (std::map<std::wstring, std::wstring>::const_iterator dev_it = devices.begin();
                     dev_it != devices.end(); dev_it++)
                {
                    SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance> disk = AddDiskInstance(dev_it->first, dev_it->second);
#if defined(hpux)
                    if (0 != disk)
                    {
                        if (m_pathToRdev.end() == m_pathToRdev.find(disk->m_device))
                        {
                            SCXCoreLib::SCXFilePath fp(disk->m_device);
                            fp.SetFilename(L"");
                            UpdatePathToRdev(fp.Get());
                        }
                        SCXASSERT(m_pathToRdev.end() != m_pathToRdev.find(disk->m_device));

                        scxlong diskInfoIndex = disk->FindDiskInfoByID(m_pathToRdev.find(disk->m_device)->second);
                        m_deps->AddDeviceInstance(disk->m_device, L"", diskInfoIndex, m_pathToRdev.find(disk->m_device)->second);
                    }
#endif
                }
            }
        }

#if defined(sun)
        this->UpdateSolarisHelper();
#endif

    }
    /**
       Update the enumeration.

       \param updateInstances If true (default) all instances will be updated.
                              Otherwise only the content of the enumeration will be updated.

    */
    void StaticPhysicalDiskEnumeration::Update(bool updateInstances/*=true*/)
    {
        for (EntityIterator iter=Begin(); iter!=End(); iter++)
        {
            SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk = *iter;
            disk->m_online = false;
        }

#if defined(linux)
        // First detect optical devices so later we can just skip the mount points which we determined are optical disks.
        // Various projects may or may not require optical drive detection. We check if iso9660 file system is to be
        // ignored to determine if optical drives should be detected.
        std::vector<std::wstring> drives;
        if ( ! m_deps->FileSystemIgnored(L"iso9660") )
        {
            // Get CD-ROM and DVD drives directly from the kernel interface in /proc.
            SCXCoreLib::SCXHandle<std::wistream> cdStrm = m_deps->GetWIStream("/proc/sys/dev/cdrom/info");
            std::vector<std::wstring> cdStrmLines;
            SCXCoreLib::SCXStream::NLFs nlfs;
            // /proc/sys/dev/cdrom/info format:
            // CD-ROM information, Id: cdrom.c 3.20 2003/12/17
            //
            // drive name:             sr0      hdc
            // drive speed:            0        0
            // drive # of slots:       1        1
            // ...
            SCXCoreLib::SCXStream::ReadAllLines(*cdStrm, cdStrmLines, nlfs);
            std::wstring lineID(L"drive name:");
            size_t i;
            for (i = 0; i < cdStrmLines.size(); i++)
            {
                if (cdStrmLines[i].substr(0, lineID.size()) == lineID)
                {
                    std::wstring drivesLine = cdStrmLines[i].substr(lineID.size(), std::wstring::npos);
                    SCXCoreLib::StrTokenize(drivesLine, drives, L" \t");
                    size_t d;
                    for (d = 0; d < drives.size(); d++)
                    {
                        AddDiskInstance(L"/dev/" + drives[d], L"/dev/" + drives[d], true);
                    }                
                    break;
                }
            }
        }
#endif

        m_deps->RefreshMNTTab();
        for (std::vector<MntTabEntry>::const_iterator it = m_deps->GetMNTTab().begin(); 
             it != m_deps->GetMNTTab().end(); it++)
        {
#if defined(linux)
            // It this is an optical device just skip it. We already processed it.
            size_t d;
            bool found = false;
            for (d = 0; d < drives.size(); d++)
            {
                if ((L"/dev/" + drives[d]) == it->device)
                {
                    found = true;
                    break;
                }
            }
            if (found)
            {
                continue;
            }
#endif
            if ( ! m_deps->FileSystemIgnored(it->fileSystem) &&
                 ! m_deps->DeviceIgnored(it->device) &&
                 m_deps->LinkToPhysicalExists(it->fileSystem, it->device, it->mountPoint) )
            {
                std::map<std::wstring, std::wstring> devices = m_deps->GetPhysicalDevices(it->device);
                if (devices.size() == 0)
                {
                    static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eError, SCXCoreLib::eTrace);
                    std::wstringstream                  out;

                    out << L"Unable to locate physical devices for: " << it->device;
                    SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
                    continue;
                }
                for (std::map<std::wstring, std::wstring>::const_iterator dev_it = devices.begin();
                     dev_it != devices.end(); dev_it++)
                {
                    SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk = AddDiskInstance(dev_it->first, dev_it->second);
                }
            }
        }
#if defined(sun)
        this->UpdateSolarisHelper();
#endif

        if (updateInstances)
        {
            UpdateInstances();
        }
    }