#!/usr/bin/php -q
session_start();
$docroot = '/usr/local/emhttp';
$varroot = '/var/local/emhttp';
$smartALL = '/boot/config/smart-all.cfg';
$smartONE = '/boot/config/smart-one.cfg';
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/webGui/include/publish.php";
extract(parse_plugin_cfg('dynamix',true));
// add translations
$_SERVER['REQUEST_URI'] = 'main';
$_SESSION['locale'] = $display['locale'];
require_once "$docroot/webGui/include/Translations.php";
// remember current language
$locale_init = $locale;
// close session, it is not needed anymore
session_unset();
session_destroy();
function initSum() {
return ['count'=>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,'_'));
}
function device_info(&$disk,$online) {
global $pools, $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) {
$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 = "
";
}
function vfs_type($fs) {
return str_replace('luks:','',$fs);
}
function vfs_luks($fs) {
return ($fs != vfs_type($fs));
}
function fs_info(&$disk) {
global $display, $pools;
$echo = [];
if (empty($disk['fsStatus']) || $disk['fsStatus']=='-') {
return ($disk['type']=='Cache' && !in_array($disk['name'],$pools)) ? ""._('Device is part of a pool')." | | " : " | ";
} 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']);
return implode('',$echo);
}
function my_diskio($data) {
return my_scale($data,$unit,1)." $unit/s";
}
function array_offline(&$disk,$pool='') {
global $var, $disks;
$echo = [];
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[] = "
";
return implode('',$echo);
}
function array_online(&$disk) {
global $pools, $sum, $diskio;
$echo = [];
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[] = " | ";
$echo[] = fs_info($disk);
}
break;
case 'DISK_NP_DSBL':
$echo[] = "".device_info($disk,true)." | ";
$echo[] = ""._('Not installed')." | ";
$echo[] = " | ";
$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'])." | ";
$echo[] = fs_info($disk);
break;
}
$echo[] = "
";
return implode('',$echo);
}
function show_totals($text,$array,$name) {
global $var, $display, $sum, $locale;
$echo = [];
$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[] = "
";
return implode('',$echo);
}
function array_slots() {
global $var;
$min = max($var['sbNumDisks'], 3);
$max = $var['MAX_ARRAYSZ'];
$out = "";
return $out;
}
function cache_slots($off,$pool,$min,$slots) {
global $var;
$off = $off && $min ? ' disabled' : '';
$max = $var['MAX_CACHESZ'];
$out = "";
return $out;
}
function update_translation($locale) {
global $docroot,$language;
$language = [];
if ($locale) {
$text = "$docroot/languages/$locale/translations.txt";
if (file_exists($text)) {
$store = "$docroot/languages/$locale/translations.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = unserialize(file_get_contents($store));
}
$text = "$docroot/languages/$locale/main.txt";
if (file_exists($text)) {
$store = "$docroot/languages/$locale/main.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = array_merge($language,unserialize(file_get_contents($store)));
}
}
}
while (true) {
$var = (array)parse_ini_file("$varroot/var.ini");
$devs = (array)parse_ini_file("$varroot/devs.ini",true);
$disks = (array)parse_ini_file("$varroot/disks.ini",true);
$sec = (array)parse_ini_file("$varroot/sec.ini",true);
$diskio = @(array)parse_ini_file("$varroot/diskload.ini");
$crypto = false;
$pools = pools_filter($disks);
$echo = [];
// check for language changes
extract(parse_plugin_cfg('dynamix',true));
if ($display['locale'] != $locale_init) {
$locale_init = $display['locale'];
update_translation($locale_init);
}
// 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);
// merge device custom settings
if (file_exists($smartALL)) $var = array_merge($var, parse_ini_file($smartALL));
if (file_exists($smartONE)) {
$smarts = parse_ini_file($smartONE,true);
foreach ($smarts as $id => $smart) {
if (isset($disks)) {
foreach ($disks as $key => $disk) {
if ($disk['id'] == $id) $disks[$key] = array_merge($disks[$key], $smart);
}
}
if (isset($devs)) {
foreach ($devs as $key => $disk) {
if ($disk['id'] == $id) $devs[$key] = array_merge($devs[$key], $smart);
}
}
}
}
$sum = initSum();
$echo[0] = "array_devices\n";
$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) $echo[0] .= array_offline($disk);
$echo[0] .= " |
";
foreach ($data as $disk) $echo[0] .= array_offline($disk);
$echo[0] .= "| "._('Slots').": | ".array_slots()." | |
";
} else {
foreach ($parity as $disk) if ($disk['status']!='DISK_NP_DSBL') $echo[0] .= array_online($disk);
foreach ($data as $disk) $echo[0] .= array_online($disk);
if ($display['total'] && $var['mdNumDisks']>1) $echo[0] .= show_totals(sprintf(_('Array of %s devices'),my_word($var['mdNumDisks'])),true,'array*');
}
$echo[1] = "boot_device\n";
$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[1] .= "";
$echo[1] .= "| ".$share.device_info($disk,true)." | ";
$echo[1] .= "".device_desc($disk)." | ";
$echo[1] .= "* | ";
$echo[1] .= "".my_diskio($data[0])."".my_number($disk['numReads'])." | ";
$echo[1] .= "".my_diskio($data[1])."".my_number($disk['numWrites'])." | ";
$echo[1] .= "".my_number($disk['numErrors'])." | ";
$echo[1] .= fs_info($disk);
$echo[1] .= "
";
$sum = initSum();
$cache = cache_filter($disks); $n = 2;
foreach ($pools as $pool) {
$echo[$n] = "pool_device".($n-2)."\n";
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) {
$echo[$n] .= 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\"";
$echo[$n] .= "| "._('Slots').": | ".cache_slots($off,$pool,$cache[$pool]['devicesSb'],$cache[$pool]['slots'])." | |
";
} else {
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'];
$echo[$n] .= array_online($disk);
}
if ($display['total'] && $cache[$pool]['devices']>1) $echo[$n] .= show_totals(sprintf(_('Pool of %s devices'),my_word($cache[$pool]['devices'])),false,"$pool*");
$sum = initSum();
}
$n++;
}
$echo[$n] = "open_devices\n";
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[$n] .= "";
$echo[$n] .= "| ".device_info($disk,true)." | ";
$echo[$n] .= "".device_desc($disk)." | ";
$echo[$n] .= "".my_temp($disk['temp'])." | ";
$echo[$n] .= "".my_diskio($data[0])."".my_number($disk['numReads'])." | ";
$echo[$n] .= "".my_diskio($data[1])."".my_number($disk['numWrites'])." | ";
$echo[$n] .= "".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[$n] .= "$text | ";
} else
$echo[$n] .= " | ";
$echo[$n] .= "
";
}
publish('devices', implode("\0",$echo));
usleep(333333);
}
?>