Subversion Repositories ALCASAR

Rev

Go to most recent revision | Details | Last modification | View Log

Rev Author Line No. Line
2780 rexy 1
<?php
2
/**
3
 * SMART plugin, which displays all SMART informations available
4
 *
5
 * @category  PHP
6
 * @package   PSI_Plugin_SMART
7
 * @author    Antoine Bertin <diaoulael@users.sourceforge.net>
8
 * @copyright 2009 phpSysInfo
9
 * @license   http://opensource.org/licenses/gpl-2.0.php GNU General Public License version 2, or (at your option) any later version
10
 * @version   Release: 3.0
11
 * @link      http://phpsysinfo.sourceforge.net
12
 */
13
class SMART extends PSI_Plugin
14
{
15
    /**
16
     * variable, which holds the content of the command
17
     * @var array
18
     */
19
    private $_filecontent = array();
20
 
21
    /**
22
     * variable, which holds the result before the xml is generated out of this array
23
     * @var array
24
     */
25
    private $_result = array();
26
 
27
    /**
28
     * variable, which holds PSI_PLUGIN_SMART_IDS well formated datas
29
     * @var array
30
     */
31
    private $_ids = array();
32
 
33
    /**
34
     * read the data into an internal array and also call the parent constructor
35
     *
36
     * @param String $enc target encoding
37
     */
38
    public function __construct($enc)
39
    {
40
        parent::__construct(__CLASS__, $enc);
41
        switch (strtolower(PSI_PLUGIN_SMART_ACCESS)) {
42
            case 'wmi':
43
            case 'command':
44
            case 'data':
45
                if (defined('PSI_PLUGIN_SMART_DEVICES') && is_string(PSI_PLUGIN_SMART_DEVICES)) {
46
                    if (preg_match(ARRAY_EXP, PSI_PLUGIN_SMART_DEVICES)) {
47
                        $disks = eval(PSI_PLUGIN_SMART_DEVICES);
48
                    } else {
49
                        $disks = array(PSI_PLUGIN_SMART_DEVICES);
50
                    }
51
                    if (defined('PSI_PLUGIN_SMART_IDS') && is_string(PSI_PLUGIN_SMART_IDS)) {
52
                        if (preg_match(ARRAY_EXP, PSI_PLUGIN_SMART_IDS)) {
53
                            $fullIds = eval(PSI_PLUGIN_SMART_IDS);
54
                        } else {
55
                            $fullIds = array(PSI_PLUGIN_SMART_IDS);
56
                        }
57
                        foreach ($fullIds as $fullId) {
58
                            $arrFullId = preg_split('/-/', $fullId);
59
                            $this->_ids[intval($arrFullId[0])] = strtolower($arrFullId[1]);
60
                            if (!empty($arrFullId[2]))
61
                                $this->_ids[intval($arrFullId[2])] = "#replace-".intval($arrFullId[0]);
62
                        }
63
                    }
64
                }
65
                break;
66
            default:
67
                $this->global_error->addConfigError("__construct()", "[smart] ACCESS");
68
                break;
69
        }
70
 
71
        switch (strtolower(PSI_PLUGIN_SMART_ACCESS)) {
72
            case 'wmi':
73
                if (PSI_OS == 'WINNT') {
74
                    $asd_wmi = null;
75
                    try {
76
                        $objLocator = new COM('WbemScripting.SWbemLocator');
77
                        $wmi = $objLocator->ConnectServer('', 'root\wmi');
78
                        $asd_wmi = CommonFunctions::getWMI($wmi, 'MSStorageDriver_ATAPISmartData', array('VendorSpecific'));
79
                    } catch (Exception $e) {
80
                    }
81
                    foreach ($asd_wmi as $_nr=>$asd) {
82
                        $_name = "/dev/sd".chr(97+$_nr);
83
                        if (array_search($_name, $disks) !== false) {
84
                            $this->_filecontent[$_name] = "\nVendor Specific SMART Attributes with Thresholds\n";
85
                            $this->_filecontent[$_name] .= "ID# _ATTRIBUTE_NAME_ FLAG VALUE WORST RAW_VALUE\n";
86
                            $asdvs = $asd['VendorSpecific'];
87
                            for ($c = 2; $c < count($asdvs); $c += 12) {
88
                                //Attribute values 0x00, 0xff are invalid
89
                                $id = $asdvs[$c];
90
                                if (($id != 0) && ($id != 255)) {
91
                                    switch ($id) {
92
                                        case 3:
93
                                            //raw16(avg16)
94
                                            $this->_filecontent[$_name] .= $id." ID".$id." 0x".substr("0".dechex($asdvs[$c+2]),-2).substr("0".dechex($asdvs[$c+1]),-2)." ".substr("00".$asdvs[$c+3],-3)." ".substr("00".$asdvs[$c+4],-3)." ".($asdvs[$c+5]+256*$asdvs[$c+6])."\n";
95
                                            break;
96
                                        case 5:
97
                                        case 196:
98
                                            //raw16(raw16)
99
                                            $this->_filecontent[$_name] .= $id." ID".$id." 0x".substr("0".dechex($asdvs[$c+2]),-2).substr("0".dechex($asdvs[$c+1]),-2)." ".substr("00".$asdvs[$c+3],-3)." ".substr("00".$asdvs[$c+4],-3)." ".($asdvs[$c+5]+256*$asdvs[$c+6])."\n";
100
                                            break;
101
                                        case 9:
102
                                        case 240:
103
                                            //raw24(raw8)
104
                                            $this->_filecontent[$_name] .= $id." ID".$id." 0x".substr("0".dechex($asdvs[$c+2]),-2).substr("0".dechex($asdvs[$c+1]),-2)." ".substr("00".$asdvs[$c+3],-3)." ".substr("00".$asdvs[$c+4],-3)." ".($asdvs[$c+5]+256*$asdvs[$c+6]+65536*$asdvs[$c+7])."\n";
105
                                            break;
106
                                        case 190:
107
                                        case 194:
108
                                            //tempminmax
109
                                            $this->_filecontent[$_name] .= $id." ID".$id." 0x".substr("0".dechex($asdvs[$c+2]),-2).substr("0".dechex($asdvs[$c+1]),-2)." ".substr("00".$asdvs[$c+3],-3)." ".substr("00".$asdvs[$c+4],-3)." ".($asdvs[$c+5]+256*$asdvs[$c+6])."\n";
110
                                            break;
111
                                        default:
112
                                            //raw48
113
                                            $this->_filecontent[$_name] .= $id." ID".$id." 0x".substr("0".dechex($asdvs[$c+2]),-2).substr("0".dechex($asdvs[$c+1]),-2)." ".substr("00".$asdvs[$c+3],-3)." ".substr("00".$asdvs[$c+4],-3)." ".($asdvs[$c+5]+256*$asdvs[$c+6]+65536*$asdvs[$c+7]+16777216*$asdvs[$c+8])."\n";
114
                                            break;
115
                                    }
116
                                }
117
                            }
118
                            $this->_filecontent[$_name] .= "SMART Error Log Version";
119
                        }
120
                    }
121
                }
122
                break;
123
            case 'command':
124
                foreach ($disks as $disk) {
125
                    if (trim($disk) != "") {
126
                        $diskdev = "";
127
                        if (preg_match("/\s*\(([^\(\(]*)\)\s*(.*)/", $disk, $devdisk)) {
128
                            $diskname = trim($devdisk[2]);
129
                            if (trim($devdisk[1]) != "") {
130
                                $diskdev = "--device ".preg_replace('/\./', ',', trim($devdisk[1]));
131
                            }
132
                        } else {
133
                            $diskname = trim($disk);
134
                        }
135
                        $buffer = "";
136
                        if (trim($diskname != "") && (CommonFunctions::executeProgram('smartctl', '--all'.' '.$diskdev.' '.$diskname, $buffer, PSI_DEBUG))) {
137
                            $this->_filecontent[trim($disk)] = $buffer;
138
                        }
139
                    }
140
                }
141
                break;
142
            case 'data':
143
                $dn=0;
144
                foreach ($disks as $disk) {
145
                    $buffer="";
146
                    if (CommonFunctions::rfts(PSI_APP_ROOT."/data/smart{$dn}.txt", $buffer) && !empty($buffer)) {
147
                        $this->_filecontent[$disk] = $buffer;
148
                    }
149
                    $dn++;
150
                }
151
                break;
152
        }
153
    }
154
 
155
    /**
156
     * doing all tasks to get the required informations that the plugin needs
157
     * result is stored in an internal array
158
     *
159
     * @return void
160
     */
161
    public function execute()
162
    {
163
        if (empty($this->_filecontent) || empty($this->_ids)) {
164
            return;
165
        }
166
        foreach ($this->_filecontent as $disk=>$result) {
167
            // set the start and end offset in the result string at the beginning and end respectively
168
            // just in case we don't find the two strings, so that it still works as expected.
169
            $startIndex = 0;
170
            $endIndex = 0;
171
            $vendorInfos = "";
172
 
173
            // locate the beginning string offset for the attributes
174
            if (preg_match('/(Vendor Specific SMART Attributes with Thresholds)/', $result, $matches, PREG_OFFSET_CAPTURE))
175
               $startIndex = $matches[0][1];
176
 
177
            // locate the end string offset for the attributes, this is usually right before string "SMART Error Log Version" or "SMART Error Log not supported" or "Error SMART Error Log Read failed" (hopefully every output has it!)
178
            if (preg_match('/(SMART Error Log Version)|(SMART Error Log not supported)|(Error SMART Error Log Read failed)/', $result, $matches, PREG_OFFSET_CAPTURE))
179
               $endIndex = $matches[0][1];
180
 
181
            if ($startIndex && $endIndex && ($endIndex>$startIndex))
182
                 $vendorInfos = preg_split("/\n/", substr($result, $startIndex, $endIndex - $startIndex));
183
 
184
            if (!empty($vendorInfos)) {
185
                $labels = preg_split('/\s+/', $vendorInfos[1]);
186
                foreach ($labels as $k=>$v) {
187
                    $labels[$k] = str_replace('#', '', strtolower($v));
188
                }
189
                $i = 0; // Line number
190
                foreach ($vendorInfos as $line) {
191
                    $line = preg_replace('/^\s+/', '', $line);
192
                    $values = preg_split('/\s+/', $line);
193
                    if (count($values) > count($labels)) {
194
                        $values = array_slice($values, 0, count($labels), true);
195
                    }
196
                    $j = 0;
197
                    $found = false;
198
                    foreach ($values as $value) {
199
                        if ((in_array($value, array_keys($this->_ids)) && $labels[$j] == 'id')) {
200
                          $arrFullVa = preg_split('/-/', $this->_ids[$value]);
201
                          if (($arrFullVa[0]=="#replace") && !empty($arrFullVa[1]))
202
                              $value=$arrFullVa[1];
203
                        }
204
                        if (((in_array($value, array_keys($this->_ids)) && $labels[$j] == 'id') || ($found && (in_array($labels[$j], array_values($this->_ids)))) || ($found && $labels[$j] == 'attribute_name'))) {
205
                            $this->_result[$disk][$i][$labels[$j]] = $value;
206
                            $found = true;
207
                        }
208
                        $j++;
209
                    }
210
                    $i++;
211
                }
212
            } else {
213
                //SCSI and MVMe devices
214
                if (!empty($this->_ids[1]) && ($this->_ids[1]=="raw_value")) {
215
                    if (preg_match('/\nread\: (.*)\n/', $result, $lines)) {
216
                        $values=preg_split('/ +/', $lines[0]);
217
                        if (!empty($values) && ($values[7]!=null)) {
218
                            $this->_result[$disk][0]['id'] = 1;
219
                            $this->_result[$disk][0]['attribute_name'] = "Raw_Read_Error_Rate";
220
                            $this->_result[$disk][0]['raw_value'] = trim($values[7]);
221
                        }
222
                    } elseif (preg_match('/\Media and Data Integrity Errors\: (.*)\n/', $result, $lines)) {
223
                        $values=preg_split('/ +/', $lines[0]);
224
                        if (!empty($values) && ($values[5]!=null)) {
225
                            $vals=preg_replace('/,/', '', trim($values[5]));
226
                            $this->_result[$disk][0]['id'] = 1;
227
                            $this->_result[$disk][0]['attribute_name'] = "Raw_Read_Error_Rate";
228
                            $this->_result[$disk][0]['raw_value'] = $vals;
229
                        }
230
                    }
231
                }
232
                if (!empty($this->_ids[5]) && ($this->_ids[5]=="raw_value")) {
233
                    if (preg_match('/\nElements in grown defect list\: (.*)\n/', $result, $lines)) {
234
                        $values=preg_split('/ +/', $lines[0]);
235
                        if (!empty($values) && ($values[5]!=null)) {
236
                            $this->_result[$disk][1]['id'] = 5;
237
                            $this->_result[$disk][1]['attribute_name'] = "Reallocated_Sector_Ct";
238
                            $this->_result[$disk][1]['raw_value'] = trim($values[5]);
239
                        }
240
                    }
241
                }
242
                if (!empty($this->_ids[9]) && ($this->_ids[9]=="raw_value")) {
243
                    if (preg_match('/\n +number of hours powered up = (.*)\n/', $result, $lines)) {
244
                        $values=preg_split('/ +/', $lines[0]);
245
                        if (!empty($values) && ($values[7]!=null)) {
246
                            $vals=preg_split('/[,\.]/', trim($values[7]));
247
                            $this->_result[$disk][2]['id'] = 9;
248
                            $this->_result[$disk][2]['attribute_name'] = "Power_On_Hours";
249
                            $this->_result[$disk][2]['raw_value'] =  $vals[0];
250
                        }
251
                    } elseif (preg_match('/\nPower On Hours\: (.*)\n/', $result, $lines)) {
252
                        $values=preg_split('/ +/', $lines[0]);
253
                        if (!empty($values) && ($values[3]!=null)) {
254
                            $vals=preg_replace('/,/', '', trim($values[3]));
255
                            $this->_result[$disk][2]['id'] = 9;
256
                            $this->_result[$disk][2]['attribute_name'] = "Power_On_Hours";
257
                            $this->_result[$disk][2]['raw_value'] =  $vals;
258
                        }
259
                    }
260
                }
261
                if (!empty($this->_ids[194]) && ($this->_ids[194]=="raw_value")) {
262
                    if (preg_match('/\nCurrent Drive Temperature\: (.*)\n/', $result, $lines)) {
263
                        $values=preg_split('/ +/', $lines[0]);
264
                        if (!empty($values) && ($values[3]!=null)) {
265
                            $this->_result[$disk][3]['id'] = 194;
266
                            $this->_result[$disk][3]['attribute_name'] = "Temperature_Celsius";
267
                            $this->_result[$disk][3]['raw_value'] = trim($values[3]);
268
                        }
269
                    } elseif (preg_match('/\nTemperature\: (.*) Celsius/', $result, $lines)) {
270
                        $values=preg_split('/ +/', $lines[0]);
271
                        if (!empty($values) && ($values[1]!=null)) {
272
                            $this->_result[$disk][3]['id'] = 194;
273
                            $this->_result[$disk][3]['attribute_name'] = "Temperature_Celsius";
274
                            $this->_result[$disk][3]['raw_value'] = trim($values[1]);
275
                        }
276
                    }
277
                }
278
                if (!empty($this->_ids[12]) && ($this->_ids[12]=="raw_value")) {
279
                    if (preg_match('/\nPower Cycles\: (.*)\n/', $result, $lines)) {
280
                        $values=preg_split('/ +/', $lines[0]);
281
                        if (!empty($values) && ($values[2]!=null)) {
282
                            $vals=preg_replace('/,/', '', trim($values[2]));
283
                            $this->_result[$disk][4]['id'] = 12;
284
                            $this->_result[$disk][4]['attribute_name'] = "Power_Cycle_Count";
285
                            $this->_result[$disk][4]['raw_value'] = $vals;
286
                        }
287
                    }
288
                }
289
                if (!empty($this->_ids[192]) && ($this->_ids[192]=="raw_value")) {
290
                    if (preg_match('/\nUnsafe Shutdowns\: (.*)\n/', $result, $lines)) {
291
                        $values=preg_split('/ +/', $lines[0]);
292
                        if (!empty($values) && ($values[2]!=null)) {
293
                            $vals=preg_replace('/,/', '', trim($values[2]));
294
                            $this->_result[$disk][5]['id'] = 192;
295
                            $this->_result[$disk][5]['attribute_name'] = "Unsafe_Shutdown_Count";
296
                            $this->_result[$disk][5]['raw_value'] = $vals;
297
                        }
298
                    }
299
                }
300
            }
301
        }
302
        //Usage test
303
        $newIds = array();
304
        foreach ($this->_ids as $id=>$column_name) {
305
            $found = 0;
306
            foreach ($this->_result as $diskName=>$diskInfos) {
307
                if ($found!=2) foreach ($diskInfos as $lineInfos) {
308
                    if ($found!=2) {
309
                        $found = 0;
310
                        foreach ($lineInfos as $label=>$value) {
311
                            if (($found==0) && ($label=="id") && ($value==$id))
312
                                $found = 1;
313
                            if (($found==1) && ($label==$column_name))
314
                                $found = 2;
315
                        }
316
                    }
317
                }
318
            }
319
            if ($found==2) $newIds[$id] = $this->_ids[$id];
320
        }
321
        $this->_ids = $newIds;
322
    }
323
 
324
    /**
325
     * generates the XML content for the plugin
326
     *
327
     * @return SimpleXMLElement entire XML content for the plugin
328
     */
329
    public function xml()
330
    {
331
        if (empty($this->_result) || empty($this->_ids)) {
332
            return $this->xml->getSimpleXmlElement();
333
        }
334
 
335
        $columnsChild = $this->xml->addChild('columns');
336
        // Fill the xml with preferences
337
        foreach ($this->_ids as $id=>$column_name) {
338
            $columnChild = $columnsChild->addChild('column');
339
            $columnChild->addAttribute('id', $id);
340
            $columnChild->addAttribute('name', $column_name);
341
        }
342
 
343
        $disksChild = $this->xml->addChild('disks');
344
        // Now fill the xml with S.M.A.R.T datas
345
        foreach ($this->_result as $diskName=>$diskInfos) {
346
            $diskChild = $disksChild->addChild('disk');
347
            $diskChild->addAttribute('name', $diskName);
348
            foreach ($diskInfos as $lineInfos) {
349
                $lineChild = $diskChild->addChild('attribute');
350
 
351
                if (($lineInfos['id'] == 9) && isset($lineInfos['attribute_name']) && ($lineInfos['attribute_name'] !== "Power_On_Hours")) { //Power_On_Hours_and_Msec and Power_On_Seconds
352
                    $lineInfos['attribute_name'] = "Power_On_Hours";
353
                    $raw_value = preg_split("/h/", $lineInfos['raw_value'], -1, PREG_SPLIT_NO_EMPTY);
354
                    $lineInfos['raw_value'] = $raw_value[0];
355
                }
356
 
357
                foreach ($lineInfos as $label=>$value) {
358
                    $lineChild->addAttribute($label, $value);
359
                }
360
            }
361
        }
362
 
363
        return $this->xml->getSimpleXmlElement();
364
    }
365
}