void StaticDiskPartitionEnumeration::Update()

in source/code/scxsystemlib/disk/staticdiskpartitionenumeration.cpp [92:465]


    void StaticDiskPartitionEnumeration::Update(bool updateInstances /*=true*/)
    {
        SCX_LOGTRACE(m_log, L"StaticDiskPartitionEnumeration Update() Entering . . .");
        if (!updateInstances)
        {
            return;
        }

#if defined(linux)

        /************* Start Linux ************************************/
        int                major     = 0;                  // major number of a partition
        int                minor     = 0;                  // minor number of a partition
        scxulong           blocks    = 0;                  // blocks of a partition
        vector<std::wstring>  allLines;                       // all lines read from partitions table
        std::wstring          partname;                       // name of the partition
        const std::wstring    dev_dir = L"/dev/";              // device directory
        std::map<std::wstring, std::wstring> partitions;
        std::string partedOutput;

        if (!GetPartedOutput(partedOutput) || !ParsePartedOutput(partedOutput, partitions))
        {
            // An error happened and was logged
            return;
        }

        SCXStream::NLFs nlfs;
        SCXFile::ReadAllLines(m_deps->LocateProcPartitions(), allLines, nlfs);

        // Let's read through line-by-line the /proc/partitions pseudo-file.
        for (vector<std::wstring>::iterator it = allLines.begin(); it != allLines.end(); it++)
        {
            std::wstring devPath;
            std::wistringstream is(*it);

            // Each line of /proc/partitions has four fields. Here's the header:
            //     major minor  #blocks  name
            if (is>>major>>minor>>blocks>>partname)
            {
                devPath = dev_dir + partname;
            }
            else
            {
                SCX_LOGINFO(m_log, L"This line in /proc/partitions doesn't contain Blocksize and Partition Name. line:" + is.str());
                continue;
            }

            //Partition names end in the partitionIndex, skip the 'dm-*' because those are device-mapped
            if (m_deps->FileExists(devPath) && isdigit(partname[partname.size()-1]) && (std::wstring::npos == partname.find(L"-"))) 
            {
                // Check existence first to prevent duplicate instances
                SCXCoreLib::SCXHandle<StaticDiskPartitionInstance> partit = GetInstance(partname);
                if (NULL == partit)
                {
                    partit = new StaticDiskPartitionInstance();
                }
                partit->SetId(partname);
                partit->m_deviceID = devPath;
                //Last chars of partition name is the index. Need to handle 1, 2 or 3 digits
                partit->m_index = SCXCoreLib::StrToUInt(partname.substr(partname.find_first_of(L"0123456789"))); 

                // Double check to make sure this DevicePath is also listed with parted
                if (partitions.find(devPath) != partitions.end())
                {
                    AddInstance(partit);
                    std::wstring detail = partitions.find(devPath)->second;
                    // Set whether this is a boot partition
                    partit->m_bootPartition = (detail.find(L"boot") != std::string::npos);
                }
                else
                {
                    SCX_LOGINFO(m_log, L"This partition is listed in /proc/partitions, but not in parted: Name: " + partname);
                    //delete partit;  Handle destructed when exiting this block
                }
            }

        } //EndFor
        /************* End Linux **************************************/

#elif defined(sun)
        static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eWarning, SCXCoreLib::eTrace);

        // Sun doesn't have /proc/partitions or /proc/mounts, so we need to handle it differently.
        const std::wstring dev_dsk_dir = L"/dev/dsk";              // device directory

        bool firstInstance = true;
        std::wstring bootp;
        // ZFS partition indices start after regular partitions are assigned their indices.
        size_t zfsFirstIndex = 0;

        m_deps->RefreshMNTTab();
        for (std::vector<MntTabEntry>::const_iterator it = m_deps->GetMNTTab().begin(); 
             it != m_deps->GetMNTTab().end(); it++)
        {
            SCX_LOGTRACE(m_log, L"DPEnum::Update():: Inside FOR loop, Device=" + it->device + L"  And file=" + it->fileSystem + L"  MountPt=" + it->mountPoint);

            if (! m_deps->FileSystemIgnored(it->fileSystem) && ! m_deps->DeviceIgnored(it->device) &&
                (std::wstring::npos != (it->device).find(dev_dsk_dir)))
            {

                SCXCoreLib::SCXHandle<StaticDiskPartitionInstance> partit = GetInstance(it->device);
                if (0 == partit)
                {
                    partit = new StaticDiskPartitionInstance();
                    std::wstring devPath(it->device);
                    std::wstring partname = devPath.substr(devPath.find_last_of(L"/")+1);

                    partit->SetId(partname);
                    partit->m_deviceID = devPath;
                    //Last char of partition name is the index.
                    partit->m_index = 
                    SCXCoreLib::StrToUInt(partname.substr(partname.find_last_of(L"0123456789")));
                    if ((partit->m_index + 1) > zfsFirstIndex)
                    {
                        // ZFS partition indices start after last regular partition index.
                        zfsFirstIndex = partit->m_index + 1;
                    }

                    //Getting the bootdrive is expensive, let's just do it once. 
                    if (firstInstance)
                    {
                        if (partit->GetBootDrivePath(bootp))
                        {
                            firstInstance = false;
                        }
                    }

                    if (devPath == bootp)
                    {
                        partit->m_bootPartition = true;
                    }
                    else
                    {
                        partit->m_bootPartition = false;
                    }                   

                    AddInstance(partit);

                }
            }
            else if (SCXCoreLib::StrToLower(it->fileSystem) == L"zfs")
            {
                // It is ZFS partition.
                SCXCoreLib::SCXHandle<StaticDiskPartitionInstance> partit = GetInstance(it->device);
                if (NULL == partit)
                {
                    partit = new StaticDiskPartitionInstance();
                    partit->m_isZfsPartition = true;
                    std::wstring zfsPath(it->device);
                    partit->SetId(zfsPath);
                    partit->m_deviceID = zfsPath;
                    // Get filesystem info.
                    struct statvfs64 stat;
                    memset(&stat, 0, sizeof(stat));
                    if (m_deps->statvfs64(SCXCoreLib::StrToUTF8(it->mountPoint).c_str(), &stat) == 0)
                    {
                        partit->m_blockSize = stat.f_frsize;
                        partit->m_numberOfBlocks = stat.f_blocks;
                        partit->m_partitionSize = partit->m_blockSize * partit->m_numberOfBlocks;
                    }
                    else
                    {
                        // Just log in case we can not get file system data.
                        std::wstring noStatvfs = L"Statvfs failed for mountpoint \"" +
                        it->mountPoint + L"\", errno = " + StrFrom(errno);
                        SCXCoreLib::SCXLogSeverity severity(suppressor.GetSeverity(noStatvfs));
                        SCX_LOG(m_log, severity, noStatvfs);
                    }
                    // ZFS boot process works in a way that first the active boot environment is determined. Then
                    // the OS installed in the root file system of that boot environment is loaded. Finally the the
                    // root file system is mounted at '/'. Therefore the file system with the mountpoint '/' represents
                    // the boot file system. If administrator mounts some other root file system at some other mount
                    // point, this file system will be returned in our list of disk partitions as well. However,
                    // although it is possible to boot from that root file system as well, it will not be marked as
                    // a bootable file system.
                    if (it->mountPoint == L"/")
                    {
                        partit->m_bootPartition = true;
                    }
                    else
                    {
                        partit->m_bootPartition = false;
                    }
                    AddInstance(partit);
                }
            }
        }
        // All regular partitions received their indices. Continue assigning indices to the ZFS partitions.
        size_t i;
        for (i = 0; i < Size(); i++)
        {
            SCXCoreLib::SCXHandle<StaticDiskPartitionInstance> partit = GetInstance(i);
            if (partit->m_isZfsPartition == true)
            {
                partit->m_index = zfsFirstIndex;
                zfsFirstIndex++;
            }
        }

#elif defined(aix)

        // We are mapping AIX logical volumes to the Windows concept of partitions, because AIX
        // has no direct equivalent to partitions.

        // Get mounted file systems first. We will need them as we go through all logical volumes.
        int ret = -1;
        std::vector<char> vm;
        // Get the size of the required buffer.
        int vmsz = 0;
        ret = m_deps->mntctl(MCTL_QUERY, sizeof(vmsz), (char*)&vmsz);
        if(ret != 0)
        {
            throw SCXErrnoException(
                L"mntctl failed trying to get required buffer size", errno, SCXSRCLOCATION);
        }
        vm.resize(vmsz);
        // Fill the buffer with mount points data.
        int mount_point_cnt = m_deps->mntctl(MCTL_QUERY, vm.size(), &vm[0]);
        if(mount_point_cnt == -1)
        {
            throw SCXErrnoException(L"mntctl failed trying to get mount points", errno, SCXSRCLOCATION);
        }

        // Now get all of the partitions.

        unsigned int partition_index = 0;
        
        // Get list of all volume groups.
        struct queryvgs *vgs = NULL;
        int ret_lvmvgs = m_deps->lvm_queryvgs(&vgs, NULL);
        if (ret_lvmvgs != 0)
        {
            throw SCXInternalErrorException(L"lvm_queryvgs failed with error code: " + StrFrom(ret_lvmvgs) +
                                            L".", SCXSRCLOCATION);
        }
        // Iterate through volume groups.
        for (long ivg = 0; ivg < vgs->num_vgs; ivg++)
        {
            // For each volume group get list of logical volumes.
            struct queryvg *vg = NULL;
            int ret_lvmvg = m_deps->lvm_queryvg(&vgs->vgs[ivg].vg_id, &vg, NULL);
            if (ret_lvmvg != 0)
            {
                throw SCXInternalErrorException(L"lvm_queryvg failed with error code: " + StrFrom(ret_lvmvg) +
                                                L".", SCXSRCLOCATION);
            }
            // Iterate through logical volumes.
            for (long ilv = 0; ilv < vg->num_lvs; ilv++)
            {
                // Get logical volume data. We use try catch so we don't crash just because
                // there was error getting data for one volume.
                try
                {
                    struct querylv *lv = NULL;
                    int ret_lvmlv = m_deps->lvm_querylv(&vg->lvs[ilv].lv_id, &lv, NULL);
                    if (ret_lvmlv != 0)
                    {
                        throw SCXInternalErrorException(L"lvm_querylv for logical volume \"" +
                                                        StrFromUTF8(vg->lvs[ilv].lvname) + L"\" failed with error code: " +
                                                        StrFrom(ret_lvmlv) + L".", SCXSRCLOCATION);
                    }
                    ProcessOneDiskPartition(vm, mount_point_cnt, lv->lvname, 
                                            static_cast<scxlong>(lv->currentsize) << lv->ppsize, partition_index);
                }
                catch(SCXCoreLib::SCXException& e)
                {
                    SCX_LOGERROR(m_log, e.What() + L" " + e.Where());
                }
            }
        }        
#elif defined(hpux)
        vector<SCXLogicalVolumes> logVol;
        bool bootLvFound = false;
        size_t fullBootLvIndex = 0;
        GetLogicalVolumesBoot(logVol, bootLvFound, fullBootLvIndex);
        size_t i;
        for(i = 0; i<logVol.size(); i++)
        {
            SCXCoreLib::SCXHandle<StaticDiskPartitionInstance> partition_instance = GetInstance(logVol[i].name);
            if (NULL == partition_instance)
            {
                partition_instance = new StaticDiskPartitionInstance();
                partition_instance->SetId(logVol[i].name);
                partition_instance->m_deviceID = logVol[i].name;
                partition_instance->m_index = i;

                if(logVol[i].mntDir.size() != 0)
                {
                    // We have a mount point for this logical volume. Get info about the file system.
                    struct statvfs64 stat;
                    memset(&stat, 0, sizeof(stat));
                    int r = m_deps->statvfs(StrToUTF8(logVol[i].mntDir).c_str(), &stat);
                    if(r != 0)
                    {
                        wstring msg = L"statvfs() failed for mountpoint \"" + logVol[i].mntDir + L"\".";
                        SCX_LOGERROR(m_log, msg);
                    }
                    // Now we have all file system data. Update the disk partition instance.
                    scxulong partition_size =
                    static_cast<scxulong>(stat.f_frsize) * static_cast<scxulong>(stat.f_blocks);

                    partition_instance->m_blockSize = stat.f_frsize;
                    partition_instance->m_numberOfBlocks = stat.f_blocks;
                    partition_instance->m_partitionSize = partition_size;
                }
                else
                {
                    // No mount point. Get the size by other means. We use try catch so we don't crash just because
                    // there was error getting one datafield for one volume.
                    try
                    {
                        // Before calling ioctl verify that name matches logical volume name. We expect name in format:
                        // "/def/some_vg_name/some_lv_name"
                        SCXRegex regEx(L"(^/dev/[^/]+/[^/]+$)");
                        vector<std::wstring> matches;
                        if (!regEx.ReturnMatch(logVol[i].name, matches, 0))
                        {
                            if (!matches[0].empty())
                            {
                                wstring msg = L"Error encountered when trying to verify device name \"" + logVol[i].name +
                                L"\". " + matches[0];
                                throw SCXInternalErrorException(msg, SCXSRCLOCATION);
                            }
                            else
                            {
                                wstring msg = L"Device name \"" + logVol[i].name + L"\" is invalid.";
                                throw SCXInternalErrorException(msg, SCXSRCLOCATION);
                            }
                        }
                        // Name matches, make raw device name.
                        wstring rname = logVol[i].name;
                        size_t namePos = rname.rfind(L'/');
                        if (namePos == wstring::npos)
                        {
                            wstring msg = L"Device name \"" + rname + L"\" missing full path.";
                            throw SCXErrnoException(msg, errno, SCXSRCLOCATION);
                        }
                        rname.insert(namePos + 1, L"r");
                        // Open the device file, call ioctl(DIOC_CAPACITY), set the size value and close the device file.
                        int fd = m_deps->_open(StrToUTF8(rname).c_str(), O_RDONLY);
                        if (fd == -1)
                        {
                            wstring msg = L"open(O_RDONLY) failed for device \"" + rname + L"\".";
                            throw SCXErrnoException(msg, errno, SCXSRCLOCATION);
                        }
                        capacity_type ct;
                        memset(&ct, 0, sizeof(ct));
                        int ret = m_deps->_ioctl(fd, DIOC_CAPACITY, &ct);
                        if (ret == -1)
                        {
                            wstring msg = L"ioctl(DIOC_CAPACITY) failed for device \"" + rname + L"\".";
                            throw SCXErrnoException(msg, errno, SCXSRCLOCATION);
                        }
                        partition_instance->m_partitionSize = ct.lba * DEV_BSIZE;
                        if (m_deps->_close(fd) != 0)
                        {
                            wstring msg = L"close() failed for device \"" + rname + L"\".";
                            throw SCXErrnoException(msg, errno, SCXSRCLOCATION);
                        }
                    }
                    catch(SCXCoreLib::SCXException& e)
                    {
                        SCX_LOGERROR(m_log, e.What() + L" " + e.Where());
                    }
                }
                if(bootLvFound && fullBootLvIndex == i)
                {
                    partition_instance->m_bootPartition = true;
                }
                AddInstance(partition_instance);
            }
        }
#endif
    }