If your code was as bad as mine you wouldn't brag it around either,
you'd wait until you had something decent.
Here, see what you can make of this one, no telling what knode will
do with the tabs; see if it makes you hate me more, or less. I have lots
of code, but it's all in PHP. Now stfu please.
// need NOT be called as root, use sysfs to get list of all real (non-virtual) block
// devices currently present. returns false on failure, else an array whose
// index is the device name (sorted-ascending), and which contains the following:
//
// $result[$device]['size']['blocks'] = number of blocks
// $result[$device]['size']['blockSize'] = block size in bytes
// $result[$device]['size']['totalBytes'] = blocks * blockSize
// $result[$device]['size']['readable'] = totalBytes as KiB, MiB, GiB,
TiB
// $result[$device]['removable'] = boolean removability indicator
// $result[$device]['mfgName'] = "vendor: model"
// $result[$device]['partition'][$partition]['size']['blocks'] = blocks
in partition
// $result[$device]['partition'][$partition]['size']['totalBytes'] =
blocks * $blkSize;
// $result[$device]['partition'][$partition]['size']['readable'] =
totalBytes as KiB, MiB, GiB, TiB
// $result[$device]['partition'][$partition]['start']['block'] =
starting block
// $result[$device]['partition'][$partition]['start']['readable'] =
block * $blkSize as KiB, MiB, GiB, TiB
// $device is the userspace name of the device, eg "/dev/sda"
// $partition is the userspace name of the partition, eg "/dev/sda6"
//
// for information about sysfs, see:
//
https://www.kernel.org/doc/Documentation/sysfs.txt
//
https://www.kernel.org/doc/Documentation/sysfs-rules.txt
// in particular,
// "- sysfs is always at /sys"
// "- devices are only 'devices' There is no such thing like
class-, bus-,
// physical devices, interfaces, and such that you
can rely on in userspace.
// Everything is just simply a "device". Class-,
bus-, physical, ... types
// are just kernel implementation details which
should not be expected by
// applications that look for devices in sysfs."
// "devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0)
// - identical to the DEVPATH value in the event sent from the
kernel
// at device creation and removal
// - the unique key to the device at that point in time
// - the kernel's path to the device directory without the
leading
// /sys, and always starting with a slash"
// (note: contained in variable $devPath below.)
//
// NOTE: the "parted -l" command can be used to obtain similar information, but has
// several disadvantages:
// - requires that the caller be running as root
// - does not ignore virtual devices like "/dev/zram0"
// - under certain timing conditions when a device is removed, it may
hang due to
// a broken pipe.
// This routine works better for detecting what devices actually exist, than
other
// commands like parted/fdisk/etc. can be used to add details as necessary.
//
// USAGE NOTE: an extended partition will be listed "nakedly", IOW its start block
and
// size will be listed but that is the extended partition descriptor alone, so
the
// reported size will not be the size of the extended partition.
//
// 2014.08.19 initial version
// 2014.11.04 significant rewrite to add details and partition info.
// 2014.11.06 update comments
// 2014.11.07 change result item names for consistency.
// 2014.11.17 return $result[$device]['partition'][$partition]['size']['blocks'].
function getRealBlockDeviceList()
{
$result = false; // if
unable to open /sys/block directory
$sysBlock = '/sys/block'; // only
interested in block devices
$usrNamePfx = '/dev'; //
userspace device name prefix
$virtDev = 'virtual'; // in
devPath of virtual devices
if ($dh = @opendir($sysBlock))
{
$result = array();
while (($kName = readdir($dh)) !== false) // scanning
"/sys/block"
{
if ($kName=="." || $kName=="..") // kernel-name
of device, eg "sda"
continue;
$blkDevLinkName = "$sysBlock/$kName"; // eg,
"/sys/block/sda"
if (!@is_link($blkDevLinkName))
continue;
// "/sys/block" contains only links
$linkCont = @readlink($blkDevLinkName);
if ($linkCont === false)
continue;
$linkDirs = explode('/', $linkCont);
if ($linkDirs[2] == $virtDev)
continue;
// "../devices/virtual/block/ram0" --> not physical
if ($linkDirs[0] == "..")
$linkDirs[0] = "";
$devPath = implode('/', $linkDirs); //
"/devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sda"
$deviceInfoDir = "/sys$devPath";
$device = "$usrNamePfx/$kName"; //
userspace name, eg "/dev/sda"
// if device is actually present, the "size" file will be
present/nonzero.
$deviceSizeFile = "$deviceInfoDir/size";
$blocks = @file_get_contents($deviceSizeFile);
if ($blocks == false)
continue;
$blocks = trim($blocks);
if ($blocks == 0)
continue;
// device not physically present
$result[$device] = array();
$blocks = (float)$blocks;
// extract device hex-id from "dev" file in device
information directory.
$deviceHexIdFile = "$deviceInfoDir/dev";
$hexId = @file_get_contents($deviceHexIdFile);
if ($hexId === false)
{
closedir($dh);
return false;
}
// record physical device blocks and block-size.
$result[$device]['size']['blocks'] = $blocks;
$blkSizeFile =
"/sys/block/$kName/queue/physical_block_size";
$blkSize = @file_get_contents($blkSizeFile);
if ($blkSize == false)
{
closedir($dh);
return false;
}
$blkSize = (float)trim($blkSize);
$result[$device]['size']['blockSize'] = $blkSize;
$result[$device]['size']['totalBytes'] = $blkSize *
$blocks;
$result[$device]['size']['readable'] = asKilo($blkSize *
$blocks);
// determine removability.
$deviceRemovabilityFile = "$deviceInfoDir/removable";
$remov = @file_get_contents($deviceRemovabilityFile);
if ($remov !== false)
$result[$device]['removable'] = trim($remov) ?
true : false;
// extract relevant information from files in "device" sub-
directory.
$vendorNameFile = "$deviceInfoDir/device/vendor";
$modelNameFile = "$deviceInfoDir/device/model";
$vendor = @file_get_contents($vendorNameFile);
if ($vendor === false)
$vendor = "vendor-unknown";
else
$vendor = trim($vendor);
$model = @file_get_contents($modelNameFile);
if ($model === false)
$model = "model-unknown";
else
$model = trim($model);
$devMfgrInfo = "$vendor: $model";
$result[$device]['mfgName'] = $devMfgrInfo;
// scan device information directory for partition sub-
directories,
// these begin with the device's kernel-name, eg "sda".
if ($ph = @opendir($deviceInfoDir))
{
$knl = strlen($kName);
while (($pName = readdir($ph)) !== false)
{
if (substr($pName,0,$knl) != $kName)
continue;
if (!is_dir("$deviceInfoDir/$pName"))
continue;
$pDevIdFile =
"$deviceInfoDir/$pName/dev";
if (!file_exists($pDevIdFile))
continue;
$pDevId =
@file_get_contents($pDevIdFile);
if ($pDevId === false)
continue;
$partition = "$usrNamePfx/$pName";
// userspace name, eg "/dev/sda6"
$pDevId = trim($pDevId);
$pSysDevIntf =
"/sys/dev/block/$pDevId";// device interface directory
$pSizeFile = "$pSysDevIntf/size";
// size in blocks
$blocks = @file_get_contents($pSizeFile);
if ($blocks === false)
continue;
$blocks = (float)trim($blocks);
$result[$device]['partition'][$partition]
['size']['blocks'] = $blocks;
$result[$device]['partition'][$partition]
['size']['totalBytes'] = $blocks * $blkSize;
$result[$device]['partition'][$partition]
['size']['readable'] = asKilo($blocks * $blkSize);
$startFile = "$pSysDevIntf/start";
// starting block
$start = @file_get_contents($startFile);
if ($start === false)
continue;
$start = (float)trim($start);
$result[$device]['partition'][$partition]
['start']['block'] = $start;
$result[$device]['partition'][$partition]
['start']['readable'] = asKilo($start * $blkSize);
}
closedir($ph);
if (count($result[$device]['partition']) > 0)
ksort($result[$device]['partition']);
}
}
closedir($dh);
if (count($result) > 0)
ksort($result); // always
order by ascending device name
}
return $result;