Project

General

Profile

Download (14 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	diag_smart.php
4
*/
5
/* ====================================================================
6
 *  Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7
 *	Copyright (c)  2006 Eric Friesen
8
 *
9
 *  Redistribution and use in source and binary forms, with or without modification,
10
 *  are permitted provided that the following conditions are met:
11
 *
12
 *  1. Redistributions of source code must retain the above copyright notice,
13
 *      this list of conditions and the following disclaimer.
14
 *
15
 *  2. Redistributions in binary form must reproduce the above copyright
16
 *      notice, this list of conditions and the following disclaimer in
17
 *      the documentation and/or other materials provided with the
18
 *      distribution.
19
 *
20
 *  3. All advertising materials mentioning features or use of this software
21
 *      must display the following acknowledgment:
22
 *      "This product includes software developed by the pfSense Project
23
 *       for use in the pfSense software distribution. (http://www.pfsense.org/).
24
 *
25
 *  4. The names "pfSense" and "pfSense Project" must not be used to
26
 *       endorse or promote products derived from this software without
27
 *       prior written permission. For written permission, please contact
28
 *       coreteam@pfsense.org.
29
 *
30
 *  5. Products derived from this software may not be called "pfSense"
31
 *      nor may "pfSense" appear in their names without prior written
32
 *      permission of the Electric Sheep Fencing, LLC.
33
 *
34
 *  6. Redistributions of any form whatsoever must retain the following
35
 *      acknowledgment:
36
 *
37
 *  "This product includes software developed by the pfSense Project
38
 *  for use in the pfSense software distribution (http://www.pfsense.org/).
39
 *
40
 *  THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
 *  EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
52
 *
53
 *  ====================================================================
54
 *
55
 */
56

    
57
##|+PRIV
58
##|*IDENT=page-diagnostics-smart
59
##|*NAME=Diagnostics: S.M.A.R.T. Status
60
##|*DESCR=Allow access to the 'Diagnostics: S.M.A.R.T. Status' page.
61
##|*MATCH=diag_smart.php*
62
##|-PRIV
63

    
64
require_once("guiconfig.inc");
65

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

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

    
72
if ($action != 'config') {
73
	$pgtitle[] = htmlspecialchars(gettext('Information & Tests'));
74
} else {
75
	$pgtitle[] = gettext('Config');
76
}
77
$smartctl = "/usr/local/sbin/smartctl";
78
$smartd = "/usr/local/sbin/smartd";
79
$start_script = "/usr/local/etc/rc.d/smartd.sh";
80

    
81
$valid_test_types = array("offline", "short", "long", "conveyance");
82
$valid_info_types = array("i", "H", "c", "A", "a");
83
$valid_log_types = array("error", "selftest");
84

    
85
include("head.inc");
86

    
87
// Highlights the words "PASSED", "FAILED", and "WARNING".
88
function add_colors($string) {
89
	// To add words keep arrays matched by numbers
90
	$patterns[0] = '/PASSED/';
91
	$patterns[1] = '/FAILED/';
92
	$patterns[2] = '/Warning/';
93
	$replacements[0] = '<span class="text-success">' . gettext("PASSED") . '</span>';
94
	$replacements[1] = '<span class="text-alert">' . gettext("FAILED") . '</span>';
95
	$replacements[2] = '<span class="text-warning">' . gettext("Warning") . '</span>';
96
	ksort($patterns);
97
	ksort($replacements);
98
	return preg_replace($patterns, $replacements, $string);
99
}
100

    
101
// Edits smartd.conf file, adds or removes email for failed disk reporting
102
function update_email($email) {
103
	/* Bail if an e-mail address is invalid */
104
	if (!empty($email) && (filter_var($email, FILTER_VALIDATE_EMAIL) === false)) {
105
		return;
106
	}
107

    
108
	if (!file_exists("/usr/local/etc/smartd.conf") && file_exists("/usr/local/etc/smartd.conf.sample")) {
109
		copy("/usr/local/etc/smartd.conf.sample", "/usr/local/etc/smartd.conf");
110
	}
111
	// Did they pass an email?
112
	if (!empty($email)) {
113
		// Put it in the smartd.conf file
114
		shell_exec("/usr/bin/sed -i .old " . escapeshellarg("s/^DEVICESCAN.*/DEVICESCAN -H -m {$email}/") . " /usr/local/etc/smartd.conf");
115
	} else {
116
		// Remove email flags in smartd.conf
117
		shell_exec("/usr/bin/sed -i .old 's/^DEVICESCAN.*/DEVICESCAN/' /usr/local/etc/smartd.conf");
118
	}
119
}
120

    
121
function smartmonctl($action) {
122
	global $start_script;
123
	shell_exec($start_script . escapeshellarg($action));
124
}
125
$targetdev = basename($_POST['device']);
126

    
127
if (!file_exists('/dev/' . $targetdev)) {
128
	echo gettext("Device does not exist, bailing.");
129
	return;
130
}
131

    
132
$tab_array = array();
133
$tab_array[0] = array(htmlspecialchars(gettext("Information & Tests")), ($action != 'config'), $_SERVER['PHP_SELF'] . "?action=default");
134
$tab_array[1] = array(gettext("Config"), ($action == 'config'), $_SERVER['PHP_SELF'] . "?action=config");
135
display_top_tabs($tab_array);
136

    
137
$specplatform = system_identify_specific_platform();
138
if ($specplatform['name'] == "Hyper-V") {
139
	echo gettext("S.M.A.R.T. is not supported in Hyper-V guests.");
140
	include("foot.inc");
141
	exit;
142
}
143

    
144
switch ($action) {
145
	// Testing devices
146
	case 'test':
147
	{
148
		$test = $_POST['testType'];
149
		if (!in_array($test, $valid_test_types)) {
150
			echo gettext("Invalid test type, bailing.");
151
			return;
152
		}
153

    
154
		$output = add_colors(shell_exec($smartctl . " -t " . escapeshellarg($test) . " /dev/" . escapeshellarg($targetdev)));
155
?>
156
		<div class="panel  panel-default">
157
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Test Results')?></h2></div>
158
			<div class="panel-body">
159
				<pre><?=$output?></pre>
160
			</div>
161
		</div>
162

    
163
		<form action="diag_smart.php" method="post" name="abort">
164
			<input type="hidden" name="device" value="<?=$targetdev?>" />
165
			<input type="hidden" name="action" value="abort" />
166
			<nav class="action-buttons">
167
				<button type="submit" name="submit" class="btn btn-danger" value="<?=gettext("Abort")?>">
168
					<i class="fa fa-times icon-embed-btn"></i>
169
					<?=gettext("Abort Test")?>
170
				</button>
171
				<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
172
					<i class="fa fa-undo icon-embed-btn"></i>
173
					<?=gettext("Back")?>
174
				</a>
175
			</nav>
176
		</form>
177

    
178
<?php
179
		break;
180
	}
181

    
182
	// Info on devices
183
	case 'info':
184
	{
185
		$type = $_POST['type'];
186

    
187
		if (!in_array($type, $valid_info_types)) {
188
			print_info_box(gettext("Invalid info type, bailing."), 'danger');
189
			return;
190
		}
191

    
192
		$output = add_colors(shell_exec($smartctl . " -" . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
193
?>
194
		<div class="panel  panel-default">
195
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Information')?></h2></div>
196
			<div class="panel-body">
197
				<pre><?=$output?></pre>
198
			</div>
199
		</div>
200

    
201
		<nav class="action-buttons">
202
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
203
				<i class="fa fa-undo icon-embed-btn"></i>
204
				<?=gettext("Back")?>
205
			</a>
206
		</nav>
207
<?php
208
		break;
209
	}
210

    
211
	// View logs
212
	case 'logs':
213
	{
214
		$type = $_POST['type'];
215
		if (!in_array($type, $valid_log_types)) {
216
			print_info_box(gettext("Invalid log type, bailing."), 'danger');
217
			return;
218
		}
219

    
220
		$output = add_colors(shell_exec($smartctl . " -l " . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
221
?>
222
		<div class="panel  panel-default">
223
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Logs')?></h2></div>
224
			<div class="panel-body">
225
				<pre><?=$output?></pre>
226
			</div>
227
		</div>
228

    
229
		<nav class="action-buttons">
230
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-info">
231
				<i class="fa fa-undo icon-embed-btn"></i>
232
				<?=gettext("Back")?>
233
			</a>
234
		</nav>
235
<?php
236
		break;
237
	}
238

    
239
	// Abort tests
240
	case 'abort':
241
	{
242
		$output = shell_exec($smartctl . " -X /dev/" . escapeshellarg($targetdev));
243
?>
244
		<div class="panel  panel-default">
245
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Abort')?></h2></div>
246
			<div class="panel-body">
247
				<pre><?=$output?></pre>
248
			</div>
249
		</div>
250
<?php
251
		break;
252
	}
253

    
254
	// Config changes, users email in xml config and write changes to smartd.conf
255
	case 'config':
256
	{
257
		if (isset($_POST['test'])) {
258

    
259
// FIXME				shell_exec($smartd . " -M test -m " . $config['system']['smartmonemail']);
260
			$savemsg = sprintf(gettext("Email sent to %s"), $config['system']['smartmonemail']);
261
			smartmonctl("stop");
262
			smartmonctl("start");
263
			$style = 'warning';
264
		} else if (isset($_POST['save'])) {
265
			if (!empty($_POST['smartmonemail']) && (filter_var($_POST['smartmonemail'], FILTER_VALIDATE_EMAIL) === false)) {
266
				$savemsg = "The supplied e-mail address is invalid.";
267
				$style = 'danger';
268
			} else {
269
				$config['system']['smartmonemail'] = $_POST['smartmonemail'];
270
				write_config();
271
				$retval = 0;
272
				config_lock();
273
				if (stristr($retval, "error") != true) {
274
					$savemsg = get_std_save_message($retval);
275
					$style = 'success';
276
				} else {
277
					$savemsg = $retval;
278
					$style='danger';
279
				}
280
				config_unlock();
281
				// Write the changes to the smartd.conf file
282
				update_email($_POST['smartmonemail']);
283
				// Send sig HUP to smartd, rereads the config file
284
				shell_exec("/usr/bin/killall -HUP smartd");
285
			}
286
		}
287

    
288
	// Was the config changed? if so, print the message
289
	if ($savemsg) {
290
		print_info_box($savemsg, $style);
291
	}
292

    
293
	// Get users email from the xml file
294
	$pconfig['smartmonemail'] = $config['system']['smartmonemail'];
295

    
296
	$form = new Form();
297

    
298
	$section = new Form_Section('Configuration');
299

    
300
	$section->addInput(new Form_Input(
301
		'smartmonemail',
302
		'Email Address',
303
		'text',
304
		$pconfig['smartmonemail']
305
	 ));
306

    
307
	$form->add($section);
308

    
309
	if (!empty($pconfig['smartmonemail'])) {
310
		$form->addGlobal(new Form_Button(
311
			'test',
312
			'Send test email',
313
			null,
314
			'fa-send'
315
		))->addClass('btn-info');
316
	}
317

    
318
	print($form);
319

    
320
	break;
321
	}
322

    
323
	// Default page, prints the forms to view info, test, etc...
324
	default: {
325
// Information
326
		$devs = get_smart_drive_list();
327

    
328
		$form = new Form(false);
329

    
330
		$btnview = new Form_Button(
331
			'submit',
332
			'View',
333
			null,
334
			'fa-file-text-o'
335
		);
336
		$btnview->addClass('btn-primary');
337
		$btnview->setAttribute('id');
338

    
339
		$section = new Form_Section('Information');
340

    
341
		$section->addInput(new Form_Input(
342
			'action',
343
			null,
344
			'hidden',
345
			'info'
346
		))->setAttribute('id');
347

    
348
		$group = new Form_Group('Info type');
349

    
350
		$group->add(new Form_Checkbox(
351
			'type',
352
			null,
353
			'Info',
354
			false,
355
			'i'
356
		))->displayAsRadio();
357

    
358
		$group->add(new Form_Checkbox(
359
			'type',
360
			null,
361
			'Health',
362
			true,
363
			'H'
364
		))->displayAsRadio();
365

    
366
		$group->add(new Form_Checkbox(
367
			'type',
368
			null,
369
			'S.M.A.R.T. Capabilities',
370
			false,
371
			'c'
372
		))->displayAsRadio();
373

    
374
		$group->add(new Form_Checkbox(
375
			'type',
376
			null,
377
			'Attributes',
378
			false,
379
			'A'
380
		))->displayAsRadio();
381

    
382
		$group->add(new Form_Checkbox(
383
			'type',
384
			null,
385
			'All',
386
			false,
387
			'a'
388
		))->displayAsRadio();
389

    
390
		$section->add($group);
391

    
392
		$section->addInput(new Form_Select(
393
			'device',
394
			'Device: /dev/',
395
			false,
396
			array_combine($devs, $devs)
397
		))->setAttribute('id');
398

    
399
		$section->addInput(new Form_StaticText(
400
			'',
401
			$btnview
402
		));
403

    
404
		$form->add($section);
405
		print($form);
406

    
407
// Tests
408
		$form = new Form(false);
409

    
410
		$btntest = new Form_Button(
411
			'submit',
412
			'Test',
413
			null,
414
			'fa-wrench'
415
		);
416
		$btntest->addClass('btn-primary');
417
		$btntest->setAttribute('id');
418

    
419
		$section = new Form_Section('Perform self-tests');
420

    
421
		$section->addInput(new Form_Input(
422
			'action',
423
			null,
424
			'hidden',
425
			'test'
426
		))->setAttribute('id');
427

    
428
		$group = new Form_Group('Test type');
429

    
430
		$group->add(new Form_Checkbox(
431
			'testType',
432
			null,
433
			'Offline',
434
			false,
435
			'offline'
436
		))->displayAsRadio();
437

    
438
		$group->add(new Form_Checkbox(
439
			'testType',
440
			null,
441
			'Short',
442
			true,
443
			'short'
444
		))->displayAsRadio();
445

    
446
		$group->add(new Form_Checkbox(
447
			'testType',
448
			null,
449
			'Long',
450
			false,
451
			'long'
452
		))->displayAsRadio();
453

    
454
		$group->add(new Form_Checkbox(
455
			'testType',
456
			null,
457
			'Conveyance',
458
			false,
459
			'conveyance'
460
		))->displayAsRadio();
461

    
462
		$group->setHelp('Select "Conveyance" for ATA disks only.');
463
		$section->add($group);
464

    
465
		$section->addInput(new Form_Select(
466
			'device',
467
			'Device: /dev/',
468
			false,
469
			array_combine($devs, $devs)
470
		))->setAttribute('id');
471

    
472
		$section->addInput(new Form_StaticText(
473
			'',
474
			$btntest
475
		));
476

    
477
		$form->add($section);
478
		print($form);
479

    
480
// Logs
481
		$form = new Form(false);
482

    
483
		$btnview =  new Form_Button(
484
			'submit',
485
			'View',
486
			null,
487
			'fa-file-text-o'
488
		);
489
		$btnview->addClass('btn-primary');
490
		$btnview->setAttribute('id');
491

    
492
		$section = new Form_Section('View Logs');
493

    
494
		$section->addInput(new Form_Input(
495
			'action',
496
			null,
497
			'hidden',
498
			'logs'
499
		))->setAttribute('id');
500

    
501
		$group = new Form_Group('Log type');
502

    
503
		$group->add(new Form_Checkbox(
504
			'type',
505
			null,
506
			'Error',
507
			true,
508
			'error'
509
		))->displayAsRadio();
510

    
511
		$group->add(new Form_Checkbox(
512
			'type',
513
			null,
514
			'Self-test',
515
			false,
516
			'selftest'
517
		))->displayAsRadio();
518

    
519
		$section->add($group);
520

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

    
528
		$section->addInput(new Form_StaticText(
529
			'',
530
			$btnview
531
		));
532

    
533
		$form->add($section);
534
		print($form);
535

    
536
// Abort
537
		$btnabort = new Form_Button(
538
			'submit',
539
			'Abort',
540
			null,
541
			'fa-times'
542
		);
543

    
544
		$btnabort->addClass('btn-danger')->setAttribute('id');
545

    
546
		$form = new Form(false);
547

    
548
		$section = new Form_Section('Abort');
549

    
550
		$section->addInput(new Form_Input(
551
			'action',
552
			null,
553
			'hidden',
554
			'abort'
555
		))->setAttribute('id');
556

    
557
		$section->addInput(new Form_Select(
558
			'device',
559
			'Device: /dev/',
560
			false,
561
			array_combine($devs, $devs)
562
		))->setAttribute('id');
563

    
564
		$section->addInput(new Form_StaticText(
565
			'',
566
			$btnabort
567
		));
568

    
569
		$form->add($section);
570
		print($form);
571

    
572
		break;
573
	}
574
}
575

    
576
include("foot.inc");
(27-27/225)