mirror of
https://github.com/unraid/webgui.git
synced 2026-03-13 06:19:47 -05:00
Merge pull request #194 from bergware/6.4-wip
NVMe devices attribute reading + temperature warning enhancements
This commit is contained in:
@@ -15,7 +15,16 @@ Tag="snowflake-o"
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$stop = (file_exists($var['luksKeyfile']) && $var['fsEncryption']=='wrong') || ($var['fsEncryption']=='missing' && $var['luksRestricted']=='yes') ? 'disabled':'';
|
||||
$forced = $var['fsEncryption']=='no';
|
||||
$crypto = $var['fsEncryption']=='yes';
|
||||
$wrong = $var['fsEncryption']=='wrong';
|
||||
$missing = $var['fsEncryption']=='missing';
|
||||
$check = $var['luksRestricted']=='yes';
|
||||
$keyfile = file_exists($var['luksKeyfile']);
|
||||
$stop = ($keyfile && $wrong) || ($check && $missing) ? 'disabled':'';
|
||||
|
||||
$encrypt = false;
|
||||
if ($forced) foreach ($disks as $disk) $encrypt |= strpos($disk['fsType'],'luks:')!==false;
|
||||
|
||||
function maintenance_mode() {
|
||||
echo "<tr>";
|
||||
@@ -41,6 +50,7 @@ td.gap{padding-left:26px!important}
|
||||
</style>
|
||||
<script>
|
||||
var ctrl = "<span class='status'><a style='cursor:pointer' class='tooltip_diskio' title='Toggle reads/writes display' onclick='toggle_diskio();return false'><i class='toggle fa'></i></a></span>";
|
||||
var forced = <?=$forced ? 'true':'false'?>;
|
||||
|
||||
function tab0() {
|
||||
$.removeCookie('one',{path:'/'});
|
||||
@@ -112,6 +122,7 @@ function prepareInput(form) {
|
||||
form.local.disabled = true;
|
||||
form.file.disabled = true;
|
||||
form.text.disabled = true;
|
||||
form.copy.disabled = true;
|
||||
$.post('/update.php',data,function(){form.submit();});
|
||||
}
|
||||
}
|
||||
@@ -120,29 +131,46 @@ function selectInput(form) {
|
||||
form.file.value = '';
|
||||
form.local.value = '';
|
||||
$('#text').show();
|
||||
if (forced || $('input[name="luksReformat"]').prop('checked')) $('#copy').show();
|
||||
$('#file').hide();
|
||||
} else {
|
||||
form.text.value = '';
|
||||
form.copy.value = '';
|
||||
$('#text').hide();
|
||||
$('#copy').hide();
|
||||
$('#file').show();
|
||||
}
|
||||
toggleStart(true);
|
||||
}
|
||||
function toggleStart(data) {
|
||||
<?if ($stop):?>
|
||||
$('#cmdStart').prop('disabled',data=='');
|
||||
<?endif;?>
|
||||
function toggleStart(form) {
|
||||
var disabled = typeof(form)=='boolean' ? form : ((forced || form.luksReformat.checked) ? (form.text.value!=form.copy.value || form.text.value=='') : form.text.value=='');
|
||||
$('#cmdStart').prop('disabled',disabled);
|
||||
}
|
||||
function toggleApply(checked) {
|
||||
$('input[name="#apply"]').prop('disabled',!checked);
|
||||
}
|
||||
function showPass(checked) {
|
||||
$('input[name="text"]').attr('type',checked ? 'text':'password');
|
||||
$('input[name="text"],input[name="copy"]').attr('type',checked ? 'text':'password');
|
||||
}
|
||||
function showCopy(checked) {
|
||||
if ($('select[name="input"]').val()=='file') return;
|
||||
var text = $('input[name="text"]').val();
|
||||
var copy = $('input[name="copy"]').val();
|
||||
if (forced || checked) {
|
||||
$('#copy').show();
|
||||
toggleStart(text!=copy || text=='');
|
||||
} else {
|
||||
$('#copy').hide();
|
||||
toggleStart(text=='');
|
||||
}
|
||||
}
|
||||
function getFileContent(event,form) {
|
||||
var input = event.target;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(){form.file.value=reader.result;toggleStart('ok');};
|
||||
reader.onload = function(){form.file.value=reader.result;toggleStart(false);};
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
parity_status();
|
||||
|
||||
<?if ($tabbed):?>
|
||||
$('.tabs').append(ctrl);
|
||||
if ($.cookie('tab')=='tab0') $('i.toggle').hide();
|
||||
@@ -171,6 +199,16 @@ reload_page();
|
||||
<?endif;?>
|
||||
$('.tooltip_diskio').tooltipster({delay:100,trigger:'custom',triggerOpen:{mouseenter:true},triggerClose:{click:false,scroll:true,mouseleave:true}});
|
||||
toggle_diskio(true);
|
||||
$(function(){
|
||||
<?if ($encrypt):?>
|
||||
$('#cmdStart').prop('disabled',true);
|
||||
$('#copy').show();
|
||||
<?endif;?>
|
||||
<?if ($var['mdState']=='STOPPED' && $wrong):?>
|
||||
$('#copy').hide();
|
||||
$('#perm').show()
|
||||
<?endif;?>
|
||||
});
|
||||
</script>
|
||||
<form name="arrayOps" method="POST" action="/update.htm" target="progressFrame">
|
||||
<input type="hidden" name="startState" value="<?=htmlspecialchars($var['mdState'])?>">
|
||||
@@ -305,11 +343,14 @@ toggle_diskio(true);
|
||||
<td><strong>Start</strong> will bring the array on-line.</td></tr>
|
||||
<? endif;
|
||||
maintenance_mode();
|
||||
if ((file_exists($var['luksKeyfile']) && $var['fsEncryption']=='wrong') || $var['fsEncryption']=='missing'):?>
|
||||
<tr><td></td><td class="gap">Encryption status:</td><td><span class="red-text"><?=$var['fsEncryption']=='wrong'?'Wrong key':'Missing key'?></span></td></tr>
|
||||
if (($keyfile && $wrong) || $missing || $encrypt || (!$keyfile && $crypto)):?>
|
||||
<tr><td></td><td class="gap">Encryption status:</td><td><span class="red-text"><?=$wrong?'Wrong key':(($missing||$crypto)?'Missing key':'Enter new key')?></span></td></tr>
|
||||
<tr><td></td><td class="gap">Encryption input:</td><td><select name="input" size="1" onchange="selectInput(this.form)"><?=mk_option(1,"text","Passphrase")?><?=mk_option(1,"file","Keyfile")?></select></td></tr>
|
||||
<tr id="text"><td></td><td class="gap">Passphrase:</td><td><input type="password" name="text" maxlength="512" value="" onkeyup="toggleStart(this.value)"><input type="checkbox" onchange="showPass(this.checked)">show passphrase</td></tr>
|
||||
<tr id="text"><td></td><td class="gap">Passphrase:</td><td><input type="password" name="text" maxlength="512" value="" onkeyup="toggleStart(this.form)"><input type="checkbox" onchange="showPass(this.checked)">show passphrase</td></tr>
|
||||
<tr id="copy" style="display:none"><td></td><td class="gap">Retype passphrase:</td><td><input type="password" name="copy" maxlength="512" value="" onkeyup="toggleStart(this.form)"></td></tr>
|
||||
<tr id="file" style="display:none"><td></td><td class="gap">Keyfile:</td><td><input type="file" name="local" onchange="getFileContent(event,this.form)"></td></tr>
|
||||
<tr id="perm" style="display:none"><td></td><td></td><td><input name="luksReformat" type="checkbox" onchange="showCopy(this.checked)">permit reformat</td></tr>
|
||||
<tr><td></td><td></td><td><input type="button" value="Benchmark" onclick="openBox('/webGui/include/CryptoBenchmark.php','Encryption Benchmarking',600,640)"></td></tr>
|
||||
<? endif;
|
||||
break;
|
||||
case "NEW_ARRAY":
|
||||
@@ -431,6 +472,15 @@ toggle_diskio(true);
|
||||
</table>
|
||||
</form>
|
||||
<?endif;?>
|
||||
<?if ($keyfile):?>
|
||||
<form markdown="1" name="delete_keyfile" method="POST" action="/update.php" target="progressFrame">
|
||||
<input type="hidden" name="#file" value="unused">
|
||||
<input type="hidden" name="#include" value="webGui/include/KeyUpload.php">
|
||||
<table class="array_status">
|
||||
<tr><td></td><td><input type="submit" name="#apply" value="Delete" disabled></td><td><input type="checkbox" onchange="toggleApply(this.checked)">Delete encryption keyfile</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
<form name="shutdownOps" method="POST" action="/webGui/include/Boot.php">
|
||||
<table class="array_status">
|
||||
@@ -509,4 +559,36 @@ if (isset($display['sleep'])) @include $display['sleep'];
|
||||
>
|
||||
> Once you have assigned all of your hard drives, refer to the Array Status section below
|
||||
> and Start the array.
|
||||
|
||||
<?if (($keyfile && $wrong) || $missing || $encrypt):?>
|
||||
<div></div>
|
||||
> #### Encryption input
|
||||
>
|
||||
> This keyfile is read during array Start and is used to encrypt/decrypt content of encrypted devices.
|
||||
>
|
||||
> With array Stopped, the keyfile may be deleted and the user can specify a new encryption key. Note that once a device
|
||||
> is formatted with a particular key it may only be opened using that same key. Changing the encryption key requires
|
||||
> encrypted devices to be reformatted **resulting in permanent loss of all existing data on those devices.**
|
||||
>
|
||||
> With array Started, the keyfile may be deleted to ensure there is no encryption key present on the server when
|
||||
> the array is online. Note that plugins are installed and may execute before and during the array Start process.
|
||||
>
|
||||
> #### Passphrase
|
||||
>
|
||||
> Enter a passphrase of up to 512 characters. It is highly advisable to only use the 95 printable characters from the
|
||||
> first 128 characters of the [ASCII table](https://en.wikipedia.org/wiki/ASCII), as they will always have the same binary
|
||||
> representation. Other characters may have different encoding depending on system configuration and your passphrase will
|
||||
> not work with a different encoding. If you want a longer passphrase or to include binary data, upload a keyfile instead.
|
||||
>
|
||||
> Please refer to the [cryptsetup FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions#5-security-aspects)
|
||||
> for what constitutes a *secure* passphrase.
|
||||
>
|
||||
> **Memorize** this passphrase. **IF LOST, ENCRYPTED CONTENT CANNOT BE RECOVERED!**
|
||||
>
|
||||
> #### Keyfile
|
||||
>
|
||||
> Select a local keyfile with a stored encryption key or a binary file. The maximum size of the keyfile is 8M (8388608 byte).
|
||||
>
|
||||
> **Backup** your local keyfile. **IF LOST, ENCRYPTED CONTENT CANNOT BE RECOVERED!**
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Menu="Main:2"
|
||||
Title="Cache Devices"
|
||||
Tag="upload"
|
||||
Tag="bullseye"
|
||||
Cond="($var['fsState']=='Stopped' || $var['cacheSbNumDisks'])"
|
||||
---
|
||||
<?PHP
|
||||
|
||||
@@ -27,9 +27,17 @@ function maintenance_mode() {
|
||||
global $var, $disk;
|
||||
return ($var['fsState']=="Started" && $var['startMode']=="Maintenance" && $disk['luksState']<=1);
|
||||
}
|
||||
|
||||
$luks_disabled = file_exists($var['luksKeyfile']) ? '' : 'disabled';
|
||||
?>
|
||||
<style>
|
||||
input.option{display:none;width:40px}
|
||||
span.devtext{display:none;font-weight:bold}
|
||||
span.helptext{display:none;font-style:italic}
|
||||
<?if (strstr('azure,gray',$display['theme'])):?>
|
||||
span.code{display:inline-block;width:186px}
|
||||
<?else:?>
|
||||
span.code{display:inline-block;width:138px}
|
||||
<?endif;?>
|
||||
</style>
|
||||
<script>
|
||||
function doDispatch(form) {
|
||||
var fields = {};
|
||||
@@ -48,28 +56,67 @@ function prepareDeviceInfo(form) {
|
||||
form.elements['at'+i].disabled = true;
|
||||
}
|
||||
var custom = form.smCustom.value.trim();
|
||||
var custom = custom.length ? custom.split(',') : [];
|
||||
custom = custom.length ? custom.split(',') : [];
|
||||
for (var i=0; i < custom.length; i++) events.push(custom[i].trim());
|
||||
form.smEvents.value = events.join('|');
|
||||
if (form.smEvents.value == '<?=implode('|',$events)?>') form.smEvents.value = '';
|
||||
if (form.smLevel.value == 1.00) form.smLevel.value = '';
|
||||
}
|
||||
function setGlue(form) {
|
||||
var data = [{glue:'' ,more:0}, // auto
|
||||
{glue:'' ,more:0}, // ata
|
||||
{glue:'' ,more:0}, // sata
|
||||
{glue:'' ,more:0}, // scsi
|
||||
{glue:',',more:1,min1:0,max1:127}, // 3ware
|
||||
{glue:'/',more:2,min1:1,max1:128,min2:1,max2:8}, // areca
|
||||
{glue:'/',more:3,min1:1,max1:4,min2:1,max2:128,min3:1,max3:4}, // highpoint
|
||||
{glue:'' ,more:0}, // marvell
|
||||
{glue:',',more:1,min1:0,max1:127} // megaraid
|
||||
];
|
||||
var n = form.smType.selectedIndex > 0 ? form.smType.selectedIndex-1 : <?=isset($var['smIndex'])?$var['smIndex']:0?>;
|
||||
function setGlue(form,reset) {
|
||||
var data =
|
||||
[{glue:'' ,more:0,dev:0,type:''}, // auto
|
||||
{glue:'' ,more:0,dev:0,type:''}, // ata
|
||||
{glue:',',more:1,dev:0,type:'input',min1:'',max1:'0xffffffff'}, // nvme
|
||||
{glue:',',more:2,dev:0,type:'select',min11:'',min12:'auto',min21:'',min22:12,min23:16}, // sat
|
||||
{glue:'' ,more:0,dev:0,type:''}, // scsi
|
||||
{glue:',',more:1,dev:1,type:'',min1:0,max1:127}, // 3ware
|
||||
{glue:',',more:3,dev:1,type:'',min1:0,max1:15,min2:0,max2:7,min3:0,max3:7}, // adaptec
|
||||
{glue:',',more:1,dev:1,type:'',min1:1,max1:24}, // areca
|
||||
{glue:'/',more:3,dev:1,type:'',min1:1,max1:4,min2:1,max2:128,min3:1,max3:4}, // highpoint
|
||||
{glue:'' ,more:0,dev:0,type:''}, // marvell
|
||||
{glue:',',more:1,dev:1,type:'',min1:0,max1:127} // megaraid
|
||||
];
|
||||
var n = form.smType.selectedIndex>0 ? form.smType.selectedIndex-1 : <?=$var['smIndex']??0?>;
|
||||
var x = data[n]['more'];
|
||||
for (var i=1; i <= x; i++) $('input[name="smPort'+i+'"]').attr('placeholder',data[n]['min'+i]+'..'+data[n]['max'+i]).show();
|
||||
for (var i=x+1; i <= 3; i++) $('input[name="smPort'+i+'"]').val('').hide();
|
||||
if (x > 0) {
|
||||
var t = data[n]['type'];
|
||||
for (var i=1; i <= x; i++) {
|
||||
switch (t) {
|
||||
case 'input':
|
||||
var min = data[n]['min'+i];
|
||||
var max = data[n]['max'+i];
|
||||
var len = max.toString().length;
|
||||
if (reset) $('input[name="smPort'+i+'"]').val('');
|
||||
$('select[name="smPort'+i+'"]').prop('disabled',true).hide();
|
||||
$('input[name="smPort'+i+'"]').css('width',80).attr('maxlength',len).attr('placeholder',min).prop('disabled',false).show();
|
||||
break;
|
||||
case 'select':
|
||||
var options = [];
|
||||
var c = 1;
|
||||
do {
|
||||
var option = data[n]['min'+i+(c++)];
|
||||
if (typeof(option)!='undefined') {
|
||||
var selected = option==$('input[name="smPort'+i+'"]').val() ? ' selected':'';
|
||||
options.push('<option value="'+option+'"'+selected+'>'+option+'</option>');
|
||||
} else break;
|
||||
} while (true);
|
||||
if (reset) $('select[name="smPort'+i+'"]').val('');
|
||||
$('input[name="smPort'+i+'"]').prop('disabled',true).hide();
|
||||
$('select[name="smPort'+i+'"]').html(options.join('')).prop('disabled',false).show();
|
||||
break;
|
||||
default:
|
||||
var min = data[n]['min'+i];
|
||||
var max = data[n]['max'+i];
|
||||
var len = max.toString().length;
|
||||
if (reset) $('input[name="smPort'+i+'"]').val('');
|
||||
$('select[name="smPort'+i+'"]').prop('disabled',true).hide();
|
||||
$('input[name="smPort'+i+'"]').css('width',40).attr('maxlength',len).attr('placeholder',min+'...'+max).prop('disabled',false).show();
|
||||
}
|
||||
}
|
||||
for (var i=x+1; i <= 3; i++) {
|
||||
$('input[name="smPort'+i+'"]').val('').prop('disabled',false).hide();
|
||||
$('select[name="smPort'+i+'"]').prop('disabled',true).hide();
|
||||
}
|
||||
if (data[n]['dev']==1) {
|
||||
$('#devtext').show();
|
||||
$('input[name="smDevice"]').show();
|
||||
$('#helptext').show();
|
||||
@@ -84,7 +131,7 @@ $(function() {
|
||||
<?if (!isset($disk['smType'])):?>
|
||||
form.smType.selectedIndex = 0;
|
||||
<?endif;?>
|
||||
setGlue(form);
|
||||
setGlue(form,false);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -104,7 +151,7 @@ Spinup group(s):
|
||||
|
||||
<?endif;?>
|
||||
Spin down delay:
|
||||
: <select name="diskSpindownDelay.<?=$disk['idx']?>" size="1">
|
||||
: <select name="diskSpindownDelay.<?=$disk['idx']?>">
|
||||
<?=mk_option($disk['spindownDelay'], "-1", "Use default")?>
|
||||
<?=mk_option($disk['spindownDelay'], "0", "Never")?>
|
||||
<?=mk_option($disk['spindownDelay'], "15", "15 minutes")?>
|
||||
@@ -143,14 +190,14 @@ File system status:
|
||||
<?$disabled = $var['mdState']=="SWAP_DSBL" ? "disabled" : "";?>
|
||||
<?if ($disk['type']=="Data" || $var['SYS_CACHE_SLOTS']==1):?>
|
||||
File system type:
|
||||
: <select id="diskFsType" name="diskFsType.<?=$disk['idx'];?>" size="1" <?=$disabled?>>
|
||||
: <select id="diskFsType" name="diskFsType.<?=$disk['idx'];?>" <?=$disabled?>>
|
||||
<?=mk_option($disk['fsType'], "auto", "auto")?>
|
||||
<?=mk_option($disk['fsType'], "xfs", "xfs")?>
|
||||
<?=mk_option($disk['fsType'], "btrfs", "btrfs")?>
|
||||
<?=mk_option($disk['fsType'], "reiserfs", "reiserfs")?>
|
||||
<?=mk_option($disk['fsType'], "luks:xfs", "xfs - encrypted", $luks_disabled)?>
|
||||
<?=mk_option($disk['fsType'], "luks:btrfs", "btrfs - encrypted", $luks_disabled)?>
|
||||
<?=mk_option($disk['fsType'], "luks:reiserfs", "reiserfs - encrypted", $luks_disabled)?>
|
||||
<?=mk_option($disk['fsType'], "luks:xfs", "xfs - encrypted")?>
|
||||
<?=mk_option($disk['fsType'], "luks:btrfs", "btrfs - encrypted")?>
|
||||
<?=mk_option($disk['fsType'], "luks:reiserfs", "reiserfs - encrypted")?>
|
||||
</select>
|
||||
|
||||
> Enter the desired file system type. Changing the file system type of a device will permit you to reformat
|
||||
@@ -160,10 +207,10 @@ File system type:
|
||||
|
||||
<?elseif ($var['SYS_CACHE_SLOTS']>1):?>
|
||||
File system type:
|
||||
: <select id="diskFsType" name="diskFsType.<?=$disk['idx'];?>" size="1" <?=$disabled?>>
|
||||
: <select id="diskFsType" name="diskFsType.<?=$disk['idx'];?>" <?=$disabled?>>
|
||||
<?=mk_option($disk['fsType'], "auto", "auto")?>
|
||||
<?=mk_option($disk['fsType'], "btrfs", "btrfs")?>
|
||||
<?=mk_option($disk['fsType'], "luks:btrfs", "btrfs - encrypted", $luks_disabled)?>
|
||||
<?=mk_option($disk['fsType'], "luks:btrfs", "btrfs - encrypted")?>
|
||||
</select>
|
||||
|
||||
<?endif;?>
|
||||
@@ -469,7 +516,7 @@ xfs_repair status:
|
||||
<input type="hidden" name="smEvents" value="">
|
||||
<input type="hidden" name="smGlue" value="<?=htmlspecialchars($var['smGlue'])?>">
|
||||
SMART notification value:
|
||||
: <select name="smSelect" size="1">
|
||||
: <select name="smSelect">
|
||||
<?=mk_option($disk['smSelect'], "-1", "Use default")?>
|
||||
<?=mk_option($disk['smSelect'], "0", "Raw")?>
|
||||
<?=mk_option($disk['smSelect'], "1", "Normalized")?>
|
||||
@@ -480,7 +527,7 @@ SMART notification value:
|
||||
> Each disk may have its own specific setting overruling the 'default' setting (see global SMART settings under Disk Settings).
|
||||
|
||||
SMART notification tolerance level:
|
||||
: <select name="smLevel" size="1">
|
||||
: <select name="smLevel">
|
||||
<?=mk_option($disk['smLevel'], "-1", "Use default")?>
|
||||
<?=mk_option($disk['smLevel'], "1.00", "Absolute")?>
|
||||
<?=mk_option($disk['smLevel'], "1.05", "5%")?>
|
||||
@@ -496,22 +543,24 @@ SMART notification tolerance level:
|
||||
> Each disk may have its own specific setting overruling the 'default' setting (see global SMART settings under Disk Settings).
|
||||
|
||||
SMART controller type:
|
||||
: <select name="smType" size="1" onchange="setGlue(this.form)">
|
||||
: <select name="smType" onchange="setGlue(this.form,true)">
|
||||
<?=mk_option($disk['smType'], "-1", "Use default")?>
|
||||
<?=mk_option($disk['smType'], " ", "Automatic")?>
|
||||
<?=mk_option($disk['smType'], "-d ata", "ATA")?>
|
||||
<?=mk_option($disk['smType'], "-d sat", "SATA")?>
|
||||
<?=mk_option($disk['smType'], "-d nvme", "NVMe")?>
|
||||
<?=mk_option($disk['smType'], "-d sat", "SAT")?>
|
||||
<?=mk_option($disk['smType'], "-d scsi", "SCSI")?>
|
||||
<?=mk_option($disk['smType'], "-d 3ware", "3Ware")?>
|
||||
<?=mk_option($disk['smType'], "-d aacraid", "Adaptec")?>
|
||||
<?=mk_option($disk['smType'], "-d areca", "Areca")?>
|
||||
<?=mk_option($disk['smType'], "-d hpt", "HighPoint")?>
|
||||
<?=mk_option($disk['smType'], "-d marvell", "Marvell")?>
|
||||
<?=mk_option($disk['smType'], "-d megaraid", "MegaRAID")?>
|
||||
</select>
|
||||
<input type="text" name="smPort1" maxlength="3" value="<?=$disk['smPort1']?>" style="display:none;width:32px">
|
||||
<input type="text" name="smPort2" maxlength="3" value="<?=$disk['smPort2']?>" style="display:none;width:32px">
|
||||
<input type="text" name="smPort3" maxlength="3" value="<?=$disk['smPort3']?>" style="display:none;width:32px"><span id="devtext" style="display:none;font-weight:bold">/dev/</span>
|
||||
<input type="text" name="smDevice" value="<?=isset($disk['smDevice'])?$disk['smDevice']:''?>" style="display:none;width:32px" placeholder="<?=htmlspecialchars($disk['device'])?>"><span id="helptext" style="display:none;font-style:italic">enter disk index and device name as applicable to your controller</span>
|
||||
<input type="text" name="smPort1" value="<?=$disk['smPort1']?>" class="option"><select name="smPort1" class="narrow" style="display:none" disabled></select>
|
||||
<input type="text" name="smPort2" value="<?=$disk['smPort2']?>" class="option"><select name="smPort2" class="narrow" style="display:none" disabled></select>
|
||||
<input type="text" name="smPort3" value="<?=$disk['smPort3']?>" class="option"><select name="smPort3" class="narrow" style="display:none" disabled></select><span id="devtext" class="devtext">/dev/</span>
|
||||
<input type="text" name="smDevice" value="<?=$disk['smDevice']??''?>" class="option" placeholder="<?=htmlspecialchars($disk['device'])?>"><span id="helptext" class="helptext">enter disk index and device name as applicable to your controller</span>
|
||||
|
||||
> By default automatic controller selection is done by smartctl to read the SMART information. Certain controllers however need specific settings for smartctl to work.
|
||||
> Use this setting to select your controller type and fill-in the specific disk index and device name for your situation. Use the manufacturer's documentation to find the relevant information.
|
||||
@@ -519,12 +568,12 @@ SMART controller type:
|
||||
> Each disk may have its own specific setting overruling the 'default' setting (see global SMART settings under Disk Settings).
|
||||
|
||||
SMART attribute notifications:
|
||||
: <input type="text" name="smCustom" value="<?=isset($disk['smCustom'])?$disk['smCustom']:$var['smCustom']?>" class="narrow">Custom attributes (use comma to separate numbers)
|
||||
: <input type="text" name="smCustom" value="<?=$disk['smCustom']??$var['smCustom']?>" class="narrow">Custom attributes (use comma to separate numbers)
|
||||
|
||||
<?for ($x = 0; $x < count($preselect); $x++):?>
|
||||
<?for ($x=0; $x < count($preselect); $x++):?>
|
||||
|
||||
: <input type="checkbox" name="at<?=$x?>" value="<?=$preselect[$x]['code']?>"<?=in_array($preselect[$x]['code'],$events)?' checked':''?>><span style="display:inline-block;width:136px"><?=$preselect[$x]['code']?></span><?=$preselect[$x]['text']?>
|
||||
<?endfor;?>
|
||||
: <input type="checkbox" name="at<?=$x?>" value="<?=$preselect[$x]['code']?>"<?=in_array($preselect[$x]['code'],$events)?' checked':''?>><span class="code">Attribute = <?=$preselect[$x]['code']?></span><?=$preselect[$x]['text']?>
|
||||
<?endfor;?>
|
||||
|
||||
> The user can enable or disable notifications for the given SMART attributes. It is recommended to keep the default, which is ALL selected attributes,
|
||||
> when certain attributes are not present on your hard disk or do not provide the correct information, these may be excluded.
|
||||
|
||||
@@ -24,6 +24,13 @@ function displayTemp($temp) {
|
||||
return $display['unit']=='F' ? round(9/5*$temp)+32 : $temp;
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
<?if (strstr('azure,gray',$display['theme'])):?>
|
||||
span.code{display:inline-block;width:186px}
|
||||
<?else:?>
|
||||
span.code{display:inline-block;width:138px}
|
||||
<?endif;?>
|
||||
</style>
|
||||
<script>
|
||||
function doDispatch(form) {
|
||||
var fields = {};
|
||||
@@ -261,15 +268,17 @@ Default SMART notification tolerance level:
|
||||
|
||||
Default SMART controller type:
|
||||
: <select name="smType" size="1" onchange="setIndex(this.form)">
|
||||
<?=mk_option($var['smType'], "", "Automatic")?>
|
||||
<?=mk_option($var['smType'], "-d ata", "ATA")?>
|
||||
<?=mk_option($var['smType'], "-d sat", "SATA")?>
|
||||
<?=mk_option($var['smType'], "-d scsi", "SCSI")?>
|
||||
<?=mk_option($var['smType'], "-d 3ware", "3Ware")?>
|
||||
<?=mk_option($var['smType'], "-d areca", "Areca")?>
|
||||
<?=mk_option($var['smType'], "-d hpt", "HighPoint")?>
|
||||
<?=mk_option($var['smType'], "-d marvell", "Marvell")?>
|
||||
<?=mk_option($var['smType'], "-d megaraid", "MegaRAID")?>
|
||||
<?=mk_option($disk['smType'], "", "Automatic")?>
|
||||
<?=mk_option($disk['smType'], "-d ata", "ATA")?>
|
||||
<?=mk_option($disk['smType'], "-d nvme", "NVMe")?>
|
||||
<?=mk_option($disk['smType'], "-d sat", "SAT")?>
|
||||
<?=mk_option($disk['smType'], "-d scsi", "SCSI")?>
|
||||
<?=mk_option($disk['smType'], "-d 3ware", "3Ware")?>
|
||||
<?=mk_option($disk['smType'], "-d aacraid", "Adaptec")?>
|
||||
<?=mk_option($disk['smType'], "-d areca", "Areca")?>
|
||||
<?=mk_option($disk['smType'], "-d hpt", "HighPoint")?>
|
||||
<?=mk_option($disk['smType'], "-d marvell", "Marvell")?>
|
||||
<?=mk_option($disk['smType'], "-d megaraid", "MegaRAID")?>
|
||||
</select>
|
||||
|
||||
> By default automatic controller selection is done by smartctl to read the SMART information. Certain controllers however need specific settings for smartctl to work.
|
||||
@@ -280,10 +289,10 @@ Default SMART controller type:
|
||||
Default SMART attribute notifications:
|
||||
: <input type="text" name="smCustom" value="<?=$var['smCustom']?>" class="narrow">Custom attributes (use comma to separate numbers)
|
||||
|
||||
<?for ($x = 0; $x < count($preselect); $x++):?>
|
||||
<?for ($x = 0; $x < count($preselect); $x++):?>
|
||||
|
||||
: <input type="checkbox" name="at<?=$x?>" value="<?=$preselect[$x]['code']?>"<?=in_array($preselect[$x]['code'],$events)?' checked':''?>><span style="display:inline-block;width:136px"><?=$preselect[$x]['code']?></span><?=$preselect[$x]['text']?>
|
||||
<?endfor;?>
|
||||
: <input type="checkbox" name="at<?=$x?>" value="<?=$preselect[$x]['code']?>"<?=in_array($preselect[$x]['code'],$events)?' checked':''?>><span class="code">Attribute = <?=$preselect[$x]['code']?></span><?=$preselect[$x]['text']?>
|
||||
<?endfor;?>
|
||||
|
||||
> The user can enable or disable notifications for the given SMART attributes. It is recommended to keep the default, which is ALL selected attributes,
|
||||
> when certain attributes are not present on your hard disk or do not provide the correct information, these may be excluded.
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
Menu="UserPreferences"
|
||||
Title="Encryption Settings"
|
||||
Icon="encryption-settings.png"
|
||||
Tag="key"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2017, Lime Technology
|
||||
* Copyright 2012-2017, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$keyfile = file_exists($var['luksKeyfile']) ? $var['luksKeyfile']:'';
|
||||
$online = $var['fsState']=='Stopped' ? '':'disabled';
|
||||
$allwrong = !$online && $var['fsEncryption']=='wrong';
|
||||
?>
|
||||
<script>
|
||||
<?if ($keyfile):?>
|
||||
function prepareInput(form) {
|
||||
form.keyfile.disabled = true;
|
||||
form.luksReformat.disabled = true;
|
||||
}
|
||||
function toggleApply(checked) {
|
||||
$('input[name="#apply"]').prop('disabled',!checked);
|
||||
}
|
||||
<?else:?>
|
||||
var forced = <?=$var['fsEncryption']=='no' ? 'true':'false'?>;
|
||||
|
||||
function prepareInput(form) {
|
||||
if (form.luksReformat.checked) {
|
||||
$.post('/update.htm',{luksReformat:'yes',changeDisk:'apply'});
|
||||
}
|
||||
if (form.text.value || form.file.value) {
|
||||
form.input.disabled = true;
|
||||
form.local.disabled = true;
|
||||
form.copy.disabled = true;
|
||||
form.luksReformat.disabled = true;
|
||||
}
|
||||
}
|
||||
function toggleApply(form) {
|
||||
var disabled = (forced || form.luksReformat.checked) ? form.text.value!=form.copy.value : form.text.value=='';
|
||||
form.apply.disabled = disabled;
|
||||
}
|
||||
function selectInput(form) {
|
||||
if (form.input.value == 'text') {
|
||||
form.file.value = '';
|
||||
form.local.value = '';
|
||||
$('#text').show();
|
||||
$('#file').hide();
|
||||
} else {
|
||||
form.text.value = '';
|
||||
form.copy.value = '';
|
||||
$('#text').hide();
|
||||
$('#file').show();
|
||||
}
|
||||
form.apply.disabled = true;
|
||||
}
|
||||
function showPass(checked) {
|
||||
$('input[name="text"],input[name="copy"]').attr('type',checked ? 'text':'password');
|
||||
}
|
||||
function showRetype(form) {
|
||||
if (forced || form.luksReformat.checked) $('#retype').show(); else $('#retype').hide();
|
||||
if (form.input.value=='text') form.apply.disabled = true;
|
||||
}
|
||||
function getFileContent(event,form) {
|
||||
var input = event.target;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(){form.file.value=reader.result; form.apply.disabled=false;};
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
$(function(){
|
||||
if (forced) $('#retype').show();
|
||||
});
|
||||
<?endif;?>
|
||||
</script>
|
||||
<form markdown="1" name="encrypt_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareInput(this)">
|
||||
<input type="hidden" name="#file" value="unused">
|
||||
<input type="hidden" name="#include" value="webGui/include/KeyUpload.php">
|
||||
<input type="hidden" name="file" value="">
|
||||
<?if (!$allwrong):?>
|
||||
<input type="hidden" name="luksReformat" type="checkbox">
|
||||
<?endif;?>
|
||||
<?if ($keyfile):?>
|
||||
Encryption key:
|
||||
: <?=$keyfile?>
|
||||
|
||||
> Shows the path and name of the current keyfile, if present.
|
||||
>
|
||||
> This keyfile is read during array Start and is used to encrypt/decrypt content of encrypted devices.
|
||||
>
|
||||
> With array Stopped, the keyfile may be deleted and the user can specify a new encryption key. Note that once a device
|
||||
> is formatted with a particular key it may only be opened using that same key. Changing the encryption key requires
|
||||
> encrypted devices to be reformatted **resulting in permanent loss of all existing data on those devices.**
|
||||
>
|
||||
> With array Started, the keyfile may be deleted to ensure there is no encryption key present on the server when
|
||||
> the array is online. Note that plugins are installed and may execute before and during the array Start process.
|
||||
|
||||
Delete <input type="checkbox" name="keyfile" onchange="toggleApply(this.checked)">
|
||||
: <input type="submit" name="#apply" value="Delete" disabled><input type="button" value="Done" class="lock" onclick="done()">
|
||||
|
||||
<?else:?>
|
||||
Encryption key:
|
||||
: Not present
|
||||
|
||||
Encryption input:
|
||||
: <select name="input" size="1" onchange="selectInput(this.form)"<?=$online?>>
|
||||
<?=mk_option(1, "text", "Passphrase")?>
|
||||
<?=mk_option(1, "file", "Keyfile")?>
|
||||
</select>
|
||||
|
||||
> Select manual input or file input of the encryption key. Note that the encryption key needs to be re-entered each time the server is rebooted.
|
||||
>
|
||||
> The array will **not** Start automatically when encrypted volumes are present.
|
||||
|
||||
<div id="text" markdown="1">
|
||||
Passphrase:
|
||||
: <input type="password" name="text" maxlength="512" value=""<?=$online?> onkeyup="toggleApply(this.form)"><?if (!$online):?><input type="checkbox" onchange="showPass(this.checked)">show passphrase<?endif;?>
|
||||
|
||||
> Enter a passphrase of up to 512 characters. It is highly advisable to only use the 95 printable characters from the
|
||||
> first 128 characters of the [ASCII table](https://en.wikipedia.org/wiki/ASCII), as they will always have the same binary
|
||||
> representation. Other characters may have different encoding depending on system configuration and your passphrase will
|
||||
> not work with a different encoding. If you want a longer passphrase or to include binary data, upload a keyfile instead.
|
||||
>
|
||||
> Please refer to the [cryptsetup FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions#5-security-aspects)
|
||||
> for what constitutes a *secure* passphrase.
|
||||
>
|
||||
> **Memorize** this passphrase. **IF LOST, ENCRYPTED CONTENT CANNOT BE RECOVERED!**
|
||||
|
||||
<div id="retype" markdown="1" style="display:none">
|
||||
Retype passphrase:
|
||||
: <input type="password" name="copy" maxlength="512" value=""<?=$online?> onkeyup="toggleApply(this.form)">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="file" markdown="1" style="display:none">
|
||||
Keyfile:
|
||||
: <input type="file" name="local" onchange="getFileContent(event,this.form)"<?=$online?>>
|
||||
|
||||
> Select a local keyfile with a stored encryption key or a binary file. The maximum size of the keyfile is 8M (8388608 byte).
|
||||
>
|
||||
> **Backup** your local keyfile. **IF LOST, ENCRYPTED CONTENT CANNOT BE RECOVERED!**
|
||||
|
||||
</div>
|
||||
<?if ($allwrong):?>
|
||||
|
||||
: <input name="luksReformat" type="checkbox" onchange="showRetype(this.form)">permit reformat
|
||||
|
||||
> To permit re-Format of encrypted devices, check this box and retype the passphrase.
|
||||
|
||||
<?endif;?>
|
||||
<input type="button" value="Benchmark" onclick="openBox('/webGui/include/CryptoBenchmark.php','Encryption Benchmarking',600,640)">
|
||||
: <input type="submit" name="apply" value="Apply" class="lock"><input type="button" value="Done" onclick="done()"><?if ($online):?>Array must be <span class="strong big">Stopped</span> to change<?endif;?>
|
||||
<?endif;?>
|
||||
</form>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 833 B |
Binary file not shown.
|
Before Width: | Height: | Size: 4.6 KiB |
@@ -54,11 +54,11 @@ foreach ($file as $row) {
|
||||
foreach ($rows as $row) $show |= strpos($disks[$tag.str_replace($tag,'',$row)]['fsType'],'luks:')!==false;
|
||||
if ($show) foreach ($rows as $row) {
|
||||
switch ($disks[$tag.str_replace($tag,'',$row)]['luksState']) {
|
||||
case 0: $luks .= "<i class='padlock grey-text fa fa-unlock' title='Not encrypted'></i>"; break;
|
||||
case 1: $luks .= "<i class='padlock green-text fa fa-unlock-alt' title='Encrypted and unlocked'></i>"; break;
|
||||
case 2: $luks .= "<i class='padlock red-text fa fa-lock' title='Locked: missing encryption key'></i>"; break;
|
||||
case 3: $luks .= "<i class='padlock red-text fa fa-lock' title='Locked: wrong encryption key'></i>"; break;
|
||||
default: $luks .= "<i class='padlock red-text fa fa-lock' title='Locked: unknown error'></i>"; break;}
|
||||
case 0: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-unlock grey-text'></i><span>Not encrypted</span></a>"; break;
|
||||
case 1: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-unlock-alt green-text'></i><span>Encrypted and unlocked</span></a>"; break;
|
||||
case 2: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: missing encryption key</span></a>"; break;
|
||||
case 3: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: wrong encryption key</span></a>"; break;
|
||||
default: $luks = "<a class='info' onclick='return false'><i class='lock fa fa-lock red-text'></i><span>Locked: unknown error</span></a>"; break;}
|
||||
}
|
||||
$list[] = [
|
||||
'type' => $attr[0],
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
<?
|
||||
$docroot = $docroot ?: $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
function getVal(&$ref,$n,$d) {
|
||||
global $var;
|
||||
$val = $ref[$n] ?? -1;
|
||||
return $val!==-1 ? $val : ($var[$n] ?? $d);
|
||||
}
|
||||
function normalize($type,$count) {
|
||||
$words = explode('_',$type);
|
||||
foreach ($words as &$word) $word = $word==strtoupper($word) ? $word : preg_replace(['/^(ct|cnt)$/','/^blk$/'],['count','block'],strtolower($word));
|
||||
@@ -24,19 +29,19 @@ function my_insert(&$source,$string) {
|
||||
function my_smart(&$source,$name,$page) {
|
||||
global $var,$disks,$path,$failed,$numbers,$saved;
|
||||
$disk = &$disks[$name];
|
||||
$select = $disk['smSelect'] ?? -1; if ($select==-1) $select = $var['smSelect'] ?? 0;
|
||||
$level = $disk['smLevel'] ?? -1; if ($level==-1) $level = $var['smLevel'] ?? 1;
|
||||
$events = explode('|',$disk['smEvents'] ?? $var['smEvents'] ?? $numbers);
|
||||
$select = getVal($disk,'smSelect',0);
|
||||
$level = getVal($disk,'smLevel',1);
|
||||
$events = explode('|',getVal($disk,'smEvents',$numbers));
|
||||
$title = '';
|
||||
$thumb = 'good';
|
||||
$file = "state/smart/$name";
|
||||
if (file_exists("$file.ssa") && in_array(file_get_contents("$file.ssa"),$failed)) {
|
||||
$smart = "state/smart/$name";
|
||||
if (file_exists("$smart.ssa") && in_array(file_get_contents("$smart.ssa"),$failed)) {
|
||||
$title = "S.M.A.R.T health-check failed\n"; $thumb = 'bad';
|
||||
} else {
|
||||
if (empty($saved["smart"]["$name.ack"])) {
|
||||
exec("awk 'NR>7{print $1,$2,$4,$6,$9,$10}' ".escapeshellarg($file)." 2>/dev/null", $codes);
|
||||
exec("awk 'NR>7{print $1,$2,$4,$6,$9,$10}' ".escapeshellarg($smart)." 2>/dev/null", $codes);
|
||||
foreach ($codes as $code) {
|
||||
if (!$code) continue;
|
||||
if (!$code || !is_numeric($code[0])) continue;
|
||||
list($id,$class,$value,$thres,$when,$raw) = explode(' ',$code);
|
||||
$fail = strpos($when,'FAILING_NOW')!==false;
|
||||
if (!$fail && !in_array($id,$events)) continue;
|
||||
@@ -52,7 +57,7 @@ function my_usage(&$source,$used) {
|
||||
my_insert($source, $used ? "<div class='usage-disk all'><span style='width:$used'>$used</span></div>" : "-");
|
||||
}
|
||||
function my_temp($value,$unit) {
|
||||
return ($unit=='C' ? $value : round(9/5*$value+32))." $unit";
|
||||
return ($unit=='F' ? round(9/5*$value+32) : $value)." $unit";
|
||||
}
|
||||
function my_clock($time) {
|
||||
if (!$time) return 'less than a minute';
|
||||
@@ -87,15 +92,15 @@ case 'disk':
|
||||
$row6 = array_fill(0,31,'<td></td>'); my_insert($row6[0],'Heat alarm');
|
||||
$row7 = array_fill(0,31,'<td></td>'); my_insert($row7[0],'SMART status');
|
||||
$row8 = array_fill(0,31,'<td></td>'); my_insert($row8[0],'Utilization');
|
||||
$funcRenderRow = function($n,$disk) use (&$row1,&$row2,&$row3,&$row4,&$row5,&$row6,&$row7,&$row8,$path) {
|
||||
$diskRow = function($n,$disk) use (&$row1,&$row2,&$row3,&$row4,&$row5,&$row6,&$row7,&$row8,$path) {
|
||||
if ($n>0) {
|
||||
if (isset($disk['luksState'])) {
|
||||
switch ($disk['luksState']) {
|
||||
case 0: $luks = ""; break;
|
||||
case 1: $luks = "<i class='green-text fa fa-unlock-alt'></i>"; break;
|
||||
case 2: $luks = "<i class='red-text fa fa-lock'></i>"; break;
|
||||
case 3: $luks = "<i class='red-text fa fa-lock'></i>"; break;
|
||||
default: $luks = "<i class='red-text fa fa-lock'></i>"; break;
|
||||
case 1: $luks = "<i class='fa fa-unlock-alt green-text'></i>"; break;
|
||||
case 2: $luks = "<i class='fa fa-lock red-text'></i>"; break;
|
||||
case 3: $luks = "<i class='fa fa-lock red-text'></i>"; break;
|
||||
default: $luks = "<i class='fa fa-lock red-text'></i>"; break;
|
||||
}
|
||||
} else $luks = "";
|
||||
my_insert($row1[$n],$luks);
|
||||
@@ -117,8 +122,8 @@ case 'disk':
|
||||
my_insert($row5[$n],"<img src=$path/$state.png>");
|
||||
break;}
|
||||
$temp = $disk['temp'];
|
||||
$hot = strlen($disk['hotTemp']) ? $disk['hotTemp'] : $_POST['hot'];
|
||||
$max = strlen($disk['maxTemp']) ? $disk['maxTemp'] : $_POST['max'];
|
||||
$hot = $disk['hotTemp'] ?? $_POST['hot'];
|
||||
$max = $disk['maxTemp'] ?? $_POST['max'];
|
||||
$heat = $temp>=$max && $max>0 ? 'max' : ($temp>=$hot && $hot>0 ? 'hot' : '');
|
||||
if ($heat)
|
||||
my_insert($row6[$n],"<span class='heat-img'><img src='$path/$heat.png'></span><span class='heat-text' style='display:none'>".my_temp($temp,$_POST['unit'])."</span>");
|
||||
@@ -128,16 +133,27 @@ case 'disk':
|
||||
my_usage($row8[$n],($disk['type']!='Parity' && $disk['fsStatus']=='Mounted')?(($disk['fsSize'] ? round((1-$disk['fsFree']/$disk['fsSize'])*100):0).'%'):'');
|
||||
}
|
||||
};
|
||||
foreach ($disks as $disk) if ($disk['type']=='Parity') $funcRenderRow($i++,$disk);
|
||||
foreach ($disks as $disk) if ($disk['type']=='Data') $funcRenderRow($i++,$disk);
|
||||
$devRow = function($n,$disk) use (&$row4,&$row6,&$row7,$path) {
|
||||
$hot = $_POST['hot'];
|
||||
$max = $_POST['max'];
|
||||
$name = $dev['device'];
|
||||
$port = substr($name,-2)!='n1' ? $name : substr($name,0,-2);
|
||||
$smart = "state/smart/$name";
|
||||
$state = exec("hdparm -C ".escapeshellarg("/dev/$port")."|grep -Po 'active|unknown'") ? 'blue-on' : 'blue-blink';
|
||||
if ($state=='blue-on') my_smart($row7[$n],$name,'New');
|
||||
$temp = file_exists($smart) ? exec("awk 'BEGIN{t=\"*\"} \$1==190||\$1==194{t=\$10;exit};\$1==\"Temperature:\"{t=\$2;exit} END{print t}' ".escapeshellarg($smart)) : '*';
|
||||
$heat = $temp>=$max && $max>0 ? 'max' : ($temp>=$hot && $hot>0 ? 'hot' : '');
|
||||
if ($heat)
|
||||
my_insert($row6[$n],"<span class='heat-img'><img src='$path/$heat.png'></span><span class='heat-text' style='display:none'>".my_temp($temp,$_POST['unit'])."</span>");
|
||||
else
|
||||
if ($state=='blue-on' && $temp>0) my_insert($row6[$n],"<span class='temp-text'>".my_temp($temp,$_POST['unit'])."</span>");
|
||||
my_insert($row4[$n],"<img src=$path/$state.png>");
|
||||
};
|
||||
foreach ($disks as $disk) if ($disk['type']=='Parity') $diskRow($i++,$disk);
|
||||
foreach ($disks as $disk) if ($disk['type']=='Data') $diskRow($i++,$disk);
|
||||
if ($slots <= 30) {
|
||||
foreach ($disks as $disk) if ($disk['type']=='Cache') $funcRenderRow($i++,$disk);
|
||||
foreach ($devs as $dev) {
|
||||
$device = $dev['device'];
|
||||
$state = exec("hdparm -C ".escapeshellarg("/dev/$device")."|grep -Po active") ? 'blue-on' : 'blue-blink';
|
||||
if ($state=='blue-on') my_smart($row7[$i],$device,'New');
|
||||
my_insert($row4[$i++],"<img src=$path/$state.png>");
|
||||
}
|
||||
foreach ($disks as $disk) if ($disk['type']=='Cache') $diskRow($i++,$disk);
|
||||
foreach ($devs as $dev) $devRow($i++,$dev);
|
||||
}
|
||||
echo "<tr>".implode('',$row1)."</tr>";
|
||||
echo "<tr>".implode('',$row2)."</tr>";
|
||||
@@ -157,13 +173,8 @@ case 'disk':
|
||||
$row6 = array_fill(0,31,'<td></td>'); my_insert($row6[0],'Heat alarm');
|
||||
$row7 = array_fill(0,31,'<td></td>'); my_insert($row7[0],'SMART status');
|
||||
$row8 = array_fill(0,31,'<td></td>'); my_insert($row8[0],'Utilization');
|
||||
foreach ($disks as $disk) if ($disk['type']=='Cache') $funcRenderRow($i++,$disk);
|
||||
foreach ($devs as $dev) {
|
||||
$device = $dev['device'];
|
||||
$state = exec("hdparm -C ".escapeshellarg("/dev/$device")."|grep -Po active") ? 'blue-on' : 'blue-blink';
|
||||
if ($state=='blue-on') my_smart($row7[$i],$device,'New');
|
||||
my_insert($row4[$i++],"<img src=$path/$state.png>");
|
||||
}
|
||||
foreach ($disks as $disk) if ($disk['type']=='Cache') $diskRow($i++,$disk);
|
||||
foreach ($devs as $dev) $devRow($i++,$dev);
|
||||
echo "<tr>".implode('',$row1)."</tr>";
|
||||
echo "<tr>".implode('',$row2)."</tr>";
|
||||
echo "<tr>".implode('',$row3)."</tr>";
|
||||
@@ -230,7 +241,7 @@ case 'shares':
|
||||
case 'smb':
|
||||
exec("lsof /mnt/user /mnt/disk* 2>/dev/null|awk '/^smbd/ && $0!~/\.AppleD(B|ouble)/ && $5==\"REG\"'|awk -F/ '{print $4}'",$lsof);
|
||||
$counts = array_count_values($lsof); $count = [];
|
||||
foreach ($names as $name) $count[] = isset($counts[$name]) ? $counts[$name] : 0;
|
||||
foreach ($names as $name) $count[] = $counts[$name] ?? 0;
|
||||
echo implode('#',$count);
|
||||
break;
|
||||
case 'afp':
|
||||
|
||||
@@ -35,7 +35,7 @@ function in_parity_log($log,$timestamp) {
|
||||
return !empty($line);
|
||||
}
|
||||
function device_info(&$disk,$online) {
|
||||
global $path, $var;
|
||||
global $path, $var, $show;
|
||||
$name = $disk['name'];
|
||||
$fancyname = $disk['type']=='New' ? $name : my_disk($name);
|
||||
$type = $disk['type']=='Flash' || $disk['type']=='New' ? $disk['type'] : 'Device';
|
||||
@@ -58,14 +58,14 @@ function device_info(&$disk,$online) {
|
||||
}
|
||||
$status = "$ctrl<a class='info nohand' onclick='return false'><img src='/webGui/images/{$disk['color']}.png' class='icon'><span>$help</span></a>";
|
||||
$link = (strcmp($disk['status'], 'DISK_NP')!=0 || $disk['name']=="cache") ? "<a href=\"".htmlspecialchars("$path/$type?name=$name")."\">".$fancyname."</a>" : $fancyname;
|
||||
switch ($disk['luksState']) {
|
||||
case 0: $luks = ""; break;
|
||||
case 1: $luks = "<i ".($online?"class='padlock fa fa-unlock-alt green-text' title='Encrypted and unlocked'":"class='padlock fa fa-lock grey-text' title='Encrypted and locked'")."></i>"; break;
|
||||
case 2: $luks = "<i class='padlock fa fa-lock red-text' title='Locked: missing encryption key'></i>"; break;
|
||||
case 3: $luks = "<i class='padlock fa fa-lock red-text' title='Locked: wrong encryption key'></i>"; break;
|
||||
default: $luks = "<i class='padlock fa fa-lock red-text' title='Locked: unknown error'></i>"; break;
|
||||
}
|
||||
return $status.$link.$luks;
|
||||
if ($show && $online) switch ($disk['luksState']) {
|
||||
case 0: $luks = "<i class='nolock fa fa-lock'></i>"; break;
|
||||
case 1: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-unlock-alt green-text'></i><span>Encrypted and unlocked</span></a>"; break;
|
||||
case 2: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-lock red-text'></i><span>Locked: missing encryption key</span></a>"; break;
|
||||
case 3: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-lock red-text'></i><span>Locked: wrong encryption key</span></a>"; break;
|
||||
default: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-lock red-text'></i><span>Locked: unknown error</span></a>"; break;
|
||||
} else $luks = '';
|
||||
return $status.$luks.$link;
|
||||
}
|
||||
function device_browse(&$disk) {
|
||||
global $path;
|
||||
@@ -177,7 +177,7 @@ function array_offline(&$disk) {
|
||||
function array_online(&$disk) {
|
||||
global $sum, $diskio;
|
||||
$dev = $disk['device'];
|
||||
$data = isset($diskio[$dev]) ? explode(' ',$diskio[$dev]) : [];
|
||||
$data = explode(' ',$diskio[$dev] ?? '');
|
||||
if (is_numeric($disk['temp'])) {
|
||||
$sum['count']++;
|
||||
$sum['temp'] += $disk['temp'];
|
||||
@@ -229,16 +229,17 @@ function my_clock($time) {
|
||||
$mins = $time%60;
|
||||
return plus($days,'day',($hour|$mins)==0).plus($hour,'hour',$mins==0).plus($mins,'minute',true);
|
||||
}
|
||||
function read_disk($dev, $part) {
|
||||
function read_disk($name, $part) {
|
||||
global $var;
|
||||
$port = substr($name,-2)!='n1' ? $name : substr($name,0,-2);
|
||||
switch ($part) {
|
||||
case 'color':
|
||||
return exec("hdparm -C ".escapeshellarg("/dev/$dev")."|grep -Po active") ? 'blue-on' : 'blue-blink';
|
||||
return exec("hdparm -C ".escapeshellarg("/dev/$port")."|grep -Po 'active|unknown'") ? 'blue-on' : 'blue-blink';
|
||||
case 'temp':
|
||||
$smart = "/var/local/emhttp/smart/$dev";
|
||||
if (!file_exists($smart) || (time()-filemtime($smart)>=$var['poll_attributes'])) exec("smartctl -n standby -A ".escapeshellarg("/dev/$dev")." >".escapeshellarg($smart)." &");
|
||||
$temp = exec("awk '\$1==190||\$1==194{print \$10;exit}' $smart");
|
||||
return $temp ?: '*';
|
||||
$smart = "/var/local/emhttp/smart/$name";
|
||||
$type = $var['smType'] ?? '';
|
||||
if (!file_exists($smart) || (time()-filemtime($smart)>=$var['poll_attributes'])) exec("smartctl -n standby -A $type ".escapeshellarg("/dev/$port")." >".escapeshellarg($smart)." &");
|
||||
return exec("awk 'BEGIN{t=\"*\"} \$1==190||\$1==194{t=\$10;exit};\$1==\"Temperature:\"{t=\$2;exit} END{print t}' ".escapeshellarg($smart)." 2>/dev/null");
|
||||
}
|
||||
}
|
||||
function show_totals($text) {
|
||||
@@ -301,8 +302,10 @@ function cache_slots() {
|
||||
$out .= "</select></form>";
|
||||
return $out;
|
||||
}
|
||||
$show = false;
|
||||
switch ($_POST['device']) {
|
||||
case 'array':
|
||||
foreach ($disks as $disk) if ($disk['type']=='Data') $show |= strpos($disk['fsType'],'luks:')!==false;
|
||||
if ($var['fsState']=='Stopped') {
|
||||
foreach ($disks as $disk) {if ($disk['type']=='Parity') array_offline($disk);}
|
||||
echo "<tr class='tr_last'><td style='height:12px' colspan='11'></td></tr>";
|
||||
@@ -329,6 +332,7 @@ case 'flash':
|
||||
echo "</tr>";
|
||||
break;
|
||||
case 'cache':
|
||||
foreach ($disks as $disk) if ($disk['type']=='Cache') $show |= strpos($disk['fsType'],'luks:')!==false;
|
||||
if ($var['fsState']=='Stopped') {
|
||||
foreach ($disks as $disk) {if ($disk['type']=='Cache') array_offline($disk);}
|
||||
echo "<tr class='tr_last'><td><img src='/webGui/images/sum.png' class='icon'>Slots:</td><td colspan='9'>".cache_slots()."</td><td></td></tr>";
|
||||
|
||||
@@ -24,8 +24,8 @@ $compute = $_GET['compute'];
|
||||
$path = $_GET['path'];
|
||||
$fill = $_GET['fill'];
|
||||
|
||||
$display = [];
|
||||
$display['scale'] = $_GET['scale'];
|
||||
$display = [];
|
||||
$display['scale'] = $_GET['scale'];
|
||||
$display['number'] = $_GET['number'];
|
||||
|
||||
// Display export settings
|
||||
@@ -46,8 +46,12 @@ function shareInclude($name) {
|
||||
return !$include || substr($name,0,4)!='disk' || strpos("$include,", "$name,")!==false;
|
||||
}
|
||||
|
||||
// Compute all disk shares
|
||||
if ($compute=='yes') foreach ($disks as $name => $disk) if ($disk['exportable']=='yes') exec("webGui/scripts/disk_size ".escapeshellarg($name)." ssz2");
|
||||
// Compute all disk shares & check encryption
|
||||
$show = false;
|
||||
foreach ($disks as $name => $disk) {
|
||||
if ($compute=='yes' && $disk['exportable']=='yes') exec("webGui/scripts/disk_size ".escapeshellarg($name)." ssz2");
|
||||
if (strstr('Data,Cache',$disk['type'])) $show |= strpos($disk['fsType'],'luks:')!==false;
|
||||
}
|
||||
|
||||
// global shares include/exclude
|
||||
$myDisks = array_filter(array_diff(array_keys($disks), explode(',',$var['shareUserExclude'])), 'globalInclude');
|
||||
@@ -62,23 +66,21 @@ else
|
||||
// Build table
|
||||
$row = 0;
|
||||
foreach ($disks as $name => $disk) {
|
||||
if ($disk['type']=='Flash') continue;
|
||||
if ($disk['fsColor']=='grey-off') continue;
|
||||
if ($disk['exportable']=='no') continue;
|
||||
if (!strstr('Data,Cache',$disk['type']) || $disk['fsColor']=='grey-off' || $disk['exportable']=='no') continue;
|
||||
$row++;
|
||||
$ball = "/webGui/images/{$disk['fsColor']}.png";
|
||||
switch ($disk['fsColor']) {
|
||||
case 'green-on': $help = 'All files protected'; break;
|
||||
case 'yellow-on': $help = 'All files unprotected'; break;
|
||||
}
|
||||
switch ($disk['luksState']) {
|
||||
case 0: $luks = ""; break;
|
||||
case 1: $luks = "<i class='padlock green-text fa fa-unlock-alt' title='All files in share encrypted'></i>"; break;
|
||||
case 2: $luks = "<i class='padlock orange-text fa fa-unlock-alt' title='Some files in share unencrypted'></i>"; break;
|
||||
default: $luks = ""; break;
|
||||
}
|
||||
if ($show) switch ($disk['luksState']) {
|
||||
case 0: $luks = "<i class='nolock fa fa-lock'></i>"; break;
|
||||
case 1: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-unlock-alt green-text'></i><span>All files encrypted</span></a>"; break;
|
||||
case 2: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-unlock-alt orange-text'></i><span>Some or all files unencrypted</span></a>"; break;
|
||||
default: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-lock red-text'></i><span>Unknown encryption state'</span></a>"; break;
|
||||
} else $luks = "";
|
||||
echo "<tr>";
|
||||
echo "<td><a class='info nohand' onclick='return false'><img src='$ball' class='icon'><span style='left:18px'>$help</span></a><a href='$path/Disk?name=$name' onclick=\"$.cookie('one','tab1',{path:'/'})\">$name</a>$luks</td>";
|
||||
echo "<td><a class='info nohand' onclick='return false'><img src='$ball' class='icon'><span style='left:18px'>$help</span></a>$luks<a href='$path/Disk?name=$name' onclick=\"$.cookie('one','tab1',{path:'/'})\">$name</a></td>";
|
||||
echo "<td>{$disk['comment']}</td>";
|
||||
echo "<td>".disk_share_settings($var['shareSMBEnabled'], $sec[$name])."</td>";
|
||||
echo "<td>".disk_share_settings($var['shareNFSEnabled'], $sec_nfs[$name])."</td>";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2016, Lime Technology
|
||||
* Copyright 2012-2016, Bergware International.
|
||||
/* Copyright 2005-2017, Lime Technology
|
||||
* Copyright 2012-2017, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?: @$_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot = $docroot ?: $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// Helper functions
|
||||
@@ -50,7 +50,7 @@ function my_temp($value) {
|
||||
global $display;
|
||||
$unit = $display['unit'];
|
||||
$number = $display['number'];
|
||||
return is_numeric($value) ? (($unit=='C' ? str_replace('.', $number[0], $value) : round(9/5*$value+32))." $unit") : $value;
|
||||
return is_numeric($value) ? (($unit=='F' ? round(9/5*$value+32) : str_replace('.', $number[0], $value))." $unit") : $value;
|
||||
}
|
||||
function my_disk($name) {
|
||||
return ucfirst(preg_replace('/^(disk|cache|parity)(\d+)/','$1 $2',$name));
|
||||
|
||||
@@ -24,8 +24,8 @@ $compute = $_GET['compute'];
|
||||
$path = $_GET['path'];
|
||||
$fill = $_GET['fill'];
|
||||
|
||||
$display = [];
|
||||
$display['scale'] = $_GET['scale'];
|
||||
$display = [];
|
||||
$display['scale'] = $_GET['scale'];
|
||||
$display['number'] = $_GET['number'];
|
||||
|
||||
if (!$shares) {
|
||||
@@ -53,8 +53,12 @@ function shareInclude($name) {
|
||||
return !$include || substr($name,0,4)!='disk' || strpos("$include,", "$name,")!==false;
|
||||
}
|
||||
|
||||
// Compute all user shares
|
||||
if ($compute=='yes') foreach ($shares as $name => $share) exec("webGui/scripts/share_size ".escapeshellarg($name)." ssz1");
|
||||
// Compute all user shares & check encryption
|
||||
$show = false;
|
||||
foreach ($shares as $name => $share) {
|
||||
if ($compute=='yes') exec("webGui/scripts/share_size ".escapeshellarg($name)." ssz1");
|
||||
$show |= $share['luksStatus']>0;
|
||||
}
|
||||
|
||||
// global shares include/exclude
|
||||
$myDisks = array_filter(array_diff(array_keys($disks), explode(',',$var['shareUserExclude'])), 'globalInclude');
|
||||
@@ -75,14 +79,14 @@ foreach ($shares as $name => $share) {
|
||||
case 'green-on': $help = 'All files protected'; break;
|
||||
case 'yellow-on': $help = 'Some or all files unprotected'; break;
|
||||
}
|
||||
switch ($share['luksStatus']) {
|
||||
case 0: $luks = ""; break;
|
||||
case 1: $luks = "<i class='padlock green-text fa fa-unlock-alt' title='All files in share encrypted'></i>"; break;
|
||||
case 2: $luks = "<i class='padlock orange-text fa fa-unlock-alt' title='Some files in share unencrypted'></i>"; break;
|
||||
default: $luks = ""; break;
|
||||
}
|
||||
if ($show) switch ($share['luksStatus']) {
|
||||
case 0: $luks = "<i class='nolock fa fa-lock'></i>"; break;
|
||||
case 1: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-unlock-alt green-text'></i><span>All files encrypted</span></a>"; break;
|
||||
case 2: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-unlock-alt orange-text'></i><span>Some or all files unencrypted</span></a>"; break;
|
||||
default: $luks = "<a class='info' onclick='return false'><i class='padlock fa fa-lock red-text'></i><span>Unknown encryption state'</span></a>"; break;
|
||||
} else $luks = "";
|
||||
echo "<tr>";
|
||||
echo "<td><a class='info nohand' onclick='return false'><img src='$ball' class='icon'><span style='left:18px'>$help</span></a><a href='$path/Share?name=".urlencode($name)."' onclick=\"$.cookie('one','tab1',{path:'/'})\">$name</a>$luks</td>";
|
||||
echo "<td><a class='info nohand' onclick='return false'><img src='$ball' class='icon'><span style='left:18px'>$help</span></a>$luks<a href='$path/Share?name=".urlencode($name)."' onclick=\"$.cookie('one','tab1',{path:'/'})\">$name</a></td>";
|
||||
echo "<td>{$share['comment']}</td>";
|
||||
echo "<td>".user_share_settings($var['shareSMBEnabled'], $sec[$name])."</td>";
|
||||
echo "<td>".user_share_settings($var['shareNFSEnabled'], $sec_nfs[$name])."</td>";
|
||||
|
||||
@@ -28,47 +28,36 @@ function duration(&$hrs) {
|
||||
function spindownDelay($port) {
|
||||
$disks = parse_ini_file('state/disks.ini',true);
|
||||
foreach ($disks as $disk) {
|
||||
if ($disk['device']==$port) { file_put_contents("/var/tmp/diskSpindownDelay.{$disk['idx']}", $disk['spindownDelay']); break; }
|
||||
$name = substr($disk['device'],-2)!='n1' ? $disk['device'] : substr($disk['device'],0,-2);
|
||||
if ($name==$port) {file_put_contents("/var/tmp/diskSpindownDelay.{$disk['idx']}", $disk['spindownDelay']); break;}
|
||||
}
|
||||
}
|
||||
function get(&$ref,$n,$d) {
|
||||
global $var;
|
||||
$val = $ref[$n] ?? -1; if ($val==-1) $val = $var[$n] ?? $d;
|
||||
return $val;
|
||||
}
|
||||
function exist(&$ref) {
|
||||
return isset($ref) && strlen($ref);
|
||||
}
|
||||
function append(&$ref, &$info) {
|
||||
if (isset($info)) $ref .= ($ref ? " " : "").$info;
|
||||
if ($info) $ref .= ($ref ? " " : "").$info;
|
||||
}
|
||||
$disks = []; $var = [];
|
||||
require_once "$docroot/webGui/include/CustomMerge.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Preselect.php";
|
||||
$name = $_POST['name'] ?? '';
|
||||
$port = $_POST['port'] ?? '';
|
||||
if ($name) {
|
||||
$disk = &$disks[$name];
|
||||
$type = get($disk,'smType','');
|
||||
if ($type) {
|
||||
$ports = [];
|
||||
if (exist($disk['smDevice'])) $port = $disk['smDevice'];
|
||||
if (exist($disk['smPort1'])) $ports[] = $disk['smPort1'];
|
||||
if (exist($disk['smPort2'])) $ports[] = $disk['smPort2'];
|
||||
if (exist($disk['smPort3'])) $ports[] = $disk['smPort3'];
|
||||
if ($ports) $type .= ','.implode($disk['smGlue'] ?? ',',$ports);
|
||||
}
|
||||
$type = get_value($disk,'smType','');
|
||||
get_ctlr_options($type, $disk);
|
||||
} else {
|
||||
$disk = [];
|
||||
$type = '';
|
||||
}
|
||||
$port = port_name($disk['smDevice'] ?? $port);
|
||||
switch ($_POST['cmd']) {
|
||||
case "attributes":
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Preselect.php";
|
||||
$select = get($disk,'smSelect',0);
|
||||
$level = get($disk,'smLevel',1);
|
||||
$events = explode('|',$disk['smEvents'] ?? $var['smEvents'] ?? $numbers);
|
||||
$temps = [190,194];
|
||||
$select = get_value($disk,'smSelect',0);
|
||||
$level = get_value($disk,'smLevel',1);
|
||||
$events = explode('|',get_value($disk,'smEvents',$numbers));
|
||||
$unraid = parse_plugin_cfg('dynamix',true);
|
||||
$max = $unraid['display']['max'];
|
||||
$hot = $unraid['display']['hot'];
|
||||
$max = $disk['maxTemp'] ?? $unraid['display']['max'];
|
||||
$hot = $disk['hotTemp'] ?? $unraid['display']['hot'];
|
||||
exec("smartctl -A $type ".escapeshellarg("/dev/$port")."|awk 'NR>4'",$output);
|
||||
if (strpos($output[0], 'SMART Attributes Data Structure')===0) {
|
||||
$output = array_slice($output, 3);
|
||||
@@ -79,8 +68,8 @@ case "attributes":
|
||||
$color = "";
|
||||
$highlight = strpos($info[8],'FAILING_NOW')!==false || ($select ? $info[5]>0 && $info[3]<=$info[5]*$level : $info[9]>0);
|
||||
if (in_array($info[0], $events) && $highlight) $color = " class='warn'";
|
||||
elseif (in_array($info[0], $temps)) {
|
||||
if ($info[9]>=$max) $color = " class='alert'"; elseif ($info[9]>=$hot) $color = " class='warn'";
|
||||
elseif (in_array($info[0], [190,194])) {
|
||||
if ($info[9]>=$max && $max>0) $color = " class='alert'"; elseif ($info[9]>=$hot && $hot>0) $color = " class='warn'";
|
||||
}
|
||||
if ($info[8]=='-') $info[8] = 'Never';
|
||||
if ($info[0]==9 && is_numeric($info[9])) duration($info[9]);
|
||||
@@ -93,7 +82,19 @@ case "attributes":
|
||||
foreach ($output as $line) {
|
||||
if (strpos($line,':')===false) continue;
|
||||
list($name,$value) = explode(':', $line);
|
||||
echo "<tr><td>-</td><td>".ucfirst(strtolower($name))."</td><td colspan='8'>".trim($value)."</td></tr>";
|
||||
$name = ucfirst(strtolower($name));
|
||||
$value = trim($value);
|
||||
$color = '';
|
||||
switch ($name) {
|
||||
case 'Temperature':
|
||||
$temp = strtok($value,' ');
|
||||
if ($temp>=$max && $max>0) $color = " class='alert'"; elseif ($temp>=$hot && $hot>0) $color = " class='warn'";
|
||||
break;
|
||||
case 'Power on hours':
|
||||
if (is_numeric($value)) duration($value);
|
||||
break;
|
||||
}
|
||||
echo "<tr{$color}><td>-</td><td>$name</td><td colspan='8'>$value</td></tr>";
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -123,7 +124,7 @@ case "identify":
|
||||
exec("smartctl -H $type ".escapeshellarg("/dev/$port")."|grep -Pom1 '^SMART.*: [A-Z]+'|sed 's:self-assessment test result::'",$output);
|
||||
$empty = true;
|
||||
foreach ($output as $line) {
|
||||
if (!strlen($line)) continue;
|
||||
if (!$line) continue;
|
||||
if (strpos($line,'VALID ARGUMENTS')!==false) break;
|
||||
list($title,$info) = array_map('trim', explode(':', $line, 2));
|
||||
if (in_array($info,$passed)) $info = "<span class='green-text'>Passed</span>";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2016, Lime Technology
|
||||
* Copyright 2012-2016, Bergware International.
|
||||
/* Copyright 2005-2017, Lime Technology
|
||||
* Copyright 2012-2017, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?: @$_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot = $docroot ?: $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
// Wrapper functions
|
||||
function parse_plugin_cfg($plugin, $sections=false) {
|
||||
@@ -52,4 +52,22 @@ function plugin_update_available($plugin, $os=false) {
|
||||
if (version_compare($server, $unraid, '>=')) return $remote;
|
||||
}
|
||||
}
|
||||
|
||||
function get_value(&$object,$name,$default) {
|
||||
global $var;
|
||||
$value = $object[$name] ?? -1;
|
||||
return $value!==-1 ? $value : ($var[$name] ?? $default);
|
||||
}
|
||||
|
||||
function get_ctlr_options(&$type, &$disk) {
|
||||
if (!$type) return;
|
||||
$ports = [];
|
||||
if (strlen($disk['smPort1'])) $ports[] = $disk['smPort1'];
|
||||
if (strlen($disk['smPort2'])) $ports[] = $disk['smPort2'];
|
||||
if (strlen($disk['smPort3'])) $ports[] = $disk['smPort3'];
|
||||
$type .= ($ports ? ','.implode($disk['smGlue'] ?? ',',$ports) : '');
|
||||
}
|
||||
function port_name($port) {
|
||||
return substr($port,-2)!='n1' ? $port : substr($port,0,-2);
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2016, Lime Technology
|
||||
* Copyright 2012-2016, Bergware International.
|
||||
/* Copyright 2005-2017, Lime Technology
|
||||
* Copyright 2012-2017, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -19,7 +19,7 @@ $cli = empty($zip);
|
||||
$get = "/var/local/emhttp";
|
||||
$var = file_exists("$get/var.ini") ? parse_ini_file("$get/var.ini") : [];
|
||||
|
||||
$docroot = $docroot ?: @$_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot = $docroot ?: $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/extra','/boot/syslinux','/var/log','/var/log/plugins','/var/log/packages','/tmp'];
|
||||
|
||||
function anonymize($text,$select) {
|
||||
@@ -176,31 +176,22 @@ if ($qemu) {
|
||||
// create SMART reports (suppress errors)
|
||||
$disks = file_exists("$get/disks.ini") ? parse_ini_file("$get/disks.ini", true) : [];
|
||||
include_once "$docroot/webGui/include/CustomMerge.php";
|
||||
include_once "$docroot/webGui/include/Wrappers.php";
|
||||
exec("ls -l /dev/disk/by-id/[asun]* 2>/dev/null|sed '/-part/d;s|^.*/by-id/[^-]*-||;s|-> ../../||;s|:|-|'", $devices);
|
||||
foreach ($devices as $device) {
|
||||
list($name,$dev) = explode(' ',$device);
|
||||
$type = '';
|
||||
$diskName = '';
|
||||
list($name,$port) = explode(' ',$device);
|
||||
$diskName = ''; $type = '';
|
||||
foreach ($disks as $find) {
|
||||
if ($find['device']==$dev) {
|
||||
if ($find['device']==$port) {
|
||||
$diskName = $find['name'];
|
||||
$type = isset($find['smType']) ? $find['smType'] : -1;
|
||||
if ($type==-1) $type = isset($var['smType']) ? $var['smType'] : '';
|
||||
if ($type) {
|
||||
$ports = [];
|
||||
if (isset($find['smDevice']) && strlen($find['smDevice'])) $port = $find['smDevice'];
|
||||
if (isset($find['smPort1']) && strlen($find['smPort1'])) $ports[] = $find['smPort1'];
|
||||
if (isset($find['smPort2']) && strlen($find['smPort2'])) $ports[] = $find['smPort2'];
|
||||
if (isset($find['smPort3']) && strlen($find['smPort3'])) $ports[] = $find['smPort3'];
|
||||
if ($ports) {
|
||||
$glue = isset($find['smGlue']) ? $find['smGlue'] : ',';
|
||||
$type .= ','.implode($glue,$ports);
|
||||
}
|
||||
}
|
||||
$type = get_value($find,'smType','');
|
||||
get_ctlr_options($type, $find);
|
||||
$port = $find['smDevice'] ?? $port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
exec("smartctl -a $type ".escapeshellarg("/dev/$dev")." 2>/dev/null|todos >".escapeshellarg("/$diag/smart/$name-$date $diskName ($dev).txt"));
|
||||
$port = port_name($port);
|
||||
exec("smartctl -a $type ".escapeshellarg("/dev/$port")." 2>/dev/null|todos >".escapeshellarg("/$diag/smart/$name-$date $diskName ($port).txt"));
|
||||
}
|
||||
// create cache pool information
|
||||
if (is_dir('/mnt/cache') && strpos($disks['cache']['fsType'],'btrfs')) {
|
||||
|
||||
@@ -16,7 +16,7 @@ $var = parse_ini_file("/var/local/emhttp/var.ini");
|
||||
$devs = parse_ini_file("/var/local/emhttp/devs.ini",true);
|
||||
$disks = parse_ini_file("/var/local/emhttp/disks.ini",true);
|
||||
|
||||
$docroot = $docroot ?: @$_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot = $docroot ?: $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Preselect.php";
|
||||
require_once "$docroot/webGui/include/CustomMerge.php";
|
||||
@@ -37,27 +37,31 @@ function plus($val,$word,$last) {
|
||||
function my_temp($value) {
|
||||
global $unraid;
|
||||
$unit = $unraid['display']['unit'];
|
||||
return ($unit=='F' ? round(9/5*$value+32) : str_replace('.', $unraid['display']['number'][0], $value))." $unit";
|
||||
return ($unit=='F' ? round(9/5*$value+32) : $value)." $unit";
|
||||
}
|
||||
function my_disk($name) {
|
||||
return ucfirst(preg_replace('/^(disk|cache)([0-9]+)/','$1 $2',$name));
|
||||
return ucfirst(preg_replace('/^(disk|cache|parity)(\d+)/','$1 $2',$name));
|
||||
}
|
||||
function my_scale($value,&$unit,$precision=NULL) {
|
||||
function my_scale($value, &$unit, $decimals=NULL, $scale=NULL) {
|
||||
global $unraid;
|
||||
$scale = $unraid['display']['scale'];
|
||||
$scale = $scale ?? $unraid['display']['scale'];
|
||||
$number = $unraid['display']['number'];
|
||||
$units = ['B','KB','MB','GB','TB','PB'];
|
||||
if ($scale==0 && $precision===NULL) {
|
||||
$units = ['B','KB','MB','GB','TB','PB','EB','ZB','YB'];
|
||||
$size = count($units);
|
||||
if ($scale==0 && ($decimals===NULL || $decimals<0)) {
|
||||
$decimals = 0;
|
||||
$unit = '';
|
||||
return number_format($value, 0, $number[0], ($value>=10000 ? $number[1] : ''));
|
||||
} else {
|
||||
$base = $value ? floor(log($value, 1000)) : 0;
|
||||
if ($scale>0 && $base>$scale) $base = $scale;
|
||||
$value = round($value/pow(1000, $base), $precision===NULL ? 2 : $precision);
|
||||
if ($value>=1000 && $scale<0) { $value = 1; $base++; }
|
||||
if ($base>$size) $base = $size-1;
|
||||
$value /= pow(1000, $base);
|
||||
if ($decimals===NULL) $decimals = $value>=100 ? 0 : ($value>=10 ? 1 : (round($value*100)%100===0 ? 0 : 2));
|
||||
elseif ($decimals<0) $decimals = $value>=100||round($value*10)%10===0 ? 0 : abs($decimals);
|
||||
if ($scale<0 && round($value,-1)==1000) {$value = 1; $base++;}
|
||||
$unit = $units[$base];
|
||||
return number_format($value, $precision===NULL ? (($value-intval($value)==0 || $value>=100) ? 0 : ($value>=10 ? 1 : 2)) : $precision, $number[0], ($value>=10000 ? $number[1] : ''));
|
||||
}
|
||||
return number_format($value, $decimals, $number[0], $value>=10000 ? $number[1] : '');
|
||||
}
|
||||
function my_check($time,$speed) {
|
||||
if (!$time) return 'unavailable (no parity-check entries logged)';
|
||||
@@ -92,7 +96,7 @@ function check_temp($name,$temp,$text,$info) {
|
||||
$max = $disk['maxTemp'] ?? $unraid['display']['max'];
|
||||
$warn = $temp>=$max && $max>0 ? 'alert' : ($temp>=$hot && $hot>0 ? 'warning' : '');
|
||||
$item = 'temp';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : 0;
|
||||
$last = $saved[$item][$name] ?? 0;
|
||||
if ($warn) {
|
||||
if ($temp>$last) {
|
||||
exec("$notify -e ".escapeshellarg("unRAID $text temperature")." -s ".escapeshellarg(ucfirst($warn)." [$server] - $text ".($warn=='alert'?'overheated (':'is hot (').my_temp($temp).")")." -d ".escapeshellarg("$info")." -i \"$warn\"");
|
||||
@@ -107,27 +111,17 @@ function check_temp($name,$temp,$text,$info) {
|
||||
}
|
||||
function check_smart($name,$port,$text,$info) {
|
||||
global $var,$disks,$notify,$saved,$server,$numbers;
|
||||
$disk = &$disks[$name];
|
||||
$select = $disk['smSelect'] ?? -1; if ($select==-1) $select = $var['smSelect'] ?? 0;
|
||||
$level = $disk['smLevel'] ?? -1; if ($level==-1) $level = $var['smLevel'] ?? 1;
|
||||
$events = explode('|',$disk['smEvents'] ?? $var['smEvents'] ?? $numbers);
|
||||
$type = $disk['smType'] ?? -1; if ($type==-1) $type = $var['smType'] ?? '';
|
||||
if ($type) {
|
||||
$ports = [];
|
||||
if (!empty($disk['smDevice'])) $port = $disk['smDevice'];
|
||||
if (!empty($disk['smPort1'])) $ports[] = $disk['smPort1'];
|
||||
if (!empty($disk['smPort2'])) $ports[] = $disk['smPort2'];
|
||||
if (!empty($disk['smPort3'])) $ports[] = $disk['smPort3'];
|
||||
if ($ports) {
|
||||
$glue = isset($disk['smGlue']) ? $disk['smGlue'] : ',';
|
||||
$type .= ','.implode($glue,$ports);
|
||||
}
|
||||
}
|
||||
$disk = &$disks[$name];
|
||||
$select = get_value($disk,'smSelect',0);
|
||||
$level = get_value($disk,'smLevel',1);
|
||||
$events = explode('|',get_value($disk,'smEvents',$numbers));
|
||||
$type = get_value($disk,'smType','');
|
||||
get_ctlr_options($type, $disk);
|
||||
$file = "/var/local/emhttp/smart/$name";
|
||||
exec("awk 'NR>7{print $1,$2,$4,$6,$9,$10}' ".escapeshellarg($file)." 2>/dev/null", $codes);
|
||||
$item = 'smart';
|
||||
foreach ($codes as $code) {
|
||||
if (!$code) continue;
|
||||
if (!$code || !is_numeric($code[0])) continue;
|
||||
list($id,$class,$value,$thres,$when,$raw) = explode(' ',$code);
|
||||
$fail = strpos($when,'FAILING_NOW')!==false;
|
||||
if (!$fail && !in_array($id,$events)) continue;
|
||||
@@ -136,7 +130,7 @@ function check_smart($name,$port,$text,$info) {
|
||||
switch ($select) {
|
||||
case 0:
|
||||
$attr = "$name.$id";
|
||||
$last = isset($saved[$item][$attr]) ? $saved[$item][$attr]*$level : 0;
|
||||
$last = ($saved[$item][$attr] ?? 0)*$level;
|
||||
if ($raw>0 || $fail) {
|
||||
if ($raw>$last) {
|
||||
exec("$notify -e ".escapeshellarg("unRAID $text SMART health [$id]")." -s ".escapeshellarg("Warning [$server] - $word is $raw")." -d ".escapeshellarg("$info")." -i \"warning\"");
|
||||
@@ -153,7 +147,7 @@ function check_smart($name,$port,$text,$info) {
|
||||
break;
|
||||
case 1:
|
||||
$attr = "$name.${id}n";
|
||||
$last = isset($saved[$item][$attr]) ? $saved[$item][$attr] : 255;
|
||||
$last = $saved[$item][$attr] ?? 255;
|
||||
if (($thres>0 && $value<=$thres*$level) || $fail) {
|
||||
if ($value*($value>$thres?$level:1)<$last) {
|
||||
exec("$notify -e ".escapeshellarg("unRAID $text SMART health [$id]")." -s ".escapeshellarg("Warning [$server] - $word is $value")." -d ".escapeshellarg("$info")." -i \"warning\"");
|
||||
@@ -171,7 +165,7 @@ function check_smart($name,$port,$text,$info) {
|
||||
}
|
||||
}
|
||||
$file .= '.ssa';
|
||||
if (!file_exists($file) || (time()-filemtime($file)>=$var['poll_attributes'])) exec("smartctl -n standby -H ".escapeshellarg($type)." ".escapeshellarg("/dev/$port")."|grep -Pom1 '^SMART.*: \K[A-Z]+'|tr -d '\n' > ".escapeshellarg($file));
|
||||
if (!file_exists($file) || (time()-filemtime($file)>$var['poll_attributes'])) exec("smartctl -H $type ".escapeshellarg("/dev/$port")."|grep -Pom1 '^SMART.*: \K[A-Z]+'|tr -d '\n' >".escapeshellarg($file));
|
||||
}
|
||||
function check_usage($name,$used,$text,$info) {
|
||||
global $notify,$disks,$saved,$unraid,$server;
|
||||
@@ -181,7 +175,7 @@ function check_usage($name,$used,$text,$info) {
|
||||
$critical = $disk['critical'] ?? $unraid['display']['critical'];
|
||||
$warn = $used>=$critical && $critical>0 ? 'alert' : ($used>=$warning && $warning>0 ? 'warning' : '');
|
||||
$item = 'used';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : 0;
|
||||
$last = $saved[$item][$name] ?? 0;
|
||||
if ($warn) {
|
||||
if ($used>$last) {
|
||||
exec("$notify -e ".escapeshellarg("unRAID $text disk utilization")." -s ".escapeshellarg(ucfirst($warn)." [$server] - $text is ".($warn=='alert'?'low on space':'high on usage')." (${used}%)")." -d ".escapeshellarg("$info")." -i \"$warn\"");
|
||||
@@ -204,13 +198,13 @@ foreach ($disks as $disk) {
|
||||
// process disk temperature notifications
|
||||
check_temp($name,$disk['temp'],$text,$info);
|
||||
// process disk SMART notifications
|
||||
check_smart($name,$disk['device'],$text,$info);
|
||||
check_smart($name,port_name($disk['smDevice'] ?? $disk['device']),$text,$info);
|
||||
// process disk usage notifications
|
||||
check_usage($name,($disk['fsSize']?100-round(100*$disk['fsFree']/$disk['fsSize']):-1),$text,$info);
|
||||
// process disk operation notifications
|
||||
$warn = strtok($disk['color'],'-');
|
||||
$item = 'disk';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : "";
|
||||
$last = $saved[$item][$name] ?? '';
|
||||
switch ($warn) {
|
||||
case 'red':
|
||||
if ($warn!=$last) {
|
||||
@@ -257,22 +251,23 @@ foreach ($disks as $disk) {
|
||||
// check unassigned devices
|
||||
foreach ($devs as $dev) {
|
||||
$name = $dev['device'];
|
||||
if (empty($name)) continue;
|
||||
$smart = "/var/local/emhttp/smart/$name";
|
||||
if (!file_exists($smart) || (time()-filectime($smart)>=$var['poll_attributes'])) exec("smartctl -n standby -A ".escapeshellarg("/dev/$name")." > ".escapeshellarg($smart));
|
||||
$temp = exec("awk '\$1==190||\$1==194{print \$10;exit}' ".escapeshellarg($smart));
|
||||
$type = $var['smType'] ?? '';
|
||||
$port = port_name($name);
|
||||
if (!file_exists($smart) || (time()-filectime($smart)>$var['poll_attributes'])) exec("smartctl -A $type ".escapeshellarg("/dev/$port")." >".escapeshellarg($smart));
|
||||
$temp = exec("awk 'BEGIN{t=\"*\"} \$1==190||\$1==194{t=\$10;exit};\$1==\"Temperature:\"{t=\$2;exit} END{print t}' ".escapeshellarg($smart)." 2>/dev/null");
|
||||
$text = "device $name";
|
||||
$info = !empty($dev['id']) ? "{$dev['id']} ($name)": "No device identification ($name)";
|
||||
// process disk temperature notifications
|
||||
check_temp($name,$temp,$text,$info);
|
||||
// process disk SMART notifications
|
||||
check_smart($name,$dev['device'],$text,$info);
|
||||
check_smart($name,$port,$text,$info);
|
||||
}
|
||||
|
||||
// report array read errors
|
||||
$item = 'array';
|
||||
$name = 'errors';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : 0;
|
||||
$last = $saved[$item][$name] ?? 0;
|
||||
$warn = count($errors);
|
||||
$info = "Array has $warn disk".($warn==1 ? "" : "s")." with read errors";
|
||||
if ($warn>0) {
|
||||
@@ -290,7 +285,7 @@ if ($warn>0) {
|
||||
|
||||
// process parity check, parity sync and data-rebuild notifications
|
||||
$name = 'parity';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : '';
|
||||
$last = $saved[$item][$name] ?? '';
|
||||
if ($var['mdResync']>0) {
|
||||
if (!$last) {
|
||||
if (strstr($var['mdResyncAction'],"recon")) {
|
||||
@@ -321,7 +316,7 @@ if ($var['mdResync']>0) {
|
||||
|
||||
// check read-write status of USB flash drive
|
||||
$name = 'flash';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : '';
|
||||
$last = $saved[$item][$name] ?? '';
|
||||
$warn = exec("grep -Pom1 '/boot \S+ \K\S{2}' /proc/mounts");
|
||||
$info = "{$disks['flash']['id']} ({$disks['flash']['device']})";
|
||||
if ($warn!="rw") {
|
||||
@@ -341,7 +336,7 @@ system('mountpoint -q /var/lib/docker', $retval);
|
||||
if ($retval===0) {
|
||||
$item = 'system';
|
||||
$name = 'docker';
|
||||
$last = isset($saved[$item][$name]) ? $saved[$item][$name] : '';
|
||||
$last = $saved[$item][$name] ?? '';
|
||||
if (file_exists("/boot/config/docker.cfg")) {
|
||||
$cfg = parse_ini_file("/boot/config/docker.cfg");
|
||||
$info = "Docker utilization of image file {$cfg['DOCKER_IMAGE_FILE']}";
|
||||
|
||||
@@ -9,9 +9,9 @@ a:hover{text-decoration:underline}
|
||||
a{color:#486DBA;text-decoration:none}
|
||||
a.none{color:#606E7F}
|
||||
a.img{text-decoration:none;border:none}
|
||||
a.info{position:relative;z-index:1}
|
||||
a.info span{display:none}
|
||||
a.info:hover span{display:block;white-space:nowrap;font-variant:small-caps;position:absolute;left:8px;color:#4F4F4F;font-size:13px;line-height:20px;padding:5px 8px;border:1px solid #42453E;border-radius:3px;background-color:#EDEAEF}
|
||||
a.info{position:relative}
|
||||
a.info span{display:none;white-space:nowrap;font-variant:small-caps;position:absolute;top:16px;left:12px;color:#4F4F4F;font-size:13px;line-height:20px;padding:5px 8px;border:1px solid #42453E;border-radius:3px;background-color:#EDEAEF}
|
||||
a.info:hover span{display:block;z-index:1}
|
||||
a.nohand{cursor:default}
|
||||
i.spacing{margin-left:0;margin-right:10px}
|
||||
i.icon{margin-right:4px}
|
||||
@@ -223,7 +223,9 @@ span.three{margin-left:-20px}
|
||||
span.tub{margin-right:8px;font-size:24px;cursor:pointer}
|
||||
span.score{font-size:11px;color:#FFFFFF;position:absolute}
|
||||
span#dropbox{background:none;line-height:60px;margin-right:20px}
|
||||
i.padlock{margin-left:8px;cursor:help}
|
||||
i.padlock{margin-right:8px;cursor:default}
|
||||
i.nolock{visibility:hidden;margin-right:8px}
|
||||
i.lock{margin-left:8px;cursor:default}
|
||||
img.icon{margin:-3px 4px 0 0}
|
||||
img.list{width:auto;max-width:48px;height:48px}
|
||||
div.content{position:absolute;top:0;left:0;width:100%;padding-bottom:30px;z-index:-1;clear:both}
|
||||
|
||||
@@ -9,10 +9,9 @@ a:hover{text-decoration:underline}
|
||||
a{color:#486DBA;text-decoration:none}
|
||||
a.none{color:#808080}
|
||||
a.img{text-decoration:none;border:none}
|
||||
a.info{position:relative;z-index:1}
|
||||
a.info span{display:none}
|
||||
a.info:hover span{display:block;white-space:nowrap;font-variant:small-caps;position:absolute;left:8px;font-size:11px;line-height:20px;color:#FFFFFF;padding:5px 8px;border:1px solid rgba(255,255,255,0.25);border-radius:3px;background-color:rgba(25,25,25,0.95);box-shadow:0 0 3px #505050}
|
||||
a.info:hover span.left{left:-182px}
|
||||
a.info{position:relative}
|
||||
a.info span{display:none;white-space:nowrap;font-variant:small-caps;position:absolute;top:16px;left:12px;font-size:12px;line-height:20px;color:#FFFFFF;padding:5px 8px;border:1px solid rgba(255,255,255,0.25);border-radius:3px;background-color:rgba(25,25,25,0.95);box-shadow:0 0 3px #505050}
|
||||
a.info:hover span{display:block;z-index:1}
|
||||
a.nohand{cursor:default}
|
||||
i.spacing{margin-left:-6px}
|
||||
i.icon{margin-right:4px}
|
||||
@@ -201,7 +200,9 @@ span.two{margin-left:-17px}
|
||||
span.three{margin-left:-20px}
|
||||
span.tub{margin-right:8px;font-size:24px;cursor:pointer}
|
||||
span.score{font-size:11px;color:#F0F0F0;position:absolute}
|
||||
i.padlock{margin-left:8px;cursor:help}
|
||||
i.padlock{margin-right:8px;cursor:default}
|
||||
i.nolock{visibility:hidden;margin-right:8px}
|
||||
i.lock{margin-left:8px;cursor:default}
|
||||
img.icon{margin:-3px 4px 0 0}
|
||||
img.list{width:auto;max-width:48px;height:48px}
|
||||
div.content{position:absolute;top:45px;left:0;width:100%;padding-bottom:30px;z-index:-1;clear:both}
|
||||
|
||||
@@ -9,9 +9,9 @@ a:hover{text-decoration:underline}
|
||||
a{color:#486DBA;text-decoration:none}
|
||||
a.none{color:#606E7F}
|
||||
a.img{text-decoration:none;border:none}
|
||||
a.info{position:relative;z-index:1}
|
||||
a.info span{display:none}
|
||||
a.info:hover span{display:block;white-space:nowrap;font-variant:small-caps;position:absolute;left:8px;color:#B0B0B0;font-size:13px;line-height:20px;padding:5px 8px;border:1px solid #42453E;border-radius:3px;background-color:#121510}
|
||||
a.info{position:relative}
|
||||
a.info span{display:none;white-space:nowrap;font-variant:small-caps;position:absolute;top:16px;left:10px;color:#B0B0B0;font-size:13px;line-height:20px;padding:5px 8px;border:1px solid #42453E;border-radius:3px;background-color:#121510}
|
||||
a.info:hover span{display:block;z-index:1}
|
||||
a.nohand{cursor:default}
|
||||
i.spacing{margin-left:0;margin-right:10px}
|
||||
i.icon{margin-right:4px}
|
||||
@@ -223,7 +223,9 @@ span.three{margin-left:-20px}
|
||||
span.tub{margin-right:8px;font-size:24px;cursor:pointer}
|
||||
span.score{font-size:11px;color:#FFFFFF;position:absolute}
|
||||
span#dropbox{background:none;line-height:60px;margin-right:20px}
|
||||
i.padlock{margin-left:8px;cursor:help}
|
||||
i.padlock{margin-right:8px;cursor:default}
|
||||
i.nolock{visibility:hidden;margin-right:8px}
|
||||
i.lock{margin-left:8px;cursor:default}
|
||||
img.icon{margin:-3px 4px 0 0}
|
||||
img.list{width:auto;max-width:48px;height:48px}
|
||||
div.content{position:absolute;top:0;left:0;width:100%;padding-bottom:30px;z-index:-1;clear:both}
|
||||
|
||||
@@ -9,10 +9,9 @@ a:hover{text-decoration:underline}
|
||||
a{color:#00529B;text-decoration:none}
|
||||
a.none{color:#303030}
|
||||
a.img{text-decoration:none;border:none}
|
||||
a.info{position:relative;z-index:1}
|
||||
a.info span{display:none}
|
||||
a.info:hover span{display:block;white-space:nowrap;font-variant:small-caps;position:absolute;left:8px;font-size:11px;line-height:20px;color:#FFFFFF;padding:5px 8px;border:1px solid rgba(255,255,255,0.25);border-radius:3px;background-color:rgba(25,25,25,0.95);box-shadow:0 0 3px #303030}
|
||||
a.info:hover span.left{left:-182px}
|
||||
a.info{position:relative}
|
||||
a.info span{display:none;white-space:nowrap;font-variant:small-caps;position:absolute;top:16px;left:12px;font-size:12px;line-height:20px;color:#FFFFFF;padding:5px 8px;border:1px solid rgba(255,255,255,0.25);border-radius:3px;background-color:rgba(25,25,25,0.95);box-shadow:0 0 3px #303030}
|
||||
a.info:hover span{display:block;z-index:1}
|
||||
a.nohand{cursor:default}
|
||||
i.spacing{margin-left:-6px}
|
||||
i.icon{margin-right:4px}
|
||||
@@ -201,7 +200,9 @@ span.two{margin-left:-17px}
|
||||
span.three{margin-left:-20px}
|
||||
span.tub{margin-right:8px;font-size:24px;cursor:pointer}
|
||||
span.score{font-size:11px;color:#F0F0F0;position:absolute}
|
||||
i.padlock{margin-left:8px;cursor:help}
|
||||
i.padlock{margin-right:8px;cursor:default}
|
||||
i.nolock{visibility:hidden;margin-right:8px}
|
||||
i.lock{margin-left:8px;cursor:default}
|
||||
img.icon{margin:-3px 4px 0 0}
|
||||
img.list{width:auto;max-width:48px;height:48px}
|
||||
div.content{position:absolute;top:45px;left:0;width:100%;padding-bottom:30px;z-index:-1;clear:both}
|
||||
|
||||
Reference in New Issue
Block a user