From 629a40ca0b085afc2b4b566fde51f5f02f6e6ce8 Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 29 May 2025 23:29:57 +0200 Subject: [PATCH 01/13] Encryption: fix passphrase encryption not working in some cases --- emhttp/plugins/dynamix/ArrayOperation.page | 2 +- emhttp/plugins/dynamix/DiskSettings.page | 2 +- emhttp/plugins/dynamix/include/update.encryption.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 2dc4541e7..475c6c7b8 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -140,7 +140,7 @@ function toggle_diskio(init) { } function base64(str) { - return window.btoa(unescape(encodeURIComponent(str))); + return window.btoa(decodeURIComponent(encodeURIComponent(str))); } function selectInput(form) { diff --git a/emhttp/plugins/dynamix/DiskSettings.page b/emhttp/plugins/dynamix/DiskSettings.page index 6ea29a07d..0a885b352 100644 --- a/emhttp/plugins/dynamix/DiskSettings.page +++ b/emhttp/plugins/dynamix/DiskSettings.page @@ -29,7 +29,7 @@ foreach ($disks as $disk) if (isset($disk['fsType']) && strncmp($disk['fsType'], String.prototype.celsius = function(){return Math.round((parseInt(this)-32)*5/9).toString();} function base64(str) { - return window.btoa(unescape(encodeURIComponent(str))); + return window.btoa(decodeURIComponent(encodeURIComponent(str))); } function doDispatch(form) { var fields = {}; diff --git a/emhttp/plugins/dynamix/include/update.encryption.php b/emhttp/plugins/dynamix/include/update.encryption.php index 1bb937646..5dc5a3dcf 100644 --- a/emhttp/plugins/dynamix/include/update.encryption.php +++ b/emhttp/plugins/dynamix/include/update.encryption.php @@ -88,7 +88,7 @@ if (isset($_POST['newinput'])) { case 'text': file_put_contents($newkey,base64_decode(_var($_POST,'newluks'))); $luks = 'luksKey'; - $data = _var($_POST,'newluks'); + $data = rawurlencode(_var($_POST,'newluks')); break; case 'file': file_put_contents($newkey,base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1])); @@ -104,7 +104,7 @@ if (isset($_POST['newinput'])) { if (count($bad)==0) { // all okay, remove the old key foreach ($good as $disk) removeKey($oldkey,$disk); - exec("emcmd 'changeDisk=apply&$luks=$data'"); + exec("emcmd ".escapeshellarg("changeDisk=apply&$luks=$data")); reply(_('Key successfully changed'),'success'); } else { // something went wrong, restore key From 1ebe7d09f84b2a6c69c0aefdbef100b010b1a09d Mon Sep 17 00:00:00 2001 From: bergware Date: Thu, 29 May 2025 23:39:13 +0200 Subject: [PATCH 02/13] Encryption: revert unescape --- emhttp/plugins/dynamix/ArrayOperation.page | 2 +- emhttp/plugins/dynamix/DiskSettings.page | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 475c6c7b8..2dc4541e7 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -140,7 +140,7 @@ function toggle_diskio(init) { } function base64(str) { - return window.btoa(decodeURIComponent(encodeURIComponent(str))); + return window.btoa(unescape(encodeURIComponent(str))); } function selectInput(form) { diff --git a/emhttp/plugins/dynamix/DiskSettings.page b/emhttp/plugins/dynamix/DiskSettings.page index 0a885b352..6ea29a07d 100644 --- a/emhttp/plugins/dynamix/DiskSettings.page +++ b/emhttp/plugins/dynamix/DiskSettings.page @@ -29,7 +29,7 @@ foreach ($disks as $disk) if (isset($disk['fsType']) && strncmp($disk['fsType'], String.prototype.celsius = function(){return Math.round((parseInt(this)-32)*5/9).toString();} function base64(str) { - return window.btoa(decodeURIComponent(encodeURIComponent(str))); + return window.btoa(unescape(encodeURIComponent(str))); } function doDispatch(form) { var fields = {}; From 587a451268976707faf1075eea76cab13166553f Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 00:42:23 +0200 Subject: [PATCH 03/13] Encryption: fix passphrase encryption not working in some cases --- emhttp/plugins/dynamix/ArrayOperation.page | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 2dc4541e7..4b1ed69d0 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -211,7 +211,7 @@ function prepareInput(form,button,parityWarn) { if (form.text.value) { var valid = new RegExp('^[ -~]+$'); if (valid.test(form.text.value)) { - $(form).append(''); + $(form).append(''); form.submit(); } else { form.input.disabled = false; From 8b44d1145db50822803f3553ddff53d29bbcbf85 Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 00:53:31 +0200 Subject: [PATCH 04/13] Updates per codeRabbit recommendations --- emhttp/plugins/dynamix/scripts/update_services | 10 +++++++++- sbin/monitor_nchan | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix/scripts/update_services b/emhttp/plugins/dynamix/scripts/update_services index 4fbebbb2a..fc381db9a 100755 --- a/emhttp/plugins/dynamix/scripts/update_services +++ b/emhttp/plugins/dynamix/scripts/update_services @@ -15,6 +15,14 @@ else log "no queued job present" fi -echo "sleep ${1:-1}; /usr/local/emhttp/webGui/scripts/reload_services" | at -M now 2>/dev/null +# Validate delay parameter is numeric +if [[ -n $1 && ! $1 =~ ^[0-9]+$ ]]; then + log "invalid delay parameter: $1, using default" + DELAY=1 +else + DELAY=${1:-1} +fi + +echo "sleep $DELAY; /usr/local/emhttp/webGui/scripts/reload_services" | at -M now 2>/dev/null log "queue new job $(queue), wait for ${1:-1}s" exit 0 diff --git a/sbin/monitor_nchan b/sbin/monitor_nchan index dc61e7deb..297af5632 100755 --- a/sbin/monitor_nchan +++ b/sbin/monitor_nchan @@ -16,7 +16,7 @@ nchan_idle(){ idle=3 for n in {1..3}; do subs=$(nchan_subs) - [[ -z $subs || $subs =~ ^[0-9]+$ && $subs -eq 0 ]] && ((idle--)) + [[ -z $subs || ( $subs =~ ^[0-9]+$ && $subs -eq 0 ) ]] && ((idle--)) sleep 3 done [[ $idle -eq 0 ]] From b53237f39d2ff66963f391b5fdfca473823b9b62 Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 01:08:44 +0200 Subject: [PATCH 05/13] Update update_services --- emhttp/plugins/dynamix/scripts/update_services | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/scripts/update_services b/emhttp/plugins/dynamix/scripts/update_services index fc381db9a..652e555b2 100755 --- a/emhttp/plugins/dynamix/scripts/update_services +++ b/emhttp/plugins/dynamix/scripts/update_services @@ -24,5 +24,5 @@ else fi echo "sleep $DELAY; /usr/local/emhttp/webGui/scripts/reload_services" | at -M now 2>/dev/null -log "queue new job $(queue), wait for ${1:-1}s" +log "queue new job $(queue), wait for ${DELAY}s" exit 0 From 2799e45205460a1cb6a98bcb5968dfa97fbe4fbc Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 01:59:28 +0200 Subject: [PATCH 06/13] encryption: include 'escapeshellarg' for script execution --- .../dynamix/include/update.encryption.php | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/emhttp/plugins/dynamix/include/update.encryption.php b/emhttp/plugins/dynamix/include/update.encryption.php index 5dc5a3dcf..e5d1d85eb 100644 --- a/emhttp/plugins/dynamix/include/update.encryption.php +++ b/emhttp/plugins/dynamix/include/update.encryption.php @@ -1,6 +1,6 @@ 1) exec("cryptsetup luksRemoveKey /dev/$disk $key &>/dev/null"); + if ($slots > 1) exec("cryptsetup luksRemoveKey ".escapeshellarg("/dev/$disk")." ".escapeshellarg($key)." &>/dev/null"); } + function diskname($name) { global $disks; - foreach ($disks as $disk) if (strncmp($name,$disk['device'],strlen($disk['device']))==0) return $disk['name']; + foreach ($disks as $disk) if (strncmp($name, $disk['device'], strlen($disk['device'])) == 0) return $disk['name']; return $name; } -function reply($text,$type) { - global $oldkey,$newkey,$delkey; + +function reply($text, $type) { + global $oldkey, $newkey, $delkey; $reply = _var($_POST,'#reply'); - if (realpath(dirname($reply))=='/var/tmp') file_put_contents($reply,$text."\0".$type); + if (realpath(dirname($reply)) == '/var/tmp') file_put_contents($reply, $text."\0".$type); delete_file($oldkey); - if (_var($_POST,'newinput','text')=='text' || $delkey) delete_file($newkey); + if (_var($_POST,'newinput','text') == 'text' || $delkey) delete_file($newkey); die(); } if (isset($_POST['oldinput'])) { switch ($_POST['oldinput']) { case 'text': - file_put_contents($oldkey,base64_decode(_var($_POST,'oldluks'))); + file_put_contents($oldkey, base64_decode(_var($_POST,'oldluks'))); break; case 'file': - file_put_contents($oldkey,base64_decode(explode(';base64,',_var($_POST,'olddata','x;base64,'))[1])); + file_put_contents($oldkey, base64_decode(explode(';base64,',_var($_POST,'olddata','x;base64,'))[1])); break; } } else { - if (is_file($newkey)) copy($newkey,$oldkey); + if (is_file($newkey)) copy($newkey, $oldkey); } if (is_file($oldkey)) { $disk = $crypto[0]; // check first disk only (key is the same for all disks) - exec("cryptsetup luksOpen --test-passphrase --key-file $oldkey /dev/$disk &>/dev/null",$null,$error); + exec("cryptsetup luksOpen --test-passphrase --key-file ".escapeshellarg($oldkey)." ".escapeshellarg("/dev/$disk")." &>/dev/null", $null, $error); } else $error = 1; if ($error > 0) reply(_('Incorrect existing key'),'warning'); @@ -86,24 +89,24 @@ if ($error > 0) reply(_('Incorrect existing key'),'warning'); if (isset($_POST['newinput'])) { switch ($_POST['newinput']) { case 'text': - file_put_contents($newkey,base64_decode(_var($_POST,'newluks'))); + file_put_contents($newkey, base64_decode(_var($_POST,'newluks'))); $luks = 'luksKey'; $data = rawurlencode(_var($_POST,'newluks')); break; case 'file': - file_put_contents($newkey,base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1])); + file_put_contents($newkey, base64_decode(explode(';base64,',_var($_POST,'newdata','x;base64,'))[1])); $luks = 'luksKey=&luksKeyfile'; $data = $newkey; break; } $good = $bad = []; foreach ($crypto as $disk) { - exec("cryptsetup luksAddKey --key-file $oldkey /dev/$disk $newkey &>/dev/null",$null,$error); - if ($error==0) $good[] = $disk; else $bad[] = diskname($disk); + exec("cryptsetup luksAddKey --key-file ".escapeshellarg($oldkey)." ".escapeshellarg("/dev/$disk")." ".escapeshellarg($newkey)." &>/dev/null", $null, $error); + if ($error == 0) $good[] = $disk; else $bad[] = diskname($disk); } - if (count($bad)==0) { + if (count($bad) == 0) { // all okay, remove the old key - foreach ($good as $disk) removeKey($oldkey,$disk); + foreach ($good as $disk) removeKey($oldkey, $disk); exec("emcmd ".escapeshellarg("changeDisk=apply&$luks=$data")); reply(_('Key successfully changed'),'success'); } else { From 49e18ced0bfdd08b790e3208d0afbe8b20b1a1c3 Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 02:19:08 +0200 Subject: [PATCH 07/13] Update update.encryption.php --- emhttp/plugins/dynamix/include/update.encryption.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/update.encryption.php b/emhttp/plugins/dynamix/include/update.encryption.php index e5d1d85eb..7093bf7ce 100644 --- a/emhttp/plugins/dynamix/include/update.encryption.php +++ b/emhttp/plugins/dynamix/include/update.encryption.php @@ -29,7 +29,7 @@ foreach (glob('/dev/disk/by-id/*CRYPT-LUKS*', GLOB_NOSORT) as $disk) { $disk = explode('-',$disk); $crypto[] = array_pop($disk); } -if (count($crypto) == 0) die(); +if (count($crypto) == 0) reply(_('No encrypted disks found'),'warning'); function delete_file(...$file) { array_map('unlink', array_filter($file,'is_file')); From faf6b7afe339f8105ff03ed6d90269de94ee9dd7 Mon Sep 17 00:00:00 2001 From: bergware Date: Fri, 30 May 2025 08:59:57 +0200 Subject: [PATCH 08/13] Miscellaneous fixes --- emhttp/plugins/dynamix/ArrayOperation.page | 179 ++++++++++-------- emhttp/plugins/dynamix/DiskSettings.page | 27 ++- emhttp/plugins/dynamix/include/KeyUpload.php | 18 +- .../dynamix/include/update.encryption.php | 7 +- emhttp/plugins/dynamix/nchan/device_list | 26 ++- 5 files changed, 147 insertions(+), 110 deletions(-) diff --git a/emhttp/plugins/dynamix/ArrayOperation.page b/emhttp/plugins/dynamix/ArrayOperation.page index 4b1ed69d0..1ea33e0a4 100644 --- a/emhttp/plugins/dynamix/ArrayOperation.page +++ b/emhttp/plugins/dynamix/ArrayOperation.page @@ -17,27 +17,40 @@ Nchan="device_list,disk_load,parity_list" ?> 0; -$poolsOnly = (_var($var,'SYS_ARRAY_SLOTS') == 0 ) ? true : false; +$poolsOnly = (_var($var,'SYS_ARRAY_SLOTS') == 0 ) ? true : false; /* only one of $present, $missing, or $wrong will be true, or all will be false */ -$forced = $present = $wrong = false; -foreach ($disks as $disk) { - if (strpos(_var($disk,'fsType'),'luks:')!==false || (_var($disk,'fsType')=='auto' && strpos(_var($var,'defaultFsType'),'luks:')!==false)) $forced = true; - if (_var($disk,'luksState',0)==1) $present = true; - if (_var($disk,'luksState',0)==2) $missing = true; - if (_var($disk,'luksState',0)==3) $wrong = true; +$forced = $present = $missing = $wrong = false; + +function luks_only(&$disk) { + return _var($disk,'type') == 'Data' || _var($disk,'type') == 'Cache'; } + +foreach (array_filter($disks,'luks_only') as $disk) { + $fsType = _var($disk,'fsType'); + $luks = str_starts_with($fsType,'luks:'); + if ($luks || ($fsType == 'auto' && str_starts_with(_var($var,'defaultFsType'),'luks:'))) $forced = true; + if ($luks) switch (_var($disk,'luksState',0)) { + case 1: $present = true; break; + case 2: $missing = true; break; + case 3: $wrong = true; break; + } +} + $encrypt = $forced || $present || $missing || $wrong; if ($forced && ($present || $missing || $wrong)) $forced = false; function check_encryption() { global $forced, $missing, $wrong; - if ($forced) $status = _('Enter new key'); - elseif ($missing) $status = _('Missing key'); - elseif ($wrong) $status = _('Wrong key'); - else return; + if ($forced) + $status = _('Enter new key'); + elseif ($missing) + $status = _('Missing key'); + elseif ($wrong) + $status = _('Wrong key'); + else + return; echo "",_('Encryption status').":$statuspermit reformat"; echo "",_('Encryption input').":"; echo "'); if (form.input === undefined) { parityWarn ? parityWarning(form,button) : form.submit(); @@ -211,7 +224,7 @@ function prepareInput(form,button,parityWarn) { if (form.text.value) { var valid = new RegExp('^[ -~]+$'); if (valid.test(form.text.value)) { - $(form).append(''); + $(form).append(''); form.submit(); } else { form.input.disabled = false; @@ -234,7 +247,7 @@ function prepareInput(form,button,parityWarn) { }); } -function parityWarning(form,button) { +function parityWarning(form, button) { if (form.md_invalidslot.checked) { var text = "_(*Dual parity* valid requires **ALL** disks in their original slots)_"; @@ -263,7 +276,7 @@ function stopArray(form) { } -function stopParity(form,text) { +function stopParity(form, text) { $(form).append(''); swal({title:"_(Proceed)_?",text:"_(This will stop the running operation)_: "+text,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) form.submit(); else $('input[name="cmdCheckCancel"]').remove();}); @@ -292,7 +305,7 @@ function parityHistory() { openChanges("parity_history", "_(Parity Operation History)_", "phistory"); } -function shutdown_now(form,cmd) { +function shutdown_now(form, cmd) { $(form).append(''); switch (cmd) { @@ -311,25 +324,25 @@ function toggleApply(checked) { $('.tabs').append(ctrl); -if ($.cookie('tab')=='tab0') $('i.toggle').hide(); +if ($.cookie('tab') == 'tab0') $('i.toggle').hide(); $('#tab'+$('input[name$="tabs"]').length).click(function(){tab0(); $('i.toggle').hide('slow');}); $('div[class=title]:not(":last, .disable_diskio") .right').each(function(){$(this).append(ctrl);}); $('.tooltip_diskio').tooltipster({delay:100,trigger:'custom',triggerOpen:{mouseenter:true},triggerClose:{click:false,scroll:true,mouseleave:true}}); - + var mymonitor = new NchanSubscriber('/sub/mymonitor',{subscriber:'websocket', reconnectTimeout:5000}); mymonitor.on('message', function(state) { switch (state) { case '0': // normal operation $('#stop-button').prop('disabled',false); $('#stop-text').html(""); - + $('#spinup-button').prop('disabled',false); $('#spindown-button').prop('disabled',false); - + $('#mover-button').prop('disabled',false); $('#mover-text').html("_(Move)_ _(will immediately invoke the Mover)_.  onclick=\"$.cookie('one','tab2')\">(_(Schedule)_)"); @@ -337,11 +350,11 @@ mymonitor.on('message', function(state) { case '1': // parity running $('#stop-button').prop('disabled',true); $('#stop-text').html("
_(Disabled)_ -- _(Parity operation is running)_"); -0):?> + 0):?> $('#spinup-button').prop('disabled',true); $('#spindown-button').prop('disabled',true); - + $('#mover-button').prop('disabled',true); $('#mover-text').html("_(Disabled)_ -- _(Parity operation is running)_"); @@ -349,7 +362,7 @@ mymonitor.on('message', function(state) { case '2': // mover running $('#stop-button').prop('disabled',true); $('#stop-text').html("
_(Disabled)_ -- _(Mover is running)_"); - + $('#mover-button').prop('disabled',true); $('#mover-text').html("_(Disabled)_ - _(Mover is running)_."); @@ -357,7 +370,7 @@ mymonitor.on('message', function(state) { case '3': // btrfs running $('#stop-button').prop('disabled',true); $('#stop-text').html("
_(Disabled)_ -- _(BTRFS operation is running)_"); - + $('#mover-button').prop('disabled',true); $('#mover-text').html("_(Disabled)_ -- _(BTRFS operation is running)_"); @@ -369,11 +382,11 @@ mymonitor.start(); var arraymonitor = new NchanSubscriber('/sub/arraymonitor',{subscriber:'websocket', reconnectTimeout:5000}); arraymonitor.on('message', function(state) { - if (state==1 && !timers.arraymonitor) timers.arraymonitor = setTimeout(refresh,1250); + if (state == 1 && !timers.arraymonitor) timers.arraymonitor = setTimeout(refresh,1250); }); var devices = new NchanSubscriber('/sub/devices',{subscriber:'websocket', reconnectTimeout:5000}); -devices.on('message', function(msg,meta) { +devices.on('message', function(msg, meta) { switch (meta.id.channel()0) { case 0: // array + pool + ua + flash devices @@ -382,9 +395,9 @@ devices.on('message', function(msg,meta) { if (recall !== null) recall.html(' '); display_diskio(); // stop updating when array is stopped - if (get.stop==1) { + if (get.stop == 1) { $('thead tr').removeClass().addClass('offline'); - + setTimeout(refresh); if (!timers.stopped) timers.stopped = setTimeout(function(){devices.stop(); arraymonitor.start();},1500); @@ -402,17 +415,17 @@ devices.on('message', function(msg,meta) { var get = JSON.parse(msg); $.each(get,function(k,v) {if ($('#line'+k).length>0) $('#line'+k).html(v);}); // button control - if ($('#pauseButton').length>0 && $('#pauseButton').prop('disabled')==false) { - if ((get === "") && $('#cancelButton').val()=="_(Cancel)_") { + if ($('#pauseButton').length > 0 && $('#pauseButton').prop('disabled') == false) { + if ((get === "") && $('#cancelButton').val() == "_(Cancel)_") { $('#cancelButton').val("_(Done)_").prop('onclick',null).off('click').click(function(){refresh();}); $('#pauseButton').prop('disabled',true); $('#cancelText').html(''); $('#line4').html("_(completed)_"); } else { var form = document.arrayOps; - if ($('#pauseButton').val()=="_(Pause)_" && get[1].search("_(paused)_")!=-1) { + if ($('#pauseButton').val() == "_(Pause)_" && get[1].search("_(paused)_") != -1) { $('#pauseButton').val("_(Resume)_").prop('onclick',null).off('click').click(function(){resumeParity(form);}); - } else if ($('#pauseButton').val()=="_(Resume)_" && get[1].search("_(paused)_")==-1) { + } else if ($('#pauseButton').val() == "_(Resume)_" && get[1].search("_(paused)_") == -1) { $('#pauseButton').val("_(Pause)_").prop('onclick',null).off('click').click(function(){pauseParity(form);}); } } @@ -422,7 +435,7 @@ devices.on('message', function(msg,meta) { }); devices.start().monitor(); - + var fsState = new NchanSubscriber('/sub/fsState',{subscriber:'websocket', reconnectTimeout:5000}); fsState.on('message', function(msg) { switch (msg) { @@ -439,7 +452,7 @@ fsState.start(); setTimeout(function(){$('#pauseButton').prop('disabled',false);$('#cancelButton').prop('disabled',false);},250); var paritymonitor = new NchanSubscriber('/sub/paritymonitor',{subscriber:'websocket', reconnectTimeout:5000}); -paritymonitor.on('message', function(busy){if (busy==1) refresh();}); +paritymonitor.on('message', function(busy){if (busy == 1) refresh();}); setTimeout(function(){paritymonitor.start();},5000); @@ -450,7 +463,7 @@ $(function(){ }); function formatWarning(val) { - if (val==true) { + if (val == true) { swal({ title:"_(Format Unmountable disks)_", text: "_(Create an empty file system on the disks shown as **Unmountable** discarding all data currently on the disks and update parity to reflect this)_. "+ @@ -465,11 +478,11 @@ function formatWarning(val) { } window.onunload = function(){ - + try {mymonitor.stop();} catch(e) {} try {devices.stop();} catch(e) {} - + try {paritymonitor.stop();} catch(e) {} } @@ -483,42 +496,42 @@ window.onunload = function(){ **_(Started)_** **_(Stop)_** _(will take the array off-line)_. -0):?> - **:**
+ 0):?> + **:**
".my_disk(_var($disk,'name'))." • ".my_id(_var($disk,'id'))." ("._var($disk,'device').")
"; if (in_array(_var($disk,'name'),$pools)) $cache[] = $disk['name']; } ?> **_(Format)_** _(will create a file system in all **Unmountable** disks)_.
- _(Yes, I want to do this)_ + _(Yes, I want to do this)_ **** . **_(Clear)_** _(will start **Disk-Clear** of new data disk(s))_. 1):?> + if ($action[0] == "check" && count($action) > 1):?> _(Parity is valid)_.**_(Check)_** _(will start **Parity-Check**)_.  onclick="$.cookie('one','tab1')">(_(Schedule)_)
_(Write corrections to parity)_ - + **_(Check)_** _(will start **Read-Check** of all array disks)_. - +
_(Error code)_:
- +
_(Duration)_:
@@ -528,7 +541,7 @@ window.onunload = function(){
+ if ($status == 0):?>
_(Duration)_:
@@ -545,24 +558,24 @@ window.onunload = function(){ endif; // end check for poolsOnly endif; else: - if ($action[0]=="recon"): + if ($action[0] == "recon"): $resync = resync($action[1]); ?> . value="_(Pause)_" onclick="pauseParity(this.form)" value="_(Resume)_" onclick="resumeParity(this.form)" disabled> **** .**** .
**** .
_(WARNING: canceling may leave the array unprotected)_! - + _(Disk-Clear in progress)_. value="_(Pause)_" onclick="pauseParity(this.form)" value="_(Resume)_" onclick="resumeParity(this.form)" disabled> **_(Pause)_** _(will pause Disk-Clear)_.**_(Resume)_** _(will resume Disk-Clear)_.
**_(Cancel)_** _(will stop Disk-Clear)_. -1):?> + 1):?> _(Parity-Check in progress)_. value="_(Pause)_" onclick="pauseParity(this.form)" value="_(Resume)_" onclick="resumeParity(this.form)" disabled> **_(Pause)_** _(will pause Parity-Check)_.**_(Resume)_** _(will resume Parity-Check)_.
**_(Cancel)_** _(will stop Parity-Check)_. - + _(Read-Check in progress)_. value="_(Pause)_" onclick="pauseParity(this.form)" value="_(Resume)_" onclick="resumeParity(this.form)" disabled> @@ -579,11 +592,11 @@ window.onunload = function(){ _(Current position)_: _(Estimated speed)_: _(Estimated finish)_: - -1):?> - : + + 1):?> + : - : + : **_(Stopping)_...** + if (_var($var,'configValid') == "error"):?> **_(Stopped)_.** _(Invalid, missing or expired)_ _(registration key)_. - + **_(Stopped)_.** _(Too many attached devices. Please consider upgrading your)_ _(registration key)_. - + **_(Stopped)_.** _(Ineligible to run this version of Unraid OS. Please consider extending your)_ _(registration key)_. - + **_(Stopped)_.** _(Cannot contact key-server. Please check your)_ _(network settings)_. - + **_(Stopped)_.** _(This Unraid OS release has been withdrawn and may no longer be used. Please)_ _(update)_ _(your server)_. **_(Stopped)_**. _(Configuration valid)_. **** . - + **_(Stopped)_**. _(New data disk(s) detected)_. **_(Start)_** _(will bring the array on-line and start **Disk-Clear** of new data disk(s))_. -1):?> + 1):?> **_(Stopped)_**. _(Unclean shutdown detected)_. **_(Start)_** _(will bring the array on-line and start **Parity-Check**)_.
_(Write corrections to parity)_ - + **_(Stopped)_**. _(Unclean shutdown detected)_. **_(Start)_** _(will bring the array on-line)_. @@ -661,7 +674,7 @@ window.onunload = function(){ check_encryption(); break; case "NEW_ARRAY": - if (strpos(_var($disks['parity'],'status'),"DISK_NP")===0 && strpos(_var($disks['parity2'],'status'),"DISK_NP")===0):?> + if (strpos(_var($disks['parity'],'status'),"DISK_NP") === 0 && strpos(_var($disks['parity2'],'status'),"DISK_NP") === 0):?> **_(Stopped)_**. _(Configuration valid)_. **_(Start)_** _(will record all disk information and bring the array on-line)_.
_(The array will be immediately available, but **unprotected** since *parity* has not been assigned)_. @@ -688,7 +701,7 @@ window.onunload = function(){ check_encryption(); break; case "SWAP_DSBL": - if (_var($var,'fsCopyPrcnt')=="100"):?> + if (_var($var,'fsCopyPrcnt') == "100"):?> **_(Stopped)_**. _(Upgrading disk/swapping parity)_. **_(Start)_** _(will expand the file system of the data disk (if possible); then bring the array on-line and start Data-Rebuild)_. - +
@@ -749,7 +762,7 @@ endswitch; **_(Clear Stats)_** _(will immediately clear all disk statistics)_. - + @@ -776,7 +789,7 @@ endswitch;

'.parse_file($display['sleep']))?> :array_status_help: - + :array_devices_help: diff --git a/emhttp/plugins/dynamix/DiskSettings.page b/emhttp/plugins/dynamix/DiskSettings.page index 6ea29a07d..9490c47c9 100644 --- a/emhttp/plugins/dynamix/DiskSettings.page +++ b/emhttp/plugins/dynamix/DiskSettings.page @@ -31,6 +31,7 @@ String.prototype.celsius = function(){return Math.round((parseInt(this)-32)*5/9) function base64(str) { return window.btoa(unescape(encodeURIComponent(str))); } + function doDispatch(form) { var fields = {}; @@ -45,6 +46,7 @@ function doDispatch(form) { $(form).find('select[name^="display_"]').each(function(){fields[$(this).attr('name')] = $(this).val(); $(this).prop('disabled',true);}); $.post('/webGui/include/Dispatcher.php',fields); } + function prepareDiskSettings(form) { var events = []; for (var i=0; i < ; i++) { @@ -58,26 +60,38 @@ function prepareDiskSettings(form) { if (form.smEvents.value == '') form.smEvents.value = ''; if (form.smLevel.value == 1.00) form.smLevel.value = ''; } + function setIndex(form) { form.smIndex.value = form.smType.selectedIndex; } + function prepareForm(form) { form.oldluks.value = base64(form.oldtext.value); form.oldtext.disabled = true; form.oldfile.disabled = true; - form.newluks.value = base64(form.newtext.value); - form.newtext.disabled = true; - form.newcopy.disabled = true; - form.newfile.disabled = true; + var valid = new RegExp('^[ -~]+$'); + if (form.newinput.value == 'file') return true; + if (valid.test(form.newtext.value)) { + form.newluks.value = base64(form.newtext.value); + form.newtext.disabled = true; + form.newcopy.disabled = true; + form.newfile.disabled = true; + return true; + } else { + swal({title:"_(Printable Characters Only)_",text:"_(Use **ASCII** characters from space ' ' to tilde '~')_
_(Otherwise use the **keyfile** method for UTF8 input)_",html:true,type:'error',confirmButtonText:"_(Ok)_"}); + return false; + } } + function getFileContent(event,form,file) { var input = event.target; var reader = new FileReader(); reader.onload = function(){$(form).find('input[name="'+file+'"]').val(reader.result);}; reader.readAsDataURL(input.files[0]); } + function selectInput(val,old) { if (val=='text') { if (old==true) { @@ -99,6 +113,7 @@ function selectInput(val,old) { } } } + function showInput(show,old) { if (old==true) { var input = $('input[name="oldtext"]'); @@ -107,6 +122,7 @@ function showInput(show,old) { } input.attr('type',show ? 'text' : 'password'); } + function checkInput(form) { $(form).find('input[name="newkey"]').prop('disabled',form.newtext.value=='' || form.newtext.value!=form.newcopy.value); } @@ -271,7 +287,7 @@ _(Default critical SSD temperature threshold)_ (°
_(Change encryption key)_
- + @@ -299,6 +315,7 @@ _(Enter existing passphrase)_: +