\S+) Device (?P\S+): ID (?P\S+)(?P.*)$/', $usbbusdev, $usbMatch)) { //udevadm info -a --name=/dev/bus/usb/003/002 | grep KERNEL== $udevcmd = "udevadm info -a --name=/dev/bus/usb/".$usbMatch['bus']."/".$usbMatch['dev']." | grep KERNEL=="; $physical_busid = _("None"); exec($udevcmd , $udev); if (isset($udev)) { $physical_busid = trim(substr($udev[0], 13) , '"'); if (substr($physical_busid,0,3) =='usb') { $physical_busid = substr($physical_busid,3).'-0'; } } } return($physical_busid); } 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); if(isset($linereturn[0])) { 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 = array_merge(array_column($networks, 'BRNICS'), array_column($networks, 'BONDNICS')); foreach ($networklist as $niclist) { if (!empty($niclist)) { $nics = explode(",", $niclist); if (!empty($nics)) { foreach ($nics as $line) { if (!empty($line)) { exec('readlink /sys/class/net/'.$line,$linereturn); if(isset($linereturn[0])) { 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); // Filter for 'removed' devices $removedArr = array_filter($pci_device_diffs, function($entry) { return isset($entry['status']) && $entry['status'] === 'removed'; }); foreach ($removedArr as $removedpci => $removeddata) { $groups[] = "IOMMU "._("Removed"); $groups[] = "\tR[{$removeddata['device']['vendor_id']}:{$removeddata['device']['device_id']}] ".str_replace("0000:","",$removedpci)." ".trim($removeddata['device']['description'],"\n"); } $ackparm = ""; foreach ($groups as $line) { if (!$line) continue; if ($line[0]=='I') { if (isset($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]; $removed = $line[0]=='R' ? true : false; if ($removed) $line=preg_replace('/R/', '', $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) ? "" : ""; exec("lspci -v -s $pciaddress", $outputvfio); if (preg_grep("/vfio-pci/i", $outputvfio)) { echo ""; $isbound = "true"; } echo ""; if ((strpos($line, 'Host bridge') === false) && (strpos($line, 'PCI bridge') === false)) { if (file_exists('/sys/kernel/iommu_groups/'.$iommu.'/devices/'.$pciaddress.'/reset')) echo ""; echo ""; if (!$removed) { echo in_array($iommu, $iommuinuse) ? '| or just echo (in_array($pciaddress."|".$vd, $vfio_cfg_devices) || in_array($pciaddress, $vfio_cfg_devices)) ? " checked>" : ">"; } } else { echo ""; } echo '',$line,''; if (array_key_exists($pciaddress,$pci_device_diffs)) { echo ""; echo ""; echo _("PCI Device change"); echo " "._("Action").":".ucfirst(_($pci_device_diffs[$pciaddress]['status']))." "; $ackparm .= $pciaddress.",".$pci_device_diffs[$pciaddress]['status'].";"; if ($pci_device_diffs[$pciaddress]['status']!="removed") echo $pci_device_diffs[$pciaddress]['device']['description']; echo ""; if ($pci_device_diffs[$pciaddress]['status']=="changed") { echo ""; echo _("Differences"); foreach($pci_device_diffs[$pciaddress]['differences'] as $key => $changes){ echo " $key "._("before").":{$changes['old']} "._("after").":{$changes['new']} "; } echo ""; } } unset($outputvfio); switch (true) { case (strpos($line, 'USB controller') !== false): if (isset($isbound)) { echo '',_('This controller is bound to vfio, connected USB devices are not visible'),'.'; } else { exec('for usb_ctrl in $(find /sys/bus/usb/devices/usb* -maxdepth 0 -type l);do path="$(realpath "${usb_ctrl}")";if [[ $path == *'.$pciaddress.'* ]];then bus="$(cat "${usb_ctrl}/busnum")";lsusb -s $bus:|sort;fi;done',$getusb); foreach($getusb as $usbdevice) { [$bus,$id] = my_explode(':',$usbdevice); $usbport = usb_physical_port($usbdevice); if (strlen($usbport) > 7 ) {$usbport .= "\t"; } else { $usbport .= "\t\t"; } echo "$bus Port $usbport",trim($id),""; } unset($getusb); } break; case (strpos($line, 'SATA controller') !== false): case (strpos($line, 'Serial Attached SCSI controller') !== false): case (strpos($line, 'RAID bus controller') !== false): case (strpos($line, 'SCSI storage controller') !== false): case (strpos($line, 'IDE interface') !== false): case (strpos($line, 'Mass storage controller') !== false): case (strpos($line, 'Non-Volatile memory controller') !== false): if (isset($isbound)) { echo '',_('This controller is bound to vfio, connected drives are not visible'),'.'; } else { exec('ls -al /sys/block/sd* /sys/block/hd* /sys/block/sr* /sys/block/nvme* 2>/dev/null | grep -i "'.$pciaddress.'"',$getsata); foreach($getsata as $satadevice) { $satadevice = substr($satadevice, strrpos($satadevice, '/', -1)+1); $search = preg_grep('/'.$satadevice.'.*/', $lsscsi); foreach ($search as $deviceline) { echo '',$deviceline,''; } } unset($search); unset($getsata); } break; } unset($isbound); $append = false; } } echo '
'; if (file_exists("/var/log/vfio-pci") && filesize("/var/log/vfio-pci")) { echo ''; } if ($ackparm == "") $ackdisable =" disabled "; else $ackdisable = ""; echo ''; echo ''; echo ''; echo ''; echo << $("#t1 input[type='checkbox']").change(function() { var matches = document.querySelectorAll("." + this.className); for (var i=0, len=matches.length|0; i EOT; } break; case 't2': $is_intel_cpu = is_intel_cpu(); $core_types = $is_intel_cpu ? get_intel_core_types() : []; exec('cat /sys/devices/system/cpu/*/topology/thread_siblings_list|sort -nu',$pairs); $i = 1; foreach ($pairs as $line) { $line2 = $line; $line = preg_replace(['/(\d+)[-,](\d+)/','/(\d+)\b/'],['$1 / $2','cpu $1'],$line); if ($is_intel_cpu && count($core_types) > 0) { [$cpu1, $cpu2] = my_preg_split('/[,-]/',$line2); $core = $cpu1; $core_type = "({$core_types[$core]})"; } else $core_type = ""; echo "".(strpos($line,'/')===false?"Single":"Pair ".$i++).":$line $core_type"; } break; case 't3': exec('lsusb|sort',$lsusb); foreach ($lsusb as $line) { [$bus,$id] = my_explode(':',$line); $usbport = usb_physical_port($line); echo "$bus Port $usbport".trim($id).""; } break; case 't4': exec('lsscsi -s',$lsscsi); foreach ($lsscsi as $line) { if (strpos($line,'/dev/')===false) continue; echo "",preg_replace('/\] +/',']',$line),""; } break; } ?>