$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'tools';
require_once "$docroot/webGui/include/Translations.php";
switch ($_POST['table']) {
case 't1':
exec('for group in $(ls /sys/kernel/iommu_groups/ -1|sort -n);do echo "IOMMU group $group";for device in $(ls -1 "/sys/kernel/iommu_groups/$group"/devices/);do echo -n $\'\t\';lspci -ns "$device"|awk \'BEGIN{ORS=" "}{print "["$3"]"}\';lspci -s "$device";done;done',$groups);
if (empty($groups)) {
exec('lspci -n|awk \'{print "["$3"]"}\'',$iommu);
exec('lspci',$lspci);
$i = 0;
foreach ($lspci as $line) echo "
".$iommu[$i++]."
$line
";
$noiommu = true;
} else {
$BDF_VD_REGEX = '/^[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]](\|[[:xdigit:]]{4}:[[:xdigit:]]{4})?$/';
$DBDF_VD_REGEX = '/^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]](\|[[:xdigit:]]{4}:[[:xdigit:]]{4})?$/';
$BDF_REGEX = '/^[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]$/';
$DBDF_PARTIAL_REGEX = '/[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]/';
$vfio_cfg_devices = array ();
if (is_file("/boot/config/vfio-pci.cfg")) {
// accepts space-separated list of or followed by an optional "|" and
// example: BIND=03:00.0 0000:03:00.0 03:00.0|8086:1533 0000:03:00.0|8086:1533
// this front-end does not accept by itself, altough the underlying vfio-pci script does
$file = file_get_contents("/boot/config/vfio-pci.cfg");
$file = trim(str_replace("BIND=", "", $file));
$file_contents = explode(" ", $file);
foreach ($file_contents as $vfio_cfg_device) {
if (preg_match($BDF_VD_REGEX, $vfio_cfg_device)) {
// only was provided, assume Domain is 0000 (may be followed by optional too)
$vfio_cfg_devices[] = "0000:".$vfio_cfg_device;
} else if (preg_match($DBDF_VD_REGEX, $vfio_cfg_device)) {
// full was provided (may be followed by optional too)
$vfio_cfg_devices[] = $vfio_cfg_device;
} else {
// entry in wrong format, discard
}
}
$vfio_cfg_devices = array_values(array_unique($vfio_cfg_devices, SORT_STRING));
}
$disks = (array)parse_ini_file('state/disks.ini',true);
$devicelist = array_column($disks, 'device');
$lines = array ();
foreach ($devicelist as $line) {
if (!empty($line)) {
exec('udevadm info --path=$(udevadm info -q path /dev/'.$line.' | cut -d / -f 1-7) --query=path',$linereturn);
preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse);
foreach ($inuse[0] as $line) {
$lines[] = $line;
}
unset($inuse);
unset($linereturn);
}
}
$networks = (array)parse_ini_file('state/network.ini',true);
$networklist = explode(",", array_column($networks, 'BRNICS')[0].",".array_column($networks, 'BONDNICS')[0]);
foreach ($networklist as $line) {
if (!empty($line)) {
exec('readlink /sys/class/net/'.$line,$linereturn);
preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse);
foreach ($inuse[0] as $line) {
$lines[] = $line;
}
unset($inuse);
unset($linereturn);
}
}
$lines = array_values(array_unique($lines, SORT_STRING));
$iommuinuse = array ();
foreach ($lines as $pciinuse){
$string = exec("ls /sys/kernel/iommu_groups/*/devices/$pciinuse -1 -d");
$string = substr($string,25,2);
$iommuinuse[] = (strpos($string,'/')) ? strstr($string, '/', true) : $string;
}
exec('lsscsi -s',$lsscsi);
foreach ($groups as $line) {
if (!$line) continue;
if ($line[0]=='I') {
if ($spacer) echo "
"; else $spacer = true;
echo "
$line:
";
$iommu = substr($line, 12);
$append = true;
} else {
$line = preg_replace("/^\t/","",$line);
$vd = trim(explode(" ", $line)[0], "[]");
$pciaddress = explode(" ", $line)[1];
if (preg_match($BDF_REGEX, $pciaddress)) {
// By default lspci does not output the when the only domain in the system is 0000. Add it back.
$pciaddress = "0000:".$pciaddress;
}
echo ($append)?"":"