Project

General

Profile

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

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

    
62
require_once("guiconfig.inc");
63

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

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

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

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

    
83
include("head.inc");
84

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

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

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

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

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

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

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

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

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

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

    
176
<?php
177
		break;
178
	}
179

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

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

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

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

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

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

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

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

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

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

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

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

    
294
	$form = new Form();
295

    
296
	$section = new Form_Section('Configuration');
297

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

    
305
	$form->add($section);
306

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

    
316
	print($form);
317

    
318
	break;
319
	}
320

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

    
326
		$form = new Form(false);
327

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

    
337
		$section = new Form_Section('Information');
338

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

    
346
		$group = new Form_Group('Info type');
347

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

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

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

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

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

    
388
		$section->add($group);
389

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

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

    
402
		$form->add($section);
403
		print($form);
404

    
405
// Tests
406
		$form = new Form(false);
407

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

    
417
		$section = new Form_Section('Perform self-tests');
418

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

    
426
		$group = new Form_Group('Test type');
427

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

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

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

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

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

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

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

    
475
		$form->add($section);
476
		print($form);
477

    
478
// Logs
479
		$form = new Form(false);
480

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

    
490
		$section = new Form_Section('View Logs');
491

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

    
499
		$group = new Form_Group('Log type');
500

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

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

    
517
		$section->add($group);
518

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

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

    
531
		$form->add($section);
532
		print($form);
533

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

    
542
		$btnabort->addClass('btn-danger')->setAttribute('id');
543

    
544
		$form = new Form(false);
545

    
546
		$section = new Form_Section('Abort');
547

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

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

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

    
567
		$form->add($section);
568
		print($form);
569

    
570
		break;
571
	}
572
}
573

    
574
include("foot.inc");
(26-26/227)