Project

General

Profile

Download (12.7 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("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
	// Did they pass an email?
104
	if (!empty($email)) {
105
		// Put it in the smartd.conf file
106
		shell_exec("/usr/bin/sed -i old 's/^DEVICESCAN.*/DEVICESCAN -H -m " . escapeshellarg($email) . "/' /usr/local/etc/smartd.conf");
107
	} else {
108
		// Remove email flags in smartd.conf
109
		shell_exec("/usr/bin/sed -i old 's/^DEVICESCAN.*/DEVICESCAN/' /usr/local/etc/smartd.conf");
110
	}
111
}
112

    
113
function smartmonctl($action) {
114
	global $start_script;
115
	shell_exec($start_script . escapeshellarg($action));
116
}
117
$targetdev = basename($_POST['device']);
118

    
119
if (!file_exists('/dev/' . $targetdev)) {
120
	echo gettext("Device does not exist, bailing.");
121
	return;
122
}
123

    
124
$tab_array = array();
125
$tab_array[0] = array(htmlspecialchars(gettext("Information & Tests")), ($action != 'config'), $_SERVER['PHP_SELF'] . "?action=default");
126
$tab_array[1] = array(gettext("Config"), ($action == 'config'), $_SERVER['PHP_SELF'] . "?action=config");
127
display_top_tabs($tab_array);
128

    
129
switch ($action) {
130
	// Testing devices
131
	case 'test':
132
	{
133
		$test = $_POST['testType'];
134
		if (!in_array($test, $valid_test_types)) {
135
			echo gettext("Invalid test type, bailing.");
136
			return;
137
		}
138

    
139
		$output = add_colors(shell_exec($smartctl . " -t " . escapeshellarg($test) . " /dev/" . escapeshellarg($targetdev)));
140
?>
141
		<div class="panel  panel-default">
142
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Test Results')?></h2></div>
143
			<div class="panel-body">
144
				<pre><?=$output?></pre>
145
			</div>
146
		</div>
147

    
148
		<form action="diag_smart.php" method="post" name="abort">
149
			<input type="hidden" name="device" value="<?=$targetdev?>" />
150
			<input type="hidden" name="action" value="abort" />
151
			<nav class="action-buttons">
152
				<input type="submit" name="submit"	class="btn btn-danger" value="<?=gettext("Abort")?>" />
153
				<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-default"><?=gettext("Back")?></a>
154
			</nav>
155
		</form>
156

    
157
<?php
158
		break;
159
	}
160

    
161
	// Info on devices
162
	case 'info':
163
	{
164
		$type = $_POST['type'];
165

    
166
		if (!in_array($type, $valid_info_types)) {
167
			print_info_box(gettext("Invalid info type, bailing."), 'danger');
168
			return;
169
		}
170

    
171
		$output = add_colors(shell_exec($smartctl . " -" . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
172
?>
173
		<div class="panel  panel-default">
174
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Information')?></h2></div>
175
			<div class="panel-body">
176
				<pre><?=$output?></pre>
177
			</div>
178
		</div>
179

    
180
		<nav class="action-buttons">
181
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-default"><?=gettext("Back")?></a>
182
		</nav>
183
<?php
184
		break;
185
	}
186

    
187
	// View logs
188
	case 'logs':
189
	{
190
		$type = $_POST['type'];
191
		if (!in_array($type, $valid_log_types)) {
192
			print_info_box(gettext("Invalid log type, bailing."), 'danger');
193
			return;
194
		}
195

    
196
		$output = add_colors(shell_exec($smartctl . " -l " . escapeshellarg($type) . " /dev/" . escapeshellarg($targetdev)));
197
?>
198
		<div class="panel  panel-default">
199
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Logs')?></h2></div>
200
			<div class="panel-body">
201
				<pre><?=$output?></pre>
202
			</div>
203
		</div>
204

    
205
		<nav class="action-buttons">
206
			<a href="<?=$_SERVER['PHP_SELF']?>" class="btn btn-default"><?=gettext("Back")?></a>
207
		</nav>
208
<?php
209
		break;
210
	}
211

    
212
	// Abort tests
213
	case 'abort':
214
	{
215
		$output = shell_exec($smartctl . " -X /dev/" . escapeshellarg($targetdev));
216
?>
217
		<div class="panel  panel-default">
218
			<div class="panel-heading"><h2 class="panel-title"><?=gettext('Abort')?></h2></div>
219
			<div class="panel-body">
220
				<pre><?=$output?></pre>
221
			</div>
222
		</div>
223
<?php
224
		break;
225
	}
226

    
227
	// Config changes, users email in xml config and write changes to smartd.conf
228
	case 'config':
229
	{
230
		if (isset($_POST['test'])) {
231

    
232
// FIXME				shell_exec($smartd . " -M test -m " . $config['system']['smartmonemail']);
233
			$savemsg = sprintf(gettext("Email sent to %s"), $config['system']['smartmonemail']);
234
			smartmonctl("stop");
235
			smartmonctl("start");
236
			$style = 'warning';
237
		} else if (isset($_POST['save'])) {
238
			$config['system']['smartmonemail'] = $_POST['smartmonemail'];
239
			write_config();
240

    
241
			// Don't know what all this means, but it adds the config changed header when config is saved
242
			$retval = 0;
243
			config_lock();
244
			if (stristr($retval, "error") != true) {
245
				$savemsg = get_std_save_message($retval);
246
				$style = 'success';
247
			} else {
248
				$savemsg = $retval;
249
				$style='danger';
250
			}
251

    
252
			config_unlock();
253

    
254
			// Write the changes to the smartd.conf file
255
			update_email($_POST['smartmonemail']);
256

    
257
			// Send sig HUP to smartd, rereads the config file
258
			shell_exec("/usr/bin/killall -HUP smartd");
259
		}
260

    
261
	// Was the config changed? if so, print the message
262
	if ($savemsg) {
263
		print_info_box($savemsg, $style);
264
	}
265

    
266
	// Get users email from the xml file
267
	$pconfig['smartmonemail'] = $config['system']['smartmonemail'];
268

    
269
	$form = new Form();
270

    
271
	$section = new Form_Section('Configuration');
272

    
273
	$section->addInput(new Form_Input(
274
		'smartmonemail',
275
		'Email Address',
276
		'text',
277
		$pconfig['smartmonemail']
278
	 ));
279

    
280
	$form->add($section);
281

    
282
	if (!empty($pconfig['smartmonemail'])) {
283
		$form->addGlobal(new Form_Button(
284
			'test',
285
			'Send test email'
286
		))->removeClass('btn-primary')->addClass('btn-default');
287
	}
288

    
289
	print($form);
290

    
291
	break;
292
	}
293

    
294
	// Default page, prints the forms to view info, test, etc...
295
	default: {
296
// Information
297
		$devs = get_smart_drive_list();
298

    
299
		$form = new Form(false);
300

    
301
		$btnview = new Form_Button(
302
			'submit',
303
			'View'
304
		);
305

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

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

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

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

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

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

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

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

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

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

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

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

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

    
377
		$btntest = new Form_Button(
378
			'submit',
379
			'Test'
380
		);
381

    
382
		$section = new Form_Section('Perform self-tests');
383

    
384
		$section->addInput(new Form_Input(
385
			'action',
386
			null,
387
			'hidden',
388
			'test'
389
		));
390

    
391
		$group = new Form_Group('Test type');
392

    
393
		$group->add(new Form_Checkbox(
394
			'testType',
395
			null,
396
			'Offline',
397
			false,
398
			'offline'
399
		))->displayAsRadio();
400

    
401
		$group->add(new Form_Checkbox(
402
			'testType',
403
			null,
404
			'Short',
405
			true,
406
			'short'
407
		))->displayAsRadio();
408

    
409
		$group->add(new Form_Checkbox(
410
			'testType',
411
			null,
412
			'Long',
413
			false,
414
			'long'
415
		))->displayAsRadio();
416

    
417
		$group->add(new Form_Checkbox(
418
			'testType',
419
			null,
420
			'Conveyance',
421
			false,
422
			'conveyance'
423
		))->displayAsRadio();
424

    
425
		$group->setHelp('Select "Conveyance" for ATA disks only');
426
		$section->add($group);
427

    
428
		$section->addInput(new Form_Select(
429
			'device',
430
			'Device: /dev/',
431
			false,
432
			array_combine($devs, $devs)
433
		));
434

    
435
		$section->addInput(new Form_StaticText(
436
			'',
437
			$btntest
438
		));
439

    
440
		$form->add($section);
441
		print($form);
442

    
443
// Logs
444
		$form = new Form(false);
445

    
446
		$btnview =  new Form_Button(
447
			'submit',
448
			'View'
449
		);
450

    
451
		$section = new Form_Section('View Logs');
452

    
453
		$section->addInput(new Form_Input(
454
			'action',
455
			null,
456
			'hidden',
457
			'logs'
458
		));
459

    
460
		$group = new Form_Group('Log type');
461

    
462
		$group->add(new Form_Checkbox(
463
			'type',
464
			null,
465
			'Error',
466
			true,
467
			'error'
468
		))->displayAsRadio();
469

    
470
		$group->add(new Form_Checkbox(
471
			'type',
472
			null,
473
			'Self-test',
474
			false,
475
			'selftest'
476
		))->displayAsRadio();
477

    
478
		$section->add($group);
479

    
480
		$section->addInput(new Form_Select(
481
			'device',
482
			'Device: /dev/',
483
			false,
484
			array_combine($devs, $devs)
485
		));
486

    
487
		$section->addInput(new Form_StaticText(
488
			'',
489
			$btnview
490
		));
491

    
492
		$form->add($section);
493
		print($form);
494

    
495
// Abort
496
		$btnabort = new Form_Button(
497
			'submit',
498
			'Abort'
499
		);
500

    
501
		$btnabort->removeClass('btn-primary')->addClass('btn-danger');
502

    
503
		$form = new Form(false);
504

    
505
		$section = new Form_Section('Abort');
506

    
507
		$section->addInput(new Form_Input(
508
			'action',
509
			null,
510
			'hidden',
511
			'abort'
512
		));
513

    
514
		$section->addInput(new Form_Select(
515
			'device',
516
			'Device: /dev/',
517
			false,
518
			array_combine($devs, $devs)
519
		));
520

    
521
		$section->addInput(new Form_StaticText(
522
			'',
523
			$btnabort
524
		));
525

    
526
		$form->add($section);
527
		print($form);
528

    
529
		break;
530
	}
531
}
532

    
533
include("foot.inc");
(25-25/229)