Project

General

Profile

Download (12.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * diag_smart.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2006 Eric Friesen
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
##|+PRIV
24
##|*IDENT=page-diagnostics-smart
25
##|*NAME=Diagnostics: S.M.A.R.T. Status
26
##|*DESCR=Allow access to the 'Diagnostics: S.M.A.R.T. Status' page.
27
##|*MATCH=diag_smart.php*
28
##|-PRIV
29

    
30
require_once("guiconfig.inc");
31

    
32
// What page, aka. action is being wanted
33
// If they "get" a page but don't pass all arguments, smartctl will throw an error
34
$action = (isset($_POST['action']) ? $_POST['action'] : $_GET['action']);
35

    
36
$pgtitle = array(gettext("Diagnostics"), gettext("S.M.A.R.T. Status"));
37

    
38
if ($action != 'config') {
39
	$pgtitle[] = htmlspecialchars(gettext('Information & Tests'));
40
} else {
41
	$pgtitle[] = gettext('Config');
42
}
43
$smartctl = "/usr/local/sbin/smartctl";
44
$smartd = "/usr/local/sbin/smartd";
45
$start_script = "/usr/local/etc/rc.d/smartd.sh";
46

    
47
$valid_test_types = array("offline", "short", "long", "conveyance");
48
$valid_info_types = array("i", "H", "c", "A", "a");
49
$valid_log_types = array("error", "selftest");
50

    
51
include("head.inc");
52

    
53
// Highlights the words "PASSED", "FAILED", and "WARNING".
54
function add_colors($string) {
55
	// To add words keep arrays matched by numbers
56
	$patterns[0] = '/PASSED/';
57
	$patterns[1] = '/FAILED/';
58
	$patterns[2] = '/Warning/';
59
	$replacements[0] = '<span class="text-success">' . gettext("PASSED") . '</span>';
60
	$replacements[1] = '<span class="text-alert">' . gettext("FAILED") . '</span>';
61
	$replacements[2] = '<span class="text-warning">' . gettext("Warning") . '</span>';
62
	ksort($patterns);
63
	ksort($replacements);
64
	return preg_replace($patterns, $replacements, $string);
65
}
66

    
67
// Edits smartd.conf file, adds or removes email for failed disk reporting
68
function update_email($email) {
69
	/* Bail if an e-mail address is invalid */
70
	if (!empty($email) && (filter_var($email, FILTER_VALIDATE_EMAIL) === false)) {
71
		return;
72
	}
73

    
74
	if (!file_exists("/usr/local/etc/smartd.conf") && file_exists("/usr/local/etc/smartd.conf.sample")) {
75
		copy("/usr/local/etc/smartd.conf.sample", "/usr/local/etc/smartd.conf");
76
	}
77
	// Did they pass an email?
78
	if (!empty($email)) {
79
		// Put it in the smartd.conf file
80
		shell_exec("/usr/bin/sed -i .old " . escapeshellarg("s/^DEVICESCAN.*/DEVICESCAN -H -m {$email}/") . " /usr/local/etc/smartd.conf");
81
	} else {
82
		// Remove email flags in smartd.conf
83
		shell_exec("/usr/bin/sed -i .old 's/^DEVICESCAN.*/DEVICESCAN/' /usr/local/etc/smartd.conf");
84
	}
85
}
86

    
87
function smartmonctl($action) {
88
	global $start_script;
89
	shell_exec($start_script . escapeshellarg($action));
90
}
91
$targetdev = basename($_POST['device']);
92

    
93
if (!file_exists('/dev/' . $targetdev)) {
94
	echo gettext("Device does not exist, bailing.");
95
	return;
96
}
97

    
98
$tab_array = array();
99
$tab_array[0] = array(htmlspecialchars(gettext("Information & Tests")), ($action != 'config'), $_SERVER['PHP_SELF'] . "?action=default");
100
$tab_array[1] = array(gettext("Config"), ($action == 'config'), $_SERVER['PHP_SELF'] . "?action=config");
101
display_top_tabs($tab_array);
102

    
103
$specplatform = system_identify_specific_platform();
104
if ($specplatform['name'] == "Hyper-V") {
105
	echo gettext("S.M.A.R.T. is not supported in Hyper-V guests.");
106
	include("foot.inc");
107
	exit;
108
}
109

    
110
switch ($action) {
111
	// Testing devices
112
	case 'test':
113
	{
114
		$test = $_POST['testType'];
115
		if (!in_array($test, $valid_test_types)) {
116
			echo gettext("Invalid test type, bailing.");
117
			return;
118
		}
119

    
120
		$output = add_colors(shell_exec($smartctl . " -t " . escapeshellarg($test) . " /dev/" . escapeshellarg($targetdev)));
121
?>
122
		<div class="panel  panel-default">
123
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Test Results')?></h2></div>
124
			<div class="panel-body">
125
				<pre><?=$output?></pre>
126
			</div>
127
		</div>
128

    
129
		<form action="diag_smart.php" method="post" name="abort">
130
			<input type="hidden" name="device" value="<?=$targetdev?>" />
131
			<input type="hidden" name="action" value="abort" />
132
			<nav class="action-buttons">
133
				<button type="submit" name="submit" class="btn btn-danger" value="<?=gettext("Abort")?>">
134
					<i class="fa fa-times icon-embed-btn"></i>
135
					<?=gettext("Abort Test")?>
136
				</button>
137
				<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
138
					<i class="fa fa-undo icon-embed-btn"></i>
139
					<?=gettext("Back")?>
140
				</a>
141
			</nav>
142
		</form>
143

    
144
<?php
145
		break;
146
	}
147

    
148
	// Info on devices
149
	case 'info':
150
	{
151
		$type = $_POST['type'];
152

    
153
		if (!in_array($type, $valid_info_types)) {
154
			print_info_box(gettext("Invalid info type, bailing."), 'danger');
155
			return;
156
		}
157

    
158
		$output = add_colors(shell_exec($smartctl . " -" . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
159
?>
160
		<div class="panel  panel-default">
161
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Information')?></h2></div>
162
			<div class="panel-body">
163
				<pre><?=$output?></pre>
164
			</div>
165
		</div>
166

    
167
		<nav class="action-buttons">
168
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
169
				<i class="fa fa-undo icon-embed-btn"></i>
170
				<?=gettext("Back")?>
171
			</a>
172
		</nav>
173
<?php
174
		break;
175
	}
176

    
177
	// View logs
178
	case 'logs':
179
	{
180
		$type = $_POST['type'];
181
		if (!in_array($type, $valid_log_types)) {
182
			print_info_box(gettext("Invalid log type, bailing."), 'danger');
183
			return;
184
		}
185

    
186
		$output = add_colors(shell_exec($smartctl . " -l " . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
187
?>
188
		<div class="panel  panel-default">
189
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Logs')?></h2></div>
190
			<div class="panel-body">
191
				<pre><?=$output?></pre>
192
			</div>
193
		</div>
194

    
195
		<nav class="action-buttons">
196
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
197
				<i class="fa fa-undo icon-embed-btn"></i>
198
				<?=gettext("Back")?>
199
			</a>
200
		</nav>
201
<?php
202
		break;
203
	}
204

    
205
	// Abort tests
206
	case 'abort':
207
	{
208
		$output = shell_exec($smartctl . " -X /dev/" . escapeshellarg($targetdev));
209
?>
210
		<div class="panel  panel-default">
211
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Abort')?></h2></div>
212
			<div class="panel-body">
213
				<pre><?=$output?></pre>
214
			</div>
215
		</div>
216
<?php
217
		break;
218
	}
219

    
220
	// Config changes, users email in xml config and write changes to smartd.conf
221
	case 'config':
222
	{
223
		if (isset($_POST['test'])) {
224

    
225
// FIXME				shell_exec($smartd . " -M test -m " . $config['system']['smartmonemail']);
226
			$savemsg = sprintf(gettext("Email sent to %s"), $config['system']['smartmonemail']);
227
			smartmonctl("stop");
228
			smartmonctl("start");
229
			$style = 'warning';
230
		} else if (isset($_POST['save'])) {
231
			if (!empty($_POST['smartmonemail']) && (filter_var($_POST['smartmonemail'], FILTER_VALIDATE_EMAIL) === false)) {
232
				$savemsg = "The supplied e-mail address is invalid.";
233
				$style = 'danger';
234
			} else {
235
				$config['system']['smartmonemail'] = $_POST['smartmonemail'];
236
				write_config();
237
				$retval = 0;
238
				config_lock();
239
				if (stristr($retval, "error") != true) {
240
					$savemsg = get_std_save_message($retval);
241
					$style = 'success';
242
				} else {
243
					$savemsg = $retval;
244
					$style='danger';
245
				}
246
				config_unlock();
247
				// Write the changes to the smartd.conf file
248
				update_email($_POST['smartmonemail']);
249
				// Send sig HUP to smartd, rereads the config file
250
				shell_exec("/usr/bin/killall -HUP smartd");
251
			}
252
		}
253

    
254
	// Was the config changed? if so, print the message
255
	if ($savemsg) {
256
		print_info_box($savemsg, $style);
257
	}
258

    
259
	// Get users email from the xml file
260
	$pconfig['smartmonemail'] = $config['system']['smartmonemail'];
261

    
262
	$form = new Form();
263

    
264
	$section = new Form_Section('Configuration');
265

    
266
	$section->addInput(new Form_Input(
267
		'smartmonemail',
268
		'Email Address',
269
		'text',
270
		$pconfig['smartmonemail']
271
	 ));
272

    
273
	$form->add($section);
274

    
275
	if (!empty($pconfig['smartmonemail'])) {
276
		$form->addGlobal(new Form_Button(
277
			'test',
278
			'Send test email',
279
			null,
280
			'fa-send'
281
		))->addClass('btn-info');
282
	}
283

    
284
	print($form);
285

    
286
	break;
287
	}
288

    
289
	// Default page, prints the forms to view info, test, etc...
290
	default: {
291
// Information
292
		$devs = get_smart_drive_list();
293

    
294
		$form = new Form(false);
295

    
296
		$btnview = new Form_Button(
297
			'submit',
298
			'View',
299
			null,
300
			'fa-file-text-o'
301
		);
302
		$btnview->addClass('btn-primary');
303
		$btnview->setAttribute('id');
304

    
305
		$section = new Form_Section('Information');
306

    
307
		$section->addInput(new Form_Input(
308
			'action',
309
			null,
310
			'hidden',
311
			'info'
312
		))->setAttribute('id');
313

    
314
		$group = new Form_Group('Info type');
315

    
316
		$group->add(new Form_Checkbox(
317
			'type',
318
			null,
319
			'Info',
320
			false,
321
			'i'
322
		))->displayAsRadio();
323

    
324
		$group->add(new Form_Checkbox(
325
			'type',
326
			null,
327
			'Health',
328
			true,
329
			'H'
330
		))->displayAsRadio();
331

    
332
		$group->add(new Form_Checkbox(
333
			'type',
334
			null,
335
			'S.M.A.R.T. Capabilities',
336
			false,
337
			'c'
338
		))->displayAsRadio();
339

    
340
		$group->add(new Form_Checkbox(
341
			'type',
342
			null,
343
			'Attributes',
344
			false,
345
			'A'
346
		))->displayAsRadio();
347

    
348
		$group->add(new Form_Checkbox(
349
			'type',
350
			null,
351
			'All',
352
			false,
353
			'a'
354
		))->displayAsRadio();
355

    
356
		$section->add($group);
357

    
358
		$section->addInput(new Form_Select(
359
			'device',
360
			'Device: /dev/',
361
			false,
362
			array_combine($devs, $devs)
363
		))->setAttribute('id');
364

    
365
		$section->addInput(new Form_StaticText(
366
			'',
367
			$btnview
368
		));
369

    
370
		$form->add($section);
371
		print($form);
372

    
373
// Tests
374
		$form = new Form(false);
375

    
376
		$btntest = new Form_Button(
377
			'submit',
378
			'Test',
379
			null,
380
			'fa-wrench'
381
		);
382
		$btntest->addClass('btn-primary');
383
		$btntest->setAttribute('id');
384

    
385
		$section = new Form_Section('Perform self-tests');
386

    
387
		$section->addInput(new Form_Input(
388
			'action',
389
			null,
390
			'hidden',
391
			'test'
392
		))->setAttribute('id');
393

    
394
		$group = new Form_Group('Test type');
395

    
396
		$group->add(new Form_Checkbox(
397
			'testType',
398
			null,
399
			'Offline',
400
			false,
401
			'offline'
402
		))->displayAsRadio();
403

    
404
		$group->add(new Form_Checkbox(
405
			'testType',
406
			null,
407
			'Short',
408
			true,
409
			'short'
410
		))->displayAsRadio();
411

    
412
		$group->add(new Form_Checkbox(
413
			'testType',
414
			null,
415
			'Long',
416
			false,
417
			'long'
418
		))->displayAsRadio();
419

    
420
		$group->add(new Form_Checkbox(
421
			'testType',
422
			null,
423
			'Conveyance',
424
			false,
425
			'conveyance'
426
		))->displayAsRadio();
427

    
428
		$group->setHelp('Select "Conveyance" for ATA disks only.');
429
		$section->add($group);
430

    
431
		$section->addInput(new Form_Select(
432
			'device',
433
			'Device: /dev/',
434
			false,
435
			array_combine($devs, $devs)
436
		))->setAttribute('id');
437

    
438
		$section->addInput(new Form_StaticText(
439
			'',
440
			$btntest
441
		));
442

    
443
		$form->add($section);
444
		print($form);
445

    
446
// Logs
447
		$form = new Form(false);
448

    
449
		$btnview =  new Form_Button(
450
			'submit',
451
			'View',
452
			null,
453
			'fa-file-text-o'
454
		);
455
		$btnview->addClass('btn-primary');
456
		$btnview->setAttribute('id');
457

    
458
		$section = new Form_Section('View Logs');
459

    
460
		$section->addInput(new Form_Input(
461
			'action',
462
			null,
463
			'hidden',
464
			'logs'
465
		))->setAttribute('id');
466

    
467
		$group = new Form_Group('Log type');
468

    
469
		$group->add(new Form_Checkbox(
470
			'type',
471
			null,
472
			'Error',
473
			true,
474
			'error'
475
		))->displayAsRadio();
476

    
477
		$group->add(new Form_Checkbox(
478
			'type',
479
			null,
480
			'Self-test',
481
			false,
482
			'selftest'
483
		))->displayAsRadio();
484

    
485
		$section->add($group);
486

    
487
		$section->addInput(new Form_Select(
488
			'device',
489
			'Device: /dev/',
490
			false,
491
			array_combine($devs, $devs)
492
		))->setAttribute('id');
493

    
494
		$section->addInput(new Form_StaticText(
495
			'',
496
			$btnview
497
		));
498

    
499
		$form->add($section);
500
		print($form);
501

    
502
// Abort
503
		$btnabort = new Form_Button(
504
			'submit',
505
			'Abort',
506
			null,
507
			'fa-times'
508
		);
509

    
510
		$btnabort->addClass('btn-danger')->setAttribute('id');
511

    
512
		$form = new Form(false);
513

    
514
		$section = new Form_Section('Abort');
515

    
516
		$section->addInput(new Form_Input(
517
			'action',
518
			null,
519
			'hidden',
520
			'abort'
521
		))->setAttribute('id');
522

    
523
		$section->addInput(new Form_Select(
524
			'device',
525
			'Device: /dev/',
526
			false,
527
			array_combine($devs, $devs)
528
		))->setAttribute('id');
529

    
530
		$section->addInput(new Form_StaticText(
531
			'',
532
			$btnabort
533
		));
534

    
535
		$form->add($section);
536
		print($form);
537

    
538
		break;
539
	}
540
}
541

    
542
include("foot.inc");
(25-25/225)