$device){ // $match=true; // print "\n".Str_Repeat('*',30); print "\n*** Entry: {$name}"; print "\nPath={$device['path']}; Type={$device['device']}"; // $device_safe=EscapeShellArg($device['device']); $path_safe=EscapeShellArg($device['path']); // If the path doesn't exist, possibly fail Exec("[ -e {$path_safe} ]", $output_lines, $return_code); if($return_code!=0){ print "\nPath does not exist!"; if($device['bRequired']){ DoError("Path doesn't exist but was required: {$device['path']}"); } print "\n"; continue; } // Is this even a block device? Exec("[ -b {$path_safe} ]", $output_lines, $return_code); if($return_code!=0){ DoError("Path doesn't seem to point to a block device?"); continue; } // Ask smartctl for status $command="smartctl --all --device {$device_safe} {$path_safe}"; $output_lines=false; Exec($command,$output_lines,$smart_return_code); $lines=Implode("\n",$output_lines); // Output any messages indicated by smartctl $messages=CheckNamedBits($smart_return_code); foreach($messages as $message){ print "\nMESSAGE: {$message}"; } // Test Status: if(Preg_Match('@^Self-test execution status.+?(?P[0-9]+\% of test remaining)\.@smi',$lines,$match)){ print "\n{$match['remainder']}"; } else if(Preg_Match('@^Self-test execution status.+?(completed\s+without\s+error)@smi',$lines,$match)){ // print "\nNo test seems to be running"; // Start short test? if($bStartTests_short){ print "; Will start short test now!\n"; Exec("smartctl --test=short --device {$device_safe} {$path_safe}"); continue; } // Start long test? else if($bStartTests_long){ print "; Will start long test now!\n"; Exec("smartctl --test=long --device {$device_safe} {$path_safe}"); continue; } } else{ DoError("Could not locate execution status information"); } // Check for terrible states if(CheckBitPosition($smart_return_code,3)){ $error_message=Str_Repeat('!',10)." ".Str_Repeat('*',10)." CATASTROPHY WARNING!!! DISK IS FAILING ".Str_Repeat('*',10)." ".Str_Repeat('!',10); DoError($error_message); } if(CheckBitPosition($smart_return_code,4)){ $error_message=Str_Repeat('!',10)." ".Str_Repeat('*',10)." DISK IS IN PREFAIL STATE ".Str_Repeat('*',10)." ".Str_Repeat('!',10); DoError($error_message); } // print "\n"; } // function LoadConfig($config_path) { // $config=Array( 'global'=>Array(), 'devices'=>Array() ); // Load config $ini=Parse_Ini_File($config_path,true); if(!$ini){ DoError("Unable to parse config file: {$config_path}"); } // Booleans foreach($ini as $section_name=>&$section){ foreach($section as $key=>&$value){ // $v=StrToLower($value); switch($v) { // case 'true': case '1': case 'on': case 'yes': $value=true; break; // case 'false': case '0': case 'off': case 'no': $value=false; break; } }Unset($value); }Unset($section); // Pull out global config if(IsSet($ini['global'])){ $config['global']=$ini['global']; Unset($ini['global']); } // The remainder are devices $config['devices']=$ini; return $config; } // function CheckNamedBits($return_code) { // $messages=Array(); // $map=Array( '0'=>"Command line did not parse.", '1'=>"Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode", '2'=>"Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure", '3'=>"SMART status check returned \"DISK FAILING\".", '4'=>"We found prefail Attributes <= threshold.", '5'=>"SMART status check returned \"DISK OK\" but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past.", '6'=>"The device error log contains records of errors.", '7'=>"The device self-test log contains records of errors. [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored." ); // foreach($map as $bitIndex=>$message){ if(CheckBitPosition($return_code,$bitIndex)){ $messages[]=$message; } } return $messages; } // function CheckBitPosition($toCheck,$index) { // $value=Pow(2,$index); // $bIsSet=false; if($toCheck == ($toCheck|$value)){ $bIsSet=true; } // //print "\n toCheck=$toCheck, index=$index, value=$value, IsSet=".($bIsSet?'true':'false'); return $bIsSet; } // function DoError($message) { //print "\nError: {$message}"; LogError($message); MailError($message); } // function LogError($message) { // $prefix="[".(BaseName(__FILE__))."] "; // $stderr = fOpen('php://stderr', 'w'); fWrite($stderr,"\n{$message}"); fClose($stderr); // $message_safe=EscapeShellArg("{$prefix}{$message}"); Shell_Exec("logger {$message_safe}"); } // function MailError($message) { // global $config; // $hostname=Shell_Exec("hostname"); // if(!IsSet($config['global']['mailtos'])){ return false; } $mailtos=Explode(",",$config['global']['mailtos']); // foreach($mailtos as $mailto){ // $mailto=Trim($mailto); // if(Filter_Var($mailto,FILTER_VALIDATE_EMAIL)===FALSE){ LogError("This doesn't seem to be a valid email address: {$mailto}"); continue; } if(!mail( $mailto, "{$hostname} - smartctl error", $message )) { LogError("PHP failed to send email to {$mailto}, for some reason"); } } } ?> Done