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
}