0, 'temp'=>0, 'fsSize'=>0, 'fsUsed'=>0, 'fsFree'=>0, 'ioReads'=>0, 'ioWrites'=>0, 'numReads'=>0, 'numWrites'=>0, 'numErrors'=>0]; } function model($id) { return substr($id,0,strrpos($id,'_')); } // sort unassigned devices on disk identification if (count($devs)>1) array_multisort(array_column($devs,'sectors'),SORT_DESC,array_map('model',array_column($devs,'id')),SORT_NATURAL|SORT_FLAG_CASE,array_column($devs,'device'),$devs); require_once "$docroot/webGui/include/CustomMerge.php"; function in_parity_log($log,$timestamp) { if (file_exists($log)) { $handle = fopen($log, 'r'); while (($line = fgets($handle))!==false) { if (strpos($line,$timestamp)!==false) break; } fclose($handle); } return !empty($line); } function device_info(&$disk,$online) { global $pools, $path, $var, $crypto; $name = $disk['name']; $fancyname = compress(_(my_disk($name),3),16,5); $type = $disk['type']=='Flash' ? $disk['type'] : 'Device'; $action = strpos($disk['color'],'blink')===false ? 'down' : 'up'; switch ($disk['color']) { case 'green-on': $orb = 'circle'; $color = 'green'; $help = _('Normal operation, device is active'); break; case 'green-blink': $orb = 'circle'; $color = 'grey'; $help = _('Device is in standby mode (spun-down)'); break; case 'blue-on': $orb = 'square'; $color = 'blue'; $help = _('New device'); break; case 'blue-blink': $orb = 'square'; $color = 'grey'; $help = _('New device, in standby mode (spun-down)'); break; case 'yellow-on': $orb = 'warning'; $color = 'yellow'; $help = $disk['type']=='Parity' ? _('Parity is invalid') : _('Device contents emulated'); break; case 'yellow-blink': $orb = 'warning'; $color = 'grey'; $help = $disk['type']=='Parity' ? _('Parity is invalid, in standby mode (spun-down)') : _('Device contents emulated, in standby mode (spun-down)'); break; case 'red-on': case 'red-blink': $orb = 'times'; $color = 'red'; $help = $disk['type']=='Parity' ? _('Parity device is disabled') : _('Device is disabled, contents emulated'); break; case 'red-off': $orb = 'times'; $color = 'red'; $help = $disk['type']=='Parity' ? _('Parity device is missing') : _('Device is missing (disabled), contents emulated'); break; case 'grey-off': $orb = 'square'; $color = 'grey'; $help = _('Device not present'); break; } $ctrl = ''; if ($var['fsState']=='Started' && $type!='Flash' && strpos($disk['status'],'_NP')===false) { $ctrl = " style='cursor:pointer' onclick=\"toggle_state('$type','$name','$action')\""; $help .= "
"._("Click to spin $action device"); } $status = "$help"; $link = ($disk['type']=='Parity' && strpos($disk['status'],'_NP')===false) || ($disk['type']=='Data' && $disk['status']!='DISK_NP') || ($disk['type']=='Cache' && $disk['status']!='DISK_NP') || ($disk['name']=='flash') || in_array($disk['name'],$pools) || $disk['type']=='New' ? "$fancyname" : $fancyname; if ($crypto) switch ($disk['luksState']) { case 0: if (!vfs_luks($disk['fsType'])) $luks = ""; else $luks = ""._('Device to be encrypted').""; break; case 1: if ($online) { $luks = ""._('Device encrypted and unlocked').""; break; } /* fall thru */ case 2: $luks = ""._('Device encrypted').""; break; case 3: $luks = ""._('Device locked: wrong encryption key').""; break; default: $luks = ""._('Device locked: unknown error').""; break; } else $luks = ''; return $status.$luks.$link; } function device_browse(&$disk) { global $path; $dir = $disk['name']=='flash' ? "/boot" : "/mnt/{$disk['name']}"; return ""; } function device_desc(&$disk) { global $var; $size = my_scale($disk['size'] ? $disk['size']*1024 : $disk['sectors']*$disk['sector_size'],$unit,-1); switch ($disk['type']) { case 'Flash' : $type = 'usb'; break; case 'Parity': $type = $disk['rotational'] ? 'disk' : 'nvme'; break; case 'Data' : case 'Cache' : $type = $disk['rotational'] ? ($disk['luksState'] ? 'disk-encrypted' : 'disk') : 'nvme'; break; default : $type = 'disk'; break; } $log = $var['fsState']=='Started' ? ""._('Disk Log Information')."" : ""; return $log."".my_id($disk['id'])." - $size $unit ({$disk['device']})"; } function assignment(&$disk) { global $var, $devs; $out = "
"; $out .= ""; $out .= ""; $out .= "
"; } function vfs_type($fs) { return str_replace('luks:','',$fs); } function vfs_luks($fs) { return ($fs != vfs_type($fs)); } function fs_info(&$disk) { global $display; if (empty($disk['fsStatus'])) { echo ($disk['type']=='Cache') ? ""._('Device is part of a pool')."" : ""; return; } elseif ($disk['fsStatus']=='Mounted') { echo "".vfs_type($disk['fsType']).""; echo "".my_scale(($disk['fsSize']??0)*1024,$unit,-1)." $unit"; if ($display['text']%10==0) { echo "".my_scale($disk['fsUsed']*1024,$unit)." $unit"; } else { $used = isset($disk['fsSize']) && $disk['fsSize']>0 ? 100-round(100*$disk['fsFree']/$disk['fsSize']) : 0; echo "
".my_scale($disk['fsUsed']*1024,$unit)." $unit
"; } if ($display['text']<10 ? $display['text']%10==0 : $display['text']%10!=0) { echo "".my_scale($disk['fsFree']*1024,$unit)." $unit"; } else { $free = isset($disk['fsSize']) && $disk['fsSize']>0 ? round(100*$disk['fsFree']/$disk['fsSize']) : 0; echo "
".my_scale($disk['fsFree']*1024,$unit)." $unit
"; } echo "".device_browse($disk).""; } else echo "".vfs_type($disk['fsType']).""._($disk['fsStatus']); } function my_diskio($data) { return my_scale($data,$unit,1)." $unit/s"; } function array_offline(&$disk,$pool='') { global $var, $disks; if (strpos($var['mdState'],'ERROR:')===false) { $text = ""._('All existing data on this device will be OVERWRITTEN when array is Started').""; if ($disk['type']=='Cache') { if (!empty($disks[$pool]['uuid']) && $disk['status']=='DISK_NEW') $warning = $text; } else { if ($var['mdState']=='NEW_ARRAY') { if ($disk['type']=='Parity') $warning = $text; } else if ($var['mdNumInvalid']<=1) { if (in_array($disk['status'],['DISK_INVALID','DISK_DSBL_NEW','DISK_WRONG','DISK_NEW'])) $warning = $text; } } } echo ""; switch ($disk['status']) { case 'DISK_NP': case 'DISK_NP_DSBL': echo "".device_info($disk,false).""; echo "".assignment($disk).""; echo ""; break; case 'DISK_NP_MISSING': echo "".device_info($disk,false)."
"._('Missing').""; echo "".assignment($disk)."{$disk['idSb']} - ".my_scale($disk['sizeSb']*1024,$unit)." $unit"; echo ""; break; case 'DISK_OK': case 'DISK_DSBL': case 'DISK_INVALID': case 'DISK_DSBL_NEW': case 'DISK_NEW': echo "".device_info($disk,false).""; echo "".assignment($disk).""; echo "".my_temp($disk['temp']).""; echo "$warning"; break; case 'DISK_WRONG': echo "".device_info($disk,false)."
"._('Wrong').""; echo "".assignment($disk)."{$disk['idSb']} - ".my_scale($disk['sizeSb']*1024,$unit)." $unit"; echo "".my_temp($disk['temp']).""; echo "$warning"; break; } echo ""; } function array_online(&$disk) { global $pools, $sum, $diskio; if ($disk['device']!='') { $dev = $disk['device']; $data = explode(' ',$diskio[$dev] ?? '0 0'); $sum['ioReads'] += $data[0]; $sum['ioWrites'] += $data[1]; } if (is_numeric($disk['temp'])) { $sum['count']++; $sum['temp'] += $disk['temp']; } $sum['numReads'] += $disk['numReads']; $sum['numWrites'] += $disk['numWrites']; $sum['numErrors'] += $disk['numErrors']; if (isset($disk['fsFree'])) { $sum['fsSize'] += $disk['fsSize']; $sum['fsUsed'] += $disk['fsUsed']; $sum['fsFree'] += $disk['fsFree']; } echo ""; switch ($disk['status']) { case 'DISK_NP': if (in_array($disk['name'],$pools)) { echo "".device_info($disk,true).""; echo ""._('Not installed').""; echo ""; fs_info($disk); } break; case 'DISK_NP_DSBL': echo "".device_info($disk,true).""; echo ""._('Not installed').""; echo ""; fs_info($disk); break; case 'DISK_DSBL': default: echo "".device_info($disk,true).""; echo "".device_desc($disk).""; echo "".my_temp($disk['temp']).""; echo "".my_diskio($data[0])."".my_number($disk['numReads']).""; echo "".my_diskio($data[1])."".my_number($disk['numWrites']).""; echo "".my_number($disk['numErrors']).""; fs_info($disk); break; } echo ""; } function my_clock($time) { if (!$time) return _('less than a minute'); $days = floor($time/1440); $hour = $time/60%24; $mins = $time%60; return plus($days,'day',($hour|$mins)==0).plus($hour,'hour',$mins==0).plus($mins,'minute',true); } function show_totals($text,$array,$name) { global $var, $display, $sum; $ctrl1 = "onclick=\"toggle_state('Device','$name','down')\""; $ctrl2 = "onclick=\"toggle_state('Device','$name','up')\""; $help1 = _('Spin Down').' '._(ucfirst(substr($name,0,-1))); $help2 = _('Spin Up').' '._(ucfirst(substr($name,0,-1))); echo ""; echo "$help1$help2"; echo "$text"; echo "".($sum['count']>0 ? my_temp(round($sum['temp']/$sum['count'],1)) : '*').""; echo "".my_diskio($sum['ioReads'])."".my_number($sum['numReads']).""; echo "".my_diskio($sum['ioWrites'])."".my_number($sum['numWrites']).""; echo "".my_number($sum['numErrors']).""; echo ""; if ($array && ($var['startMode']=='Normal')) { echo "".my_scale($sum['fsSize']*1024,$unit,-1)." $unit"; if ($display['text']%10==0) { echo "".my_scale($sum['fsUsed']*1024,$unit)." $unit"; } else { $used = $sum['fsSize'] ? 100-round(100*$sum['fsFree']/$sum['fsSize']) : 0; echo "
".my_scale($sum['fsUsed']*1024,$unit)." $unit
"; } if ($display['text']<10 ? $display['text']%10==0 : $display['text']%10!=0) { echo "".my_scale($sum['fsFree']*1024,$unit)." $unit"; } else { $free = $sum['fsSize'] ? round(100*$sum['fsFree']/$sum['fsSize']) : 0; echo "
".my_scale($sum['fsFree']*1024,$unit)." $unit
"; } echo ""; } else echo ""; echo ""; } function array_slots() { global $var; $min = max($var['sbNumDisks'], 3); $max = $var['MAX_ARRAYSZ']; $out = "
"; $out .= ""; $out .= ""; $out .= "
"; return $out; } function cache_slots($off,$pool,$min,$slots) { global $var; $off = $off && $min ? ' disabled' : ''; $max = $var['MAX_CACHESZ']; $out = "
"; $out .= ""; $out .= ""; $out .= ""; $out .= "
"; return $out; } $crypto = false; $pools = pools_filter($disks); $sum = initSum(); switch ($_POST['device']) { case 'array': $parity = parity_filter($disks); $data = data_filter($disks); foreach ($data as $disk) $crypto |= $disk['luksState']!=0 || vfs_luks($disk['fsType']); if ($var['fsState']=='Stopped') { foreach ($parity as $disk) array_offline($disk); echo ""; foreach ($data as $disk) array_offline($disk); echo ""._('Slots').":".array_slots().""; } else { foreach ($parity as $disk) if ($disk['status']!='DISK_NP_DSBL') array_online($disk); foreach ($data as $disk) array_online($disk); if ($display['total'] && $var['mdNumDisks']>1) show_totals(sprintf(_('Array of %s devices'),my_word($var['mdNumDisks'])),true,'array*'); } break; case 'flash': $disk = &$disks['flash']; $data = explode(' ',$diskio[$disk['device']] ?? '0 0'); $flash = &$sec['flash']; $share = ""; if ($var['shareSMBEnabled']=='yes' && $flash['export']=='e' && $flash['security']=='public') $share = ""._('Flash device is set as public share')."
"._('Please change share SMB security')."
"._('Click on FLASH above this message')."
"; echo ""; echo "".$share.device_info($disk,true).""; echo "".device_desc($disk).""; echo "*"; echo "".my_diskio($data[0])."".my_number($disk['numReads']).""; echo "".my_diskio($data[1])."".my_number($disk['numWrites']).""; echo "".my_number($disk['numErrors']).""; fs_info($disk); echo ""; break; case 'cache': $cache = cache_filter($disks); foreach ($pools as $pool) { $tmp = "/var/tmp/$pool.log.tmp"; foreach ($cache as $disk) if (prefix($disk['name'])==$pool) $crypto |= $disk['luksState']!=0 || vfs_luks($disk['fsType']); if ($var['fsState']=='Stopped') { $log = @(array)parse_ini_file($tmp); $off = false; foreach ($cache as $disk) if (prefix($disk['name'])==$pool) { array_offline($disk,$pool); if (isset($log[$disk['name']])) $off |= ($log[$disk['name']]!=$disk['id']); else $log[$disk['name']] = $disk['id']; } $data = []; foreach ($log as $key => $value) $data[] = "$key=\"$value\""; file_put_contents($tmp,implode("\n",$data)); echo ""._('Slots').":".cache_slots($off,$pool,$cache[$pool]['devicesSb'],$cache[$pool]['slots'])."\0"; } else { if ($cache[$pool]['devices']) { foreach ($cache as $disk) if (prefix($disk['name'])==$pool) { if (substr($cache[$pool]['fsStatus'],0,11)=='Unmountable' && empty($disk['fsStatus'])) $disk['fsStatus'] = $cache[$pool]['fsStatus']; array_online($disk); } if ($display['total'] && $cache[$pool]['devices']>1) show_totals(sprintf(_('Pool of %s devices'),my_word($cache[$pool]['devices'])),false,"$pool*"); $sum = initSum(); echo "\0"; } @unlink($tmp); } } break; case 'open': foreach ($devs as $disk) { $dev = $disk['device']; $data = explode(' ',$diskio[$dev] ?? '0 0 0 0'); $disk['type'] = 'New'; $disk['color'] = $disk['spundown']=="0" ? 'blue-on' : 'blue-blink'; echo ""; echo "".device_info($disk,true).""; echo "".device_desc($disk).""; echo "".my_temp($disk['temp']).""; echo "".my_diskio($data[0])."".my_number($disk['numReads']).""; echo "".my_diskio($data[1])."".my_number($disk['numWrites']).""; echo "".my_number($disk['numErrors']).""; if (file_exists("/tmp/preclear_stat_$dev")) { $text = exec("cut -d'|' -f3 /tmp/preclear_stat_$dev|sed 's:\^n:\:g'"); if (strpos($text,'Total time')===false) $text = _('Preclear in progress').'... '.$text; echo "$text"; } else echo ""; echo ""; } break; case 'parity': $data = []; if ($var['mdResyncPos']) { $data[] = my_scale($var['mdResyncSize']*1024,$unit,-1)." $unit"; $data[] = _(my_clock(floor((time()-$var['sbSynced'])/60)),2).($var['mdResyncDt'] ? '' : ' ('._('paused').')'); $data[] = my_scale($var['mdResyncPos']*1024,$unit)." $unit (".number_format(($var['mdResyncPos']/($var['mdResyncSize']/100+1)),1,$display['number'][0],'')." %)"; $data[] = $var['mdResyncDt'] ? my_scale($var['mdResyncDb']*1024/$var['mdResyncDt'],$unit, 1)." $unit/sec" : '---'; $data[] = $var['mdResyncDb'] ? _(my_clock(round(((($var['mdResyncDt']*(($var['mdResyncSize']-$var['mdResyncPos'])/($var['mdResyncDb']/100+1)))/100)/60),0)),2) : _('Unknown'); $data[] = $var['sbSyncErrs']; echo implode(';',$data); } else { if ($var['sbSynced']==0 || $var['sbSynced2']==0) break; $log = '/boot/config/parity-checks.log'; $timestamp = str_replace(['.0','.'],[' ',' '],date('M.d H:i:s',$var['sbSynced2'])); if (in_parity_log($log,$timestamp)) break; $duration = $var['sbSynced2'] - $var['sbSynced']; $status = $var['sbSyncExit']; $speed = ($status==0) ? my_scale($var['mdResyncSize']*1024/$duration,$unit,1)." $unit/s" : _('Unavailable'); $error = $var['sbSyncErrs']; $year = date('Y',$var['sbSynced2']); if ($status==0||file_exists($log)) file_put_contents($log,"$year $timestamp|$duration|$speed|$status|$error\n",FILE_APPEND); } break; } ?>