#!/usr/bin/php -q 0 ? (($val || $last) ? ($val.' '.$word.($val!=1?'s':'').($last ?'':', ')) : '') : ''; } function my_temp($value) { global $unraid; if ($value=='*') return ' - standby'; $unit = $unraid['display']['unit']; return ' - active '.($unit=='F' ? round(9/5*$value+32) : str_replace('.', $unraid['display']['number'][0], $value)).' '.$unit; } function my_disk($name) { return ucfirst(preg_replace('/(\d+)$/',' $1',$name)); } function my_scale($value, &$unit, $precision = NULL) { global $unraid; $scale = $unraid['display']['scale']; $number = $unraid['display']['number']; $units = ['B','KB','MB','GB','TB','PB']; if ($scale==0 && $precision===NULL) { $unit = ''; return number_format($value, 0, $number[0], ($value>=10000 ? $number[1] : '')); } else { $base = $value ? floor(log($value, 1000)) : 0; if ($scale>0 && $base>$scale) $base = $scale; $value = round($value/pow(1000, $base), $precision===NULL ? 2 : $precision); if ($value>=1000 && $scale<0) { $value = 1; $base++; } $unit = $units[$base]; return number_format($value, $precision===NULL ? (($value-intval($value)==0 || $value>=100) ? 0 : ($value>=10 ? 1 : 2)) : $precision, $number[0], ($value>=10000 ? $number[1] : '')); } } function my_check($time,$speed) { if (!$time) return 'unavailable (no parity-check entries logged)'; $days = floor($time/86400); $hmss = $time-$days*86400; $hour = floor($hmss/3600); $mins = $hmss/60%60; $secs = $hmss%60; return plus($days,'day',($hour|$mins|$secs)==0).plus($hour,'hour',($mins|$secs)==0).plus($mins,'minute',$secs==0).plus($secs,'second',true).". Average speed: $speed"; } function my_time($time) { global $unraid; $date = my_date($unraid['display']['date'].($unraid['display']['date']!='%c' ? ", {$unraid['display']['time']}" : ""), $time); $now = new DateTime("@".intval(time()/86400)*86400); $last = new DateTime("@".intval($time/86400)*86400); $days = date_diff($last,$now)->format('%a'); switch (true) { case ($days<0): return $date; case ($days==0): return "$date (today)"; case ($days==1): return "$date (yesterday)"; default: return "$date ($days days ago)"; } } 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 my_array(&$disk) { global $data,$unraid,$error0,$error1,$error2,$error3; $name = $disk['name']; $hot = $disk['hotTemp'] ?? $unraid['display']['hot'] ?? 0; $max = $disk['maxTemp'] ?? $unraid['display']['max'] ?? 0; if (strpos($disk['status'],'_NP')!==false) return false; $temp = $disk['temp']; if ($temp>=$max) { $fail = ' (disk is overheated'; $error0++; } elseif ($temp>=$hot) { $fail = ' (disk is hot'; $error1++; } else { $fail = ''; } if ($disk['numErrors']>0) { if ($fail) $fail .= ', '; else $fail = ' ('; $fail .= 'disk has read errors'; $error2++; } if ($fail) $fail .= ')'; $status = $fail ? ' [NOK]' : ' [OK]'; $color = strtok($disk['color'],'-'); if ($color=='red'||$color=='yellow') { $error3++; $status = ' ['.str_replace(['NP_','_'],['',' '],$disk['status']).']'; } $info = "{$disk['id']} ({$disk['device']})"; if ($info==" ()") $info = 'No device identification present'; $data[] = my_disk($name)." - $info".my_temp($temp).$fail.$status; return true; } // generate report of array devices foreach ($disks as $disk) if ($disk['type']=='Parity') $parity |= my_array($disk); foreach ($disks as $disk) if ($disk['type']=='Data') my_array($disk); foreach ($disks as $disk) if ($disk['type']=='Cache') $cache |= my_array($disk); $size = count($data); // generate parity report $data[] = ""; $mdResync = $var['mdResync']; if ($mdResync>0) { $mdResyncPos = $var['mdResyncPos']; $mdResyncDb = $var['mdResyncDb']; $mdResyncDt = $var['mdResyncDt']; $mode = ''; if (strstr($var['mdResyncAction'],"recon")) { $mode = 'Parity sync / Data rebuild'; } elseif (strstr($var['mdResyncAction'],"clear")) { $mode = 'Disk clear'; } elseif ($var['mdResyncAction']=="check") { $mode = 'Read check'; } elseif (strstr($var['mdResyncAction'],"check")) { $mode = 'Parity check'; } $data[] = $mode." in progress."; $data[] = "Total size: ".my_scale($mdResync*1024, $unit)." $unit"; $data[] = "Elapsed time: ".my_clock(floor((time()-$var['sbUpdated'])/60)); $data[] = "Current position: ".my_scale($mdResyncPos*1024, $unit)." $unit (".number_format(($mdResyncPos/($mdResync/100+1)),1,$unraid['display']['number'][0],'')." %)"; $data[] = "Estimated speed: ".my_scale($mdResyncDb/$mdResyncDt*1024, $unit, 1)." $unit/sec"; $data[] = "Estimated finish: ".my_clock(round(((($mdResyncDt*(($mdResync-$mdResyncPos)/($mdResyncDb/100+1)))/100)/60),0)); $data[] = "Sync errors ".($var['mdResyncCorr']==0 ? 'detected: ' : 'corrected: ').$var['sbSyncErrs']; } else { $sbSynced = $var['sbSynced']; $sbSynced2 = $var['sbSynced2']; $sbSyncErrs = $var['sbSyncErrs']; if ($var['sbSyncExit']!=0) { $data[] = "Last check incomplete on ".my_time($sbSynced2).", finding $sbSyncErrs error".($sbSyncErrs==1?'.':'s.'); $data[] = "Error code: ".$var['sbSyncExit']; } elseif ($sbSynced==0) { $data[] = "Parity has not been checked yet"; } elseif ($sbSynced2>0) { if (strstr($var['mdResyncAction'],"recon")) { $data[] = 'Parity or Data is invalid'; } else { $data[] = 'Parity is valid'; } $duration = $sbSynced2 - $sbSynced; $speed = my_scale($var['mdResyncSize']*1024/$duration,$unit,1)." $unit/s"; $data[] = "Last checked on ".my_time($sbSynced2).", finding $sbSyncErrs error".($sbSyncErrs==1?'.':'s.'); $data[] = "Duration: ".my_check($duration,$speed); } } $word = $size==1 ? "" : "including "; $warn = ($error0 || $error3) ? "alert" : (($error1 || $error2) ? "warning" : "normal"); $stat = $warn=="normal" ? "[PASS]" : "[FAIL]"; $info = "Array has $size disk".($size==1 ? "" : "s").($parity ? " ({$word}parity".($cache ? " & cache)" : ")") : ($cache ? " ({$word}cache)" : "")); $message = implode('\n', $data); exec("$notify -s ".escapeshellarg("Notice [$server] - array health report $stat")." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'"); exit(0); ?>