mirror of
https://github.com/unraid/webgui.git
synced 2026-05-04 00:39:32 -05:00
Merge branch 'unraid:master' into master
This commit is contained in:
@@ -6,7 +6,10 @@ cfg=/boot/config/plugins/dynamix.apcupsd/dynamix.apcupsd.cfg
|
||||
[[ -f /var/run/apcupsd.pid || ! -f $cfg ]] && exit
|
||||
|
||||
# Read settings
|
||||
source $cfg
|
||||
. $cfg
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
|
||||
# Apply settings
|
||||
sed -i -e '/^NISIP/c\\NISIP 0.0.0.0' $conf
|
||||
@@ -27,4 +30,4 @@ else
|
||||
fi
|
||||
|
||||
# Start daemon
|
||||
[[ $SERVICE == enable ]] && /etc/rc.d/rc.apcupsd start |& logger
|
||||
[[ $SERVICE == enable ]] && /etc/rc.d/rc.apcupsd start |& log
|
||||
|
||||
@@ -368,7 +368,7 @@ class DockerTemplates {
|
||||
@copy($iconRAM,$icon);
|
||||
}
|
||||
if ( !is_file($iconRAM) ) {
|
||||
exec("/usr/bin/logger ".escapeshellarg("$imageName: Could not download icon $imgUrl"));
|
||||
exec("logger -t webGUI -- \"$imageName: Could not download icon $imgUrl\"");
|
||||
}
|
||||
|
||||
return (is_file($iconRAM)) ? str_replace($docroot, '', $iconRAM) : '';
|
||||
|
||||
@@ -20,6 +20,9 @@ require_once "$docroot/webGui/include/Secure.php";
|
||||
$_SERVER['REQUEST_URI'] = 'plugins';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$tmpdir="/boot/deletemedowngrade.".uniqid();
|
||||
mkdir($tmpdir);
|
||||
exec("mv -f /boot/bz* $tmpdir");
|
||||
exec("mv -f /boot/previous/* /boot");
|
||||
$version = unscript(_var($_GET,'version'));
|
||||
file_put_contents("$docroot/plugins/unRAIDServer/README.md","**"._('DOWNGRADE TO VERSION')." $version**");
|
||||
|
||||
@@ -151,7 +151,7 @@ function download($url, $name, &$error) {
|
||||
// Deal with logging message.
|
||||
//
|
||||
function logger($message) {
|
||||
shell_exec("logger $message");
|
||||
exec("logger -t 'language-manager' -- \"$message\"");
|
||||
}
|
||||
|
||||
// Interpret a language file
|
||||
@@ -314,7 +314,7 @@ if ($method == 'install') {
|
||||
copy($xml_file, $lang_file);
|
||||
symlink($lang_file, $link_file);
|
||||
write("language: $lang language pack installed\n");
|
||||
logger("language: $lang language pack installed");
|
||||
logger("$lang language pack installed");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -396,7 +396,7 @@ if ($method == 'update') {
|
||||
copy($xml_file, $lang_file);
|
||||
symlink($lang_file, $link_file);
|
||||
write("language: $lang language pack updated\n");
|
||||
logger("language: $lang language pack updated");
|
||||
logger("$lang language pack updated");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -423,7 +423,7 @@ if ($method == 'remove') {
|
||||
done(1);
|
||||
}
|
||||
write("language: $lang language pack removed\n");
|
||||
logger("language: $lang language pack removed");
|
||||
logger("$lang language pack removed");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
|
||||
@@ -44,7 +44,7 @@ foreach ($plugins as $plugin) {
|
||||
$run = popen("$cmd $method $pluginArg",'r');
|
||||
while (!feof($run)) {
|
||||
$line .= fgetc($run);
|
||||
if (in_array($line[-1],["\r","\n"])) {write($line); $line = '';}
|
||||
if (!empty($line) && in_array($line[-1],["\r","\n"])) {write($line); $line = '';}
|
||||
}
|
||||
pclose($run);
|
||||
write("\n");
|
||||
|
||||
@@ -154,7 +154,7 @@ function error_desc($code) {
|
||||
case 2: return 'Parse error';
|
||||
case 3: return 'File I/O error';
|
||||
case 4: return 'Network failure';
|
||||
case 5: return 'SSL verification failure';
|
||||
case 5: return 'SSL verification failure - Check the date and time of your server in Settings - Date And Time';
|
||||
case 6: return 'Username/password authentication failure';
|
||||
case 7: return 'Protocol errors';
|
||||
case 8: return 'Invalid URL / Server error response';
|
||||
@@ -284,7 +284,7 @@ function filter_url($url) {
|
||||
// Deal with logging message.
|
||||
//
|
||||
function logger($message) {
|
||||
shell_exec("logger $message");
|
||||
exec("logger -t 'plugin-manager' -- \"$message\"");
|
||||
}
|
||||
|
||||
// Interpret a plugin file
|
||||
@@ -382,12 +382,12 @@ function plugin($method, $plugin_file, &$error) {
|
||||
// If file already exists, check the SHA256/MD5 (if supplied)
|
||||
if (file_exists($name)) {
|
||||
if ($file->SHA256) {
|
||||
logger("plugin: checking: $name - SHA256");
|
||||
logger("checking: $name - SHA256");
|
||||
if (hash_file('sha256', $name) != $file->SHA256) {
|
||||
unlink($name);
|
||||
}
|
||||
} elseif ($file->MD5) {
|
||||
logger("plugin: checking: $name - MD5");
|
||||
logger("checking: $name - MD5");
|
||||
if (md5_file($name) != $file->MD5) {
|
||||
unlink($name);
|
||||
}
|
||||
@@ -396,12 +396,12 @@ function plugin($method, $plugin_file, &$error) {
|
||||
// If file already exists, do not overwrite
|
||||
//
|
||||
if (file_exists($name)) {
|
||||
logger("plugin: skipping: $name already exists");
|
||||
logger("skipping: $name already exists");
|
||||
} elseif ($file->LOCAL) {
|
||||
// Create the file
|
||||
//
|
||||
// for local file, just copy it
|
||||
logger("plugin: creating: $name - copying LOCAL file $file->LOCAL");
|
||||
logger("creating: $name - copying LOCAL file $file->LOCAL");
|
||||
if (!copy($file->LOCAL, $name)) {
|
||||
$error = "unable to copy LOCAL file: $name";
|
||||
@unlink($name);
|
||||
@@ -409,10 +409,10 @@ function plugin($method, $plugin_file, &$error) {
|
||||
}
|
||||
} elseif ($file->INLINE) {
|
||||
// for inline file, create with inline contents
|
||||
logger("plugin: creating: $name - from INLINE content");
|
||||
logger("creating: $name - from INLINE content");
|
||||
$contents = trim($file->INLINE).PHP_EOL;
|
||||
if ($file->attributes()->Type == 'base64') {
|
||||
logger("plugin: decoding: $name as base64");
|
||||
logger("decoding: $name as base64");
|
||||
$contents = base64_decode($contents);
|
||||
if ($contents === false) {
|
||||
$error = "unable to decode inline base64: $name";
|
||||
@@ -426,20 +426,20 @@ function plugin($method, $plugin_file, &$error) {
|
||||
}
|
||||
} elseif ($file->URL) {
|
||||
// for download file, download and maybe verify the file MD5
|
||||
logger("plugin: creating: $name - downloading from URL $file->URL");
|
||||
logger("creating: $name - downloading from URL $file->URL");
|
||||
if ( (download($file->URL, $name, $error) === false) && (download(filter_url($file->URL), $name, $error) === false) ) {
|
||||
@unlink($name);
|
||||
return false;
|
||||
}
|
||||
if ($file->SHA256) {
|
||||
logger("plugin: checking: $name - SHA256");
|
||||
logger("checking: $name - SHA256");
|
||||
if (hash_file('sha256', $name) != $file->SHA256) {
|
||||
$error = "bad file SHA256: $name";
|
||||
unlink($name);
|
||||
return false;
|
||||
}
|
||||
} elseif ($file->MD5) {
|
||||
logger("plugin: checking: $name - MD5");
|
||||
logger("checking: $name - MD5");
|
||||
if (md5_file($name) != $file->MD5) {
|
||||
$error = "bad file MD5: $name";
|
||||
unlink($name);
|
||||
@@ -452,7 +452,7 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if ($file->attributes()->Mode) {
|
||||
// if file has 'Mode' attribute, apply it
|
||||
$mode = $file->attributes()->Mode;
|
||||
logger("plugin: setting: $name - mode to $mode");
|
||||
logger("setting: $name - mode to $mode");
|
||||
if (!chmod($name, octdec($mode))) {
|
||||
$error = "chmod failure: $name";
|
||||
return false;
|
||||
@@ -464,13 +464,13 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if ($file->attributes()->Run) {
|
||||
$command = $file->attributes()->Run;
|
||||
if ($name) {
|
||||
logger(escapeshellarg("plugin: running: $command $name"));
|
||||
logger("running: $command $name");
|
||||
$retval = run("$command $name");
|
||||
} elseif ($file->LOCAL) {
|
||||
logger(escapeshellarg("plugin: running: $command $file->LOCAL"));
|
||||
logger("running: $command $file->LOCAL");
|
||||
$retval = run("$command $file->LOCAL");
|
||||
} elseif ($file->INLINE) {
|
||||
logger("plugin: running: 'anonymous'");
|
||||
logger("running: 'anonymous'");
|
||||
$name = '/tmp/inline.sh';
|
||||
file_put_contents($name, $file->INLINE);
|
||||
$retval = run("$command $name");
|
||||
@@ -718,7 +718,7 @@ if ($method == 'install') {
|
||||
if ($target != $plugin_file) copy($plugin_file, $target);
|
||||
symlink($target, $symlink);
|
||||
write("plugin: $plugin installed\n");
|
||||
logger("plugin: $plugin installed");
|
||||
logger("$plugin installed");
|
||||
} else {
|
||||
write("script: $plugin executed\n");
|
||||
logger("script: $plugin executed");
|
||||
@@ -835,7 +835,7 @@ if ($method == 'update') {
|
||||
copy($plugin_file, $target);
|
||||
symlink($target, $symlink);
|
||||
write("plugin: $plugin updated\n");
|
||||
logger("plugin: $plugin updated");
|
||||
logger("$plugin updated");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -867,7 +867,7 @@ if ($method == 'remove') {
|
||||
// remove the plugin file
|
||||
move($installed_plugin_file, "$boot-removed");
|
||||
write("plugin: $plugin removed\n");
|
||||
logger("plugin: $plugin removed");
|
||||
logger("$plugin removed");
|
||||
exec("/usr/local/sbin/update_cron");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
|
||||
@@ -18,6 +18,7 @@ Markdown="false"
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
|
||||
$cpus = cpu_list();
|
||||
@@ -121,6 +122,7 @@ div.four label:nth-child(4n+4){float:none;clear:both}
|
||||
div.four label.cpu1{width:32%}
|
||||
div.four label.cpu2{width:26%}
|
||||
div.template,div#dialogWindow,input#upload{display:none}
|
||||
div.template,div#dialogWindow2,input#upload{display:none}
|
||||
table.domdisk thead tr th:nth-child(1){width:56%!important}
|
||||
table.domdisk thead tr th:nth-child(n+2){width:8%!important}
|
||||
table.domdisk thead tr th:nth-child(1){padding-left:72px}
|
||||
@@ -134,7 +136,7 @@ i.mover{margin-right:8px;display:none}
|
||||
.dropdown-menu{z-index:10001}
|
||||
</style>
|
||||
<table id="kvm_table" class="tablesorter four shift">
|
||||
<thead><tr><th class="th1"><a id="resetsort" class="nohand" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a>_(Name)_</th><th class="th2">_(Description)_</th><th>_(CPUs)_</th><th>_(Memory)_</th><th>_(vDisks)_</th><th>_(Graphics)_</th><th class="th3">_(Autostart)_</th></tr></thead>
|
||||
<thead><tr><th class="th1"><a id="resetsort" class="nohand" onclick="resetSorting()" title="Reset sorting"><i class="fa fa-th-list"></i></a>_(Name)_</th><th class="th2">_(Description)_</th><th>_(CPUs)_</th><th>_(Memory)_</th><th>_(vDisks / vCDs)_</th><th>_(Graphics)_</th><th class="th3">_(Autostart)_</th></tr></thead>
|
||||
<tbody id="kvm_list"><tr><td colspan='8'></td></tr></tbody>
|
||||
</table>
|
||||
<input type="button" onclick="addVM()" id="btnAddVM" value="_(Add VM)_" style="display:none">
|
||||
@@ -163,7 +165,54 @@ function resetSorting() {
|
||||
function changemedia(uuid,dev,bus,file) {
|
||||
if (file === "--select") getisoimage(uuid,dev,bus,file);
|
||||
if (file === "--eject") ajaxVMDispatch({action:"change-media", uuid:uuid , cdrom:"" , dev:dev , bus:bus , file:file}, "loadlist");
|
||||
}
|
||||
function getisoimageboth(uuid,dev,bus,file,dev2,bus2,file2){
|
||||
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow");
|
||||
box.html($("#templateISOboth").html());
|
||||
|
||||
box.find('#target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match).attr('value', file).fileTreeAttach(null,null,function(path){
|
||||
var bits = path.substr(1).split('/');
|
||||
var auto = bits.length>3 ? '' : share;
|
||||
box.find('#target').val(path+auto).change();
|
||||
});
|
||||
box.find('#target2').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match).attr('value', file2).fileTreeAttach(null,null,function(path){
|
||||
var bits = path.substr(1).split('/');
|
||||
var auto = bits.length>3 ? '' : share;
|
||||
box.find('#target2').val(path+auto).change();
|
||||
});
|
||||
var height = 100;
|
||||
|
||||
box.dialog({
|
||||
title: "Select ISOs for CDROMs",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 300,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
"_(Update)_": function(){
|
||||
var target = box.find('#target');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
} else target = '';
|
||||
var target2 = box.find('#target2');
|
||||
if (target2.length) {
|
||||
target2 = target2.val();
|
||||
} else target2 = '';
|
||||
box.find('#target').prop('disabled',true);
|
||||
box.find('#target2').prop('disabled',true);
|
||||
ajaxVMDispatch({action:"change-media-both", uuid:uuid , cdrom:"" , dev:dev , bus:bus , file:target, dev2:dev2 , bus2:bus2 , file2:target2}, "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
function getisoimage(uuid,dev,bus,file){
|
||||
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
@@ -203,8 +252,220 @@ function getisoimage(uuid,dev,bus,file){
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
function VMClone(uuid, name){
|
||||
|
||||
//var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow");
|
||||
var height = 200;
|
||||
box.html($("#templateClone").html());
|
||||
box.find('#VMBeingCloned').html(name).change() ;
|
||||
box.find('#target').val(name + "_clone") ;
|
||||
document.getElementById("Free").checked = true ;
|
||||
document.getElementById("Overwrite").checked = true ;
|
||||
var Cancel = _("Cancel") ;
|
||||
box.dialog({
|
||||
title: "VM Clone",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
"_(Clone)_" : function(){
|
||||
var target = box.find('#target');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
//if (!target ) {errorTarget(); return;}
|
||||
} else target = '';
|
||||
|
||||
var clone = box.find("#target").prop('value') ;
|
||||
x = box.find('#Start').prop('checked') ;
|
||||
if (x) start = 'yes' ; else start = 'no' ;
|
||||
x = box.find('#Edit').prop('checked') ;
|
||||
if (x) edit = 'yes' ; else edit = 'no' ;
|
||||
x = box.find('#Overwrite').prop('checked') ;
|
||||
if (x) overwrite = 'yes' ; else overwrite = 'no' ;
|
||||
x = box.find('#Free').prop('checked') ;
|
||||
if (x) free = 'yes' ; else free = 'no' ;
|
||||
scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone" , name:name ,clone:clone, overwrite:overwrite , edit:edit, start,start, free:free})) ;
|
||||
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist") ;
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
|
||||
function selectsnapshot(uuid, name ,snaps, opt, getlist,state){
|
||||
|
||||
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow2");
|
||||
box.html($("#templatesnapshot"+opt).html());
|
||||
var height = 200;
|
||||
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1) ;
|
||||
var optiontext = Capopt + " Snapshot" ;
|
||||
box.find('#VMName').html(name) ;
|
||||
box.find('#targetsnap').val(snaps) ;
|
||||
box.find('#targetsnapl').html(snaps) ;
|
||||
if (getlist) {
|
||||
var only = 1 ;
|
||||
if (opt == "remove") only = 0;
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-images", uuid:uuid , snapshotname:snaps, only:only}, function(data) {
|
||||
if (data.html) {
|
||||
box.find('#targetsnapimages').html(data.html) ;
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
document.getElementById("targetsnaprmv").checked = true ;
|
||||
document.getElementById("targetsnaprmvmeta").checked = true ;
|
||||
document.getElementById("targetsnapkeep").checked = true ;
|
||||
document.getElementById("targetsnapfspc").checked = true ;
|
||||
|
||||
box.dialog({
|
||||
title: "_("+optiontext+ ")_",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
|
||||
buttons: {
|
||||
"_(Proceed)_": function(){
|
||||
var target = box.find('#targetsnap');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
if (!target ) {errorTarget(); return;}
|
||||
} else target = '';
|
||||
var remove = 'yes'
|
||||
var keep = 'yes'
|
||||
var removemeta = 'yes'
|
||||
var free = 'yes'
|
||||
var desc = ''
|
||||
box.find('#targetsnap').prop('disabled',true);
|
||||
if (opt == "revert") {
|
||||
var x = box.find('#targetsnaprmv').prop('checked') ;
|
||||
if (x) remove = 'yes' ; else remove = 'no' ;
|
||||
x = box.find('#targetsnaprmvmeta').prop('checked') ;
|
||||
if (x) removemeta = 'yes' ; else removemeta = 'no' ;
|
||||
x = box.find('#targetsnapkeep').prop('checked') ;
|
||||
if (x) keep = 'yes' ; else keep = 'no' ;
|
||||
}
|
||||
if (opt == "create") {
|
||||
var x = box.find('#targetsnapfspc').prop('checked') ;
|
||||
if (x) free = 'yes' ; else free = 'no' ;
|
||||
var desc = box.find("#targetsnapdesc").prop('value') ;
|
||||
}
|
||||
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc} , "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function selectblock(uuid, name ,snaps, opt, getlist,state){
|
||||
|
||||
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow2");
|
||||
box.html($("#templateblock").html());
|
||||
var height = 200;
|
||||
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1) ;
|
||||
var optiontext = Capopt + " Block Devices" ;
|
||||
box.find('#VMName').html(name) ;
|
||||
box.find('#targetsnap').val(snaps) ;
|
||||
box.find('#targetsnapl').html(snaps) ;
|
||||
|
||||
getlist = true ;
|
||||
if (getlist) {
|
||||
var only = 1 ;
|
||||
if (opt == "remove") only = 0;
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-list", uuid:uuid }, function(data) {
|
||||
if (data.html) {
|
||||
var targetbase = document.getElementById("targetblockbase") ;
|
||||
htmlstrbase = "<select class='targetblockbase' name='targetblockbase' id='targetblockbase'><option value='--base'>--base</option>" + data.html + "</select>"
|
||||
htmlstrtop = "<select class='targetblocktop' name='targetblocktop' id='targetblocktop'><option value='--top'>--top</option>" + data.html + "</select>"
|
||||
$("select.targetblockbase").replaceWith(htmlstrbase) ;
|
||||
$("select.targetblocktop").replaceWith(htmlstrtop) ;
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
document.getElementById("targetsnaprmv").checked = true ;
|
||||
document.getElementById("targetsnaprmvmeta").checked = true ;
|
||||
document.getElementById("targetsnapkeep").checked = true ;
|
||||
document.getElementById("targetsnapfspc").checked = true ;
|
||||
if (opt== "pull") {
|
||||
$('.toprow').hide();
|
||||
$('.targetpivotrow').hide();
|
||||
$('.targetdeleterow').hide();
|
||||
} else {
|
||||
$('.toprow').show();
|
||||
$('.targetpivotrow').show();
|
||||
$('.targetdeleterow').show();
|
||||
}
|
||||
|
||||
box.dialog({
|
||||
title: "_("+optiontext+ ")_",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
_("Action")_: function(){
|
||||
var target = box.find('#targetsnap');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
if (!target ) {errorTarget(); return;}
|
||||
} else target = '';
|
||||
var remove = 'yes'
|
||||
var keep = 'yes'
|
||||
var removemeta = 'yes'
|
||||
var free = 'yes'
|
||||
var delete_file = 'yes'
|
||||
var pivot = 'yes'
|
||||
var desc = ''
|
||||
box.find('#targetsnap').prop('disabled',true);
|
||||
if (opt == "create") {
|
||||
var x = box.find('#targetsnapfspc').prop('checked') ;
|
||||
if (x) free = 'yes' ; else free = 'no' ;
|
||||
var desc = box.find("#targetsnapdesc").prop('value') ;
|
||||
}
|
||||
var targetbase = box.find("#targetblockbase").prop('value') ;
|
||||
var targettop = box.find("#targetblocktop").prop('value') ;
|
||||
|
||||
x = box.find('#targetpivot').prop('checked') ;
|
||||
if (x) pivot = 'yes' ; else pivot = 'no' ;
|
||||
x = box.find('#targetdelete').prop('checked') ;
|
||||
if (x) delete_file = 'yes' ; else delete_file = 'no' ;
|
||||
Ajaxurl = "VMAjaxCall.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMajax.php&" + $.param({action:opt , name:name ,targetbase:targetbase, targettop:targettop , snapshotname:target , remove:remove, targetpivot:pivot ,removemeta:removemeta ,targetdelete:delete_file})) ;
|
||||
openVMAction((Ajaxurl),"Block Commit", "dynamix.vm.manager", "loadlist") ;
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function dialogStyle() {
|
||||
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title',"_(Close)_").prop('onclick',null).off('click').click(function(){box.dialog('close');});
|
||||
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title');
|
||||
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
|
||||
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-button-text').css({'padding':'0px 5px'});
|
||||
@@ -304,5 +565,119 @@ $(function() {
|
||||
<div markdown="1" id="templateISO" class="template">
|
||||
_(ISO Image)_:
|
||||
: <input type="text" id="target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="templateISOboth" class="template">
|
||||
_(CD1 ISO Image)_:
|
||||
: <input type="text" id="target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop=""><br>
|
||||
_(CD2 ISO Image)_:
|
||||
: <input type="text" id="target2" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
</div>
|
||||
|
||||
<div id="dialogWindow2"></div>
|
||||
<div markdown="1" id="templatesnapshotcreate" class="template">
|
||||
<table id='snapshot'>
|
||||
<br><br>
|
||||
<tr><td> _(VM Name)_:</td><td>
|
||||
<label id="VMName"></label></td></tr>
|
||||
<tr><td>_(Snapshot Name)_:</td><td>
|
||||
<input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">
|
||||
_(Check free space)_:
|
||||
<input type="checkbox" id="targetsnapfspc" checked></td></tr>
|
||||
<tr><td>_(Description )_:</td><td>
|
||||
<input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="templatesnapshotrevert" class="template">
|
||||
_(VM Name)_:
|
||||
<label id="VMName"></label>
|
||||
<br>
|
||||
_(Snapshot Name)_:
|
||||
<input type="text" id="targetsnap" hidden>
|
||||
<label id="targetsnapl"></label><br>
|
||||
_(Remove Images)_:
|
||||
<input type="checkbox" id="targetsnaprmv" checked >
|
||||
_(Remove Meta)_:
|
||||
<input type="checkbox" id="targetsnaprmvmeta" checked>
|
||||
<!--_(Keep snapshot)_:-->
|
||||
<input type="checkbox" id="targetsnapkeep" hidden><br>
|
||||
|
||||
<label id="targetsnapimages"></label><br>
|
||||
|
||||
<div markdown="1" id="templatesnapshotremove" class="template" post>
|
||||
_(!! Warning removing Snapshots can break the chain !!)_<br><br>
|
||||
|
||||
_(VM Name)_:
|
||||
<label id="VMName"></label>
|
||||
<br>
|
||||
_(Snapshot Name)_:
|
||||
<input type="text" id="targetsnap" hidden>
|
||||
<label id="targetsnapl"></label><br>
|
||||
|
||||
<label id="targetsnapimages"></label><br>
|
||||
|
||||
<div markdown="1" id="templateblock" class="template">
|
||||
_(VM Name)_:
|
||||
<label id="VMName"></label>
|
||||
<br>
|
||||
_(Snapshot Name)_:
|
||||
<input type="text" id="targetsnap" hidden>
|
||||
<label id="targetsnapl"></label><br>
|
||||
<br><br><br><br>
|
||||
<table id='block'>
|
||||
<tr><td>_(Base Image)_:</td><td>
|
||||
<select class="targetblockbase" s>
|
||||
</select></td></tr>
|
||||
<tr name="toprow" class="toprow" ><td>_(Top Image )_:</td><td>
|
||||
<select class="targetblocktop" name="targetblocktop" id="targetblocktop">
|
||||
</select></td><td>
|
||||
<tr name="targetpivotrow" class="targetpivotrow" ><td>_(Pivot)_:</td><td>
|
||||
<input type="checkbox" id="targetpivot" checked></td></tr>
|
||||
<tr name="targetdeleterow" class="targetdeleterow" ><td>_(Delete)_:</td><td>
|
||||
<input type="checkbox" id="targetdelete" checked></td></tr>
|
||||
</table>
|
||||
<input type="checkbox" id="targetsnapkeep" hidden><br>
|
||||
<label id="targetsnapimages"></label><br>
|
||||
</div>
|
||||
|
||||
<div id="dialogWindow"></div>
|
||||
<div markdown="1" id="templateClone" class="template">
|
||||
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=1600">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="referrer" content="same-origin">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
|
||||
</head>
|
||||
<body>
|
||||
<br>
|
||||
<table>
|
||||
<tr><td>_(VM Being Cloned)_:</td>
|
||||
<td><span id="VMBeingCloned"></span></td></tr>
|
||||
|
||||
<tr><td>_(New VM)_:</td>
|
||||
<td><input type="text" id="target" autocomplete="off" spellcheck="false" value="" onclick="this.select()" ></td></tr>
|
||||
|
||||
<tr><td>_(Overwrite)_:</td>
|
||||
<td><input type="checkbox" id="Overwrite" value="" ></td></tr>
|
||||
|
||||
<tr hidden><td>_(Start Cloned VM)_:</td>
|
||||
<td><input type="checkbox" id="Start" value="" ></td></tr>
|
||||
|
||||
<tr hidden><td>_(Edit VM after clone)_:</td>
|
||||
<td><input type="checkbox" id="Edit" value="" ></td></tr>
|
||||
|
||||
<tr><td>_(Check Free Space)_:</td>
|
||||
<td><input type="checkbox" id="Free" value="" ></td></tr>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -21,6 +21,7 @@ require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
|
||||
$user_prefs = '/boot/config/plugins/dynamix.vm.manager/userprefs.cfg';
|
||||
if (file_exists('/boot/config/plugins/dynamix.vm.manager/vmpreview')) $vmpreview = true ; else $vmpreview = false ;
|
||||
$vms = $lv->get_domains();
|
||||
if (empty($vms)) {
|
||||
echo '<tr><td colspan="8" style="text-align:center;padding-top:12px">'._('No Virtual Machines installed').'</td></tr>';
|
||||
@@ -51,6 +52,8 @@ foreach ($vms as $vm) {
|
||||
$icon = $lv->domain_get_icon_url($res);
|
||||
$image = substr($icon,-4)=='.png' ? "<img src='$icon' class='img'>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
|
||||
$arrConfig = domain_to_config($uuid);
|
||||
$snapshots = getvmsnapshots($vm) ;
|
||||
$cdroms = $lv->get_cdrom_stats($res) ;
|
||||
if ($state == 'running') {
|
||||
$mem = $dom['memory']/1024;
|
||||
} else {
|
||||
@@ -101,7 +104,7 @@ foreach ($vms as $vm) {
|
||||
}
|
||||
unset($dom);
|
||||
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
|
||||
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log), $vmrcconsole);
|
||||
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log), $vmrcconsole,$vmpreview);
|
||||
$kvm[] = "kvm.push({id:'$uuid',state:'$state'});";
|
||||
switch ($state) {
|
||||
case 'running':
|
||||
@@ -123,12 +126,33 @@ foreach ($vms as $vm) {
|
||||
}
|
||||
|
||||
/* VM information */
|
||||
|
||||
if ($snapshots != null) $snapshotstr = _("(Snapshots :").count($snapshots).')' ; else $snapshotstr = _("(Snapshots :None)") ;
|
||||
$cdbus = $cdbus2 = $cdfile = $cdfile2 = "" ;
|
||||
$cdromcount = 0 ;
|
||||
foreach ($cdroms as $arrCD) {
|
||||
$disk = $arrCD['file'] ?? $arrCD['partition'];
|
||||
$dev = $arrCD['device'];
|
||||
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
|
||||
if ($dev == "hda") {
|
||||
$cdbus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
|
||||
$cdfile = $arrCD['file'] ?? $arrCD['partition'];
|
||||
if ($cdfile != "") $cdromcount++ ;
|
||||
}
|
||||
if ($dev == "hdb") {
|
||||
$cdbus2 = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
|
||||
$cdfile2 = $arrCD['file'] ?? $arrCD['partition'];
|
||||
if ($cdfile2 != "") $cdromcount++ ;
|
||||
}
|
||||
}
|
||||
$changemedia = "getisoimageboth(\"{$uuid}\",\"hda\",\"{$cdbus}\",\"{$cdfile}\",\"hdb\",\"{$cdbus2}\",\"{$cdfile2}\")";
|
||||
$cdstr = $cdromcount." / 2<a class='hand' title='$title' href='#' onclick='$changemedia'> <i class='fa fa-bullseye' ></i></a>";
|
||||
echo "<tr parent-id='$i' class='sortable'><td class='vm-name' style='width:220px;padding:8px'><i class='fa fa-arrows-v mover orange-text'></i>";
|
||||
echo "<span class='outer'><span id='vm-$uuid' $menu class='hand'>$image</span><span class='inner'><a href='#' onclick='return toggle_id(\"name-$i\")' title='click for more VM info'>$vm</a><br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span></span></td>";
|
||||
echo "<span class='outer'><span id='vm-$uuid' $menu class='hand'>$image</span><span class='inner'><a href='#' onclick='return toggle_id(\"name-$i\")' title='click for more VM info'>$vm</a><br><i class='fa fa-$shape $status $color'></i><span class='state'>"._($status)." $snapshotstcount</span></span></span></td>";
|
||||
echo "<td>$desc</td>";
|
||||
echo "<td><a class='vcpu-$uuid' style='cursor:pointer'>$vcpu</a></td>";
|
||||
echo "<td>$mem</td>";
|
||||
echo "<td title='$diskdesc'>$disks</td>";
|
||||
echo "<td title='$diskdesc'><span class='state' >$disks $cdstr<br>$snapshotstr</span></td>";
|
||||
echo "<td>$graphics</td>";
|
||||
echo "<td><input class='autostart' type='checkbox' name='auto_{$vm}' title=\""._('Toggle VM autostart')."\" uuid='$uuid' $autostart></td></tr>";
|
||||
|
||||
@@ -168,13 +192,13 @@ foreach ($vms as $vm) {
|
||||
}
|
||||
|
||||
/* Display VM cdroms */
|
||||
foreach ($lv->get_cdrom_stats($res) as $arrCD) {
|
||||
foreach ($cdroms as $arrCD) {
|
||||
$capacity = $lv->format_size($arrCD['capacity'], 0);
|
||||
$allocation = $lv->format_size($arrCD['allocation'], 0);
|
||||
$disk = $arrCD['file'] ?? $arrCD['partition'];
|
||||
$disk = $arrCD['file'] ?? $arrCD['partition'] ?? "" ;
|
||||
$dev = $arrCD['device'];
|
||||
$bus = $arrValidDiskBuses[$arrCD['bus']] ?? 'VirtIO';
|
||||
$boot= $arrCD["boot order"];
|
||||
$boot= $arrCD["boot order"] ?? "" ;
|
||||
if ($boot < 1) $boot="Not set";
|
||||
if ($disk != "" ) {
|
||||
$title = _("Eject CD Drive").".";
|
||||
@@ -214,12 +238,43 @@ foreach ($vms as $vm) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if ($gastate == "disconnected") echo "<tr><td>"._('Guest agent not installed')."</td><td></td><td></td><td></td></tr>";
|
||||
else echo "<tr><td>"._('Guest not running')."</td><td></td><td></td><td></td><td></td></tr>";
|
||||
}
|
||||
echo "</tbody></table>";
|
||||
echo "</td></tr>";
|
||||
echo "</tbody>";
|
||||
/* Display VM Snapshots */
|
||||
if ($snapshots != null) {
|
||||
$j=0 ;
|
||||
$steps = array() ;
|
||||
foreach($snapshots as $snap) {
|
||||
if ($snap['parent'] == "" || $snap['parent'] == "Base") $j++;
|
||||
$steps[$j] .= $snap['name'].';' ;
|
||||
}
|
||||
echo "<thead class='child' child-id='$i'><tr><th><i class='fa fa-clone'></i> <b>"._('Snapshots')."</b></th><th></th><th>"._('Date/Time')."</th><th>"._('Type')."</th><th>"._('Parent')."</th><th>"._('Memory')."</th></tr></thead>";
|
||||
echo "<tbody class='child'child-id='$i'>";
|
||||
foreach($steps as $stepsline)
|
||||
{
|
||||
$snapshotlist = explode(";",$stepsline) ;
|
||||
$tab = " " ;
|
||||
foreach($snapshotlist as $snapshotitem) {
|
||||
if ($snapshotitem == "") continue ;
|
||||
$snapshot = $snapshots[$snapshotitem] ;
|
||||
$snapshotstate = _(ucfirst($snapshot["state"])) ;
|
||||
$snapshotdesc = $snapshot["desc"] ;
|
||||
$snapshotmemory = _(ucfirst($snapshot["memory"]["@attributes"]["snapshot"])) ;
|
||||
$snapshotparent = $snapshot["parent"] ? $snapshot["parent"] : "None";
|
||||
$snapshotdatetime = my_time($snapshot["creationtime"],"Y-m-d" )."<br>".my_time($snapshot["creationtime"],"H:i:s") ;
|
||||
$snapmenu = sprintf("onclick=\"addVMSnapContext('%s','%s','%s','%s','%s','%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,$snapshot["name"],$vmpreview);
|
||||
echo "<tr><td><span id='vmsnap-$uuid' $snapmenu class='hand'>$tab|__ <i class='fa fa-clone'></i></span> ".$snapshot["name"]."</td><td>$snapshotdesc</td><td><span class='inner' style='font-size:1.1rem;'>$snapshotdatetime</span></td><td>$snapshotstate</td><td>$snapshotparent</td><td>$snapshotmemory</td></tr>";
|
||||
$tab .=" " ;
|
||||
}
|
||||
echo "</tbody>";
|
||||
}
|
||||
}
|
||||
echo "</table>";
|
||||
}
|
||||
|
||||
echo "\0".implode($kvm);
|
||||
?>
|
||||
|
||||
@@ -265,6 +265,40 @@ case 'change-media':
|
||||
: ['error' => "Change Media Failed"];
|
||||
break;
|
||||
|
||||
case 'change-media-both':
|
||||
requireLibvirt();
|
||||
$res = $lv->get_domain_by_name($domName);
|
||||
$cdroms = $lv->get_cdrom_stats($res) ;
|
||||
$hda = $hdb = false ;
|
||||
foreach ($lv->get_cdrom_stats($res) as $cd){
|
||||
if ($cd['device'] == 'hda') $hda = true ;
|
||||
if ($cd['device'] == 'hdb') $hdb = true ;
|
||||
}
|
||||
$file= $_REQUEST['file'];
|
||||
if ($file != "" && $hda == false) {
|
||||
$cmdstr = "virsh attach-disk '$domName' '$file' hda --type cdrom --targetbus sata --config" ;
|
||||
} else {
|
||||
if ($file == "") $cmdstr = "virsh change-media '$domName' hda --eject --current";
|
||||
else $cmdstr = "virsh change-media '$domName' hda '$file'";
|
||||
}
|
||||
$rtn=shell_exec($cmdstr)
|
||||
? ['success' => true]
|
||||
: ['error' => "Change Media Failed"];
|
||||
|
||||
if (isset($rtn['error'])) return ;
|
||||
|
||||
$file2 = $_REQUEST['file2'];
|
||||
if ($file2 != "" && $hdb == false) {
|
||||
$cmdstr = "virsh attach-disk '$domName' '$file2' hdb --type cdrom --targetbus sata --config" ;
|
||||
} else {
|
||||
if ($file2 == "") $cmdstr = "virsh change-media '$domName' hdb --eject --current";
|
||||
else $cmdstr = "virsh change-media '$domName' hdb '$file2' ";
|
||||
}
|
||||
$rtn=shell_exec($cmdstr)
|
||||
? ['success' => true]
|
||||
: ['error' => "Change Media Failed"];
|
||||
break;
|
||||
|
||||
case 'memory-change':
|
||||
requireLibvirt();
|
||||
$arrResponse = $lv->domain_set_memory($domName, $_REQUEST['memory']*1024)
|
||||
@@ -302,6 +336,40 @@ case 'snap-create':
|
||||
: ['error' => $lv->get_last_error()];
|
||||
break;
|
||||
|
||||
case 'snap-create-external':
|
||||
requireLibvirt();
|
||||
$arrResponse = vm_snapshot($domName,$_REQUEST['snapshotname'],$_REQUEST['desc'],$_REQUEST['free']) ;
|
||||
break;
|
||||
|
||||
case 'snap-images':
|
||||
requireLibvirt();
|
||||
$html = vm_snapimages($domName,$_REQUEST['snapshotname'],$_REQUEST['only']) ;
|
||||
$arrResponse = ['html' => $html , 'success' => true] ;
|
||||
break;
|
||||
|
||||
case 'snap-list':
|
||||
requireLibvirt();
|
||||
$arrResponse = ($data = getvmsnapshots($domName))
|
||||
? ['success' => true]
|
||||
: ['error' => $lv->get_last_error()];
|
||||
$datartn = "";
|
||||
foreach($data as $snap=>$snapdetail) {
|
||||
$snapshotdatetime = date("Y-m-d H:i:s",$snapdetail["creationtime"]) ;
|
||||
$datartn .= "<option value='$snap'>$snap $snapshotdatetime</option>" ;
|
||||
}
|
||||
$arrResponse['html'] = $datartn ;
|
||||
break;
|
||||
|
||||
case 'snap-revert-external':
|
||||
requireLibvirt();
|
||||
$arrResponse = vm_revert($domName,$_REQUEST['snapshotname'],$_REQUEST['remove'], $_REQUEST['removemeta']) ;
|
||||
break;
|
||||
|
||||
case 'snap-remove-external':
|
||||
requireLibvirt();
|
||||
$arrResponse = vm_snapremove($domName,$_REQUEST['snapshotname']) ;
|
||||
break;
|
||||
|
||||
case 'snap-delete':
|
||||
requireLibvirt();
|
||||
$arrResponse = $lv->domain_snapshot_delete($domName, $_REQUEST['snap'])
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
}
|
||||
|
||||
|
||||
function config_to_xml($config) {
|
||||
function config_to_xml($config,$vmclone = false) {
|
||||
$domain = $config['domain'];
|
||||
$media = $config['media'];
|
||||
$nics = $config['nic'];
|
||||
@@ -463,19 +463,26 @@
|
||||
$usbstr = '';
|
||||
if (!empty($usb)) {
|
||||
foreach($usb as $i => $v){
|
||||
$usbx = explode(':', $v);
|
||||
if ($vmclone) $usbx = explode(':', $v['id']); else $usbx = explode(':', $v);
|
||||
$startupPolicy = '' ;
|
||||
if (isset($usbopt[$v])) {
|
||||
if (isset($usbopt[$v]) && !$vmclone ) {
|
||||
if (strpos($usbopt[$v], "#remove") == false) $startupPolicy = 'startupPolicy="optional"' ; else $startupPolicy = '' ;
|
||||
}
|
||||
}
|
||||
if (isset($v["startupPolicy"]) && $vmclone ) {
|
||||
if ($v["startupPolicy"] == "optional" ) $startupPolicy = 'startupPolicy="optional"' ; else $startupPolicy = '' ;
|
||||
}
|
||||
|
||||
$usbstr .= "<hostdev mode='subsystem' type='usb'>
|
||||
<source $startupPolicy>
|
||||
<vendor id='0x".$usbx[0]."'/>
|
||||
<product id='0x".$usbx[1]."'/>
|
||||
</source>" ;
|
||||
if (!empty($usbboot[$v])) {
|
||||
if (!empty($usbboot[$v]) && !$vmclone ) {
|
||||
$usbstr .= "<boot order='".$usbboot[$v]."'/>" ;
|
||||
}
|
||||
}
|
||||
if (isset($v["usbboot"]) && $vmclone ) {
|
||||
if ($v["usbboot"] != NULL) $usbstr .= "<boot order='".$v["usbboot"]."'/>" ;
|
||||
}
|
||||
$usbstr .= "</hostdev>";
|
||||
}
|
||||
}
|
||||
@@ -774,17 +781,20 @@
|
||||
|
||||
if ($strAutoport == "yes") $strPort = $strWSport = "-1" ;
|
||||
if (($gpu['copypaste'] == "yes") && ($strProtocol == "spice")) $vmrcmousemode = "<mouse mode='server'/>" ; else $vmrcmousemode = "" ;
|
||||
if ($strProtocol == "spice") $virtualaudio = "spice" ; else $virtualaudio = "none" ;
|
||||
|
||||
$vmrc = "<input type='tablet' bus='usb'/>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='keyboard' bus='ps2'/>
|
||||
<graphics type='$strProtocol' port='$strPort' autoport='$strAutoport' websocket='$strWSport' listen='0.0.0.0' $passwdstr $strKeyMap>
|
||||
<graphics type='$strProtocol' sharePolicy='ignore' port='$strPort' autoport='$strAutoport' websocket='$strWSport' listen='0.0.0.0' $passwdstr $strKeyMap>
|
||||
<listen type='address' address='0.0.0.0'/>
|
||||
$vmrcmousemode
|
||||
</graphics>
|
||||
<video>
|
||||
<model type='$strModelType'/>
|
||||
</video>";
|
||||
</video>
|
||||
<audio id='1' type='$virtualaudio'/>";
|
||||
|
||||
|
||||
if ($gpu['copypaste'] == "yes") {
|
||||
if ($strProtocol == "spice") {
|
||||
@@ -865,20 +875,23 @@
|
||||
if (empty($pci_id) || in_array($pci_id, $pcidevs_used)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id), 3);
|
||||
if ($vmclone) [$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id['id']), 3);
|
||||
else [$pci_bus, $pci_slot, $pci_function] = my_explode(":", str_replace('.', ':', $pci_id), 3);
|
||||
|
||||
$pcidevs .= "<hostdev mode='subsystem' type='pci' managed='yes'>
|
||||
<driver name='vfio'/>
|
||||
<source>
|
||||
<address domain='0x0000' bus='0x" . $pci_bus . "' slot='0x" . $pci_slot . "' function='0x" . $pci_function . "'/>
|
||||
</source>" ;
|
||||
if (!empty($pciboot[$pci_id])) {
|
||||
if (!empty($pciboot[$pci_id]) && !$vmclone) {
|
||||
$pcidevs .= "<boot order='".$pciboot[$pci_id]."'/>" ;
|
||||
}
|
||||
if (!empty($pci_id["boot"]) && $vmclone) {
|
||||
$pcidevs .= "<boot order='".$pci_id["boot"]."'/>" ;
|
||||
}
|
||||
$pcidevs .= "</hostdev>";
|
||||
|
||||
$pcidevs_used[] = $pci_id;
|
||||
if ($vmclone) $pcidevs_used[] = $pci_id['d']; else $pcidevs_used[] = $pci_id ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,7 +1157,7 @@
|
||||
$tmp = libvirt_domain_get_block_info($dom, $disks[$i]);
|
||||
if ($tmp) {
|
||||
$tmp['bus'] = $buses[$i];
|
||||
$tmp["boot order"] = $boot[$i] ;
|
||||
$tmp["boot order"] = $boot[$i] ?? "";
|
||||
$ret[] = $tmp;
|
||||
}
|
||||
else {
|
||||
@@ -1195,7 +1208,7 @@
|
||||
|
||||
if ($tmp) {
|
||||
$tmp['bus'] = $disk->target->attributes()->bus->__toString();
|
||||
$tmp["boot order"] = $disk->boot->attributes()->order ;
|
||||
$tmp["boot order"] = $disk->boot->attributes()->order ?? "";
|
||||
$tmp['serial'] = $disk->serial ;
|
||||
|
||||
// Libvirt reports 0 bytes for raw disk images that haven't been
|
||||
@@ -1454,7 +1467,7 @@
|
||||
function domain_change_xml($domain, $xml) {
|
||||
$dom = $this->get_domain_object($domain);
|
||||
|
||||
if (!($old_xml = domain_get_xml($dom)))
|
||||
if (!($old_xml = $this->domain_get_xml($dom)))
|
||||
return $this->_set_last_error();
|
||||
if (!libvirt_domain_undefine($dom))
|
||||
return $this->_set_last_error();
|
||||
@@ -1487,6 +1500,11 @@
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
function get_interface_addresses($domain,$flag) {
|
||||
$tmp = libvirt_domain_interface_addresses($domain,$flag);
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
function get_node_device_res($res) {
|
||||
if ($res == false)
|
||||
return false;
|
||||
@@ -1590,7 +1608,7 @@
|
||||
if (!$dom)
|
||||
return false;
|
||||
|
||||
$tmp = libvirt_domain_get_xml_desc($dom, $xpath);
|
||||
$tmp = libvirt_domain_get_xml_desc($dom, 0);
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
@@ -1854,6 +1872,48 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
function nvram_create_snapshot($uuid,$snapshotname) {
|
||||
// snapshot backup OVMF VARS if this domain had them
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd')) {
|
||||
copy('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd', '/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd');
|
||||
return true;
|
||||
}
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd')) {
|
||||
copy('/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd', '/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function nvram_revert_snapshot($uuid,$snapshotname) {
|
||||
// snapshot backup OVMF VARS if this domain had them
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd')) {
|
||||
copy('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd', '/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi.fd');
|
||||
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd') ;
|
||||
return true;
|
||||
}
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd')) {
|
||||
copy('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd', '/etc/libvirt/qemu/nvram/'.$uuid.'_VARS-pure-efi-tpm.fd');
|
||||
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd') ;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function nvram_delete_snapshot($uuid,$snapshotname) {
|
||||
// snapshot backup OVMF VARS if this domain had them
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd')) {
|
||||
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi.fd') ;
|
||||
return true;
|
||||
}
|
||||
if (is_file('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd')) {
|
||||
unlink('/etc/libvirt/qemu/nvram/'.$uuid.$snapshotname.'_VARS-pure-efi-tpm.fd') ;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function is_dir_empty($dir) {
|
||||
if (!is_readable($dir)) return NULL;
|
||||
$handle = opendir($dir);
|
||||
@@ -1992,7 +2052,7 @@
|
||||
|
||||
function domain_get_description($domain) {
|
||||
$tmp = $this->get_xpath($domain, '//domain/description', false);
|
||||
$var = $tmp[0];
|
||||
$var = $tmp[0] ?? "";
|
||||
unset($tmp);
|
||||
|
||||
return $var;
|
||||
@@ -2194,33 +2254,34 @@
|
||||
|
||||
// Get any pci devices contained in the qemu args
|
||||
$args = $this->get_xpath($domain, '//domain/*[name()=\'qemu:commandline\']/*[name()=\'qemu:arg\']/@value', false);
|
||||
if (isset($args['num'])) {
|
||||
for ($i = 0; $i < $args['num']; $i++) {
|
||||
if (strpos($args[$i], 'vfio-pci') !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $args['num']; $i++) {
|
||||
if (strpos($args[$i], 'vfio-pci') !== 0) {
|
||||
continue;
|
||||
}
|
||||
$arg_list = explode(',', $args[$i]);
|
||||
|
||||
$arg_list = explode(',', $args[$i]);
|
||||
foreach ($arg_list as $arg) {
|
||||
$keypair = explode('=', $arg);
|
||||
|
||||
foreach ($arg_list as $arg) {
|
||||
$keypair = explode('=', $arg);
|
||||
|
||||
if ($keypair[0] == 'host' && !empty($keypair[1])) {
|
||||
$devid = 'pci_0000_' . str_replace([':', '.'], '_', $keypair[1]);
|
||||
$tmp2 = $this->get_node_device_information($devid);
|
||||
[$bus, $slot, $func] = my_explode(":", str_replace('.', ':', $keypair[1]), 3);
|
||||
$devs[] = [
|
||||
'domain' => '0x0000',
|
||||
'bus' => '0x' . $bus,
|
||||
'slot' => '0x' . $slot,
|
||||
'func' => '0x' . $func,
|
||||
'id' => $keypair[1],
|
||||
'vendor' => $tmp2['vendor_name'],
|
||||
'vendor_id' => $tmp2['vendor_id'],
|
||||
'product' => $tmp2['product_name'],
|
||||
'product_id' => $tmp2['product_id']
|
||||
];
|
||||
break;
|
||||
if ($keypair[0] == 'host' && !empty($keypair[1])) {
|
||||
$devid = 'pci_0000_' . str_replace([':', '.'], '_', $keypair[1]);
|
||||
$tmp2 = $this->get_node_device_information($devid);
|
||||
[$bus, $slot, $func] = my_explode(":", str_replace('.', ':', $keypair[1]), 3);
|
||||
$devs[] = [
|
||||
'domain' => '0x0000',
|
||||
'bus' => '0x' . $bus,
|
||||
'slot' => '0x' . $slot,
|
||||
'func' => '0x' . $func,
|
||||
'id' => $keypair[1],
|
||||
'vendor' => $tmp2['vendor_name'],
|
||||
'vendor_id' => $tmp2['vendor_id'],
|
||||
'product' => $tmp2['product_name'],
|
||||
'product_id' => $tmp2['product_id']
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2249,15 +2310,17 @@
|
||||
$pid = $this->get_xpath($domain, $xpath.'product/@id', false);
|
||||
|
||||
$devs = [];
|
||||
for ($i = 0; $i < $vid['num']; $i++) {
|
||||
$dev = $this->_lookup_device_usb($vid[$i], $pid[$i]);
|
||||
$devs[] = [
|
||||
'id' => str_replace('0x', '', $vid[$i] . ':' . $pid[$i]),
|
||||
'vendor_id' => $vid[$i],
|
||||
'product_id' => $pid[$i],
|
||||
'product' => $dev['product_name'],
|
||||
'vendor' => $dev['vendor_name']
|
||||
];
|
||||
if (isset($vid['num'])) {
|
||||
for ($i = 0; $i < $vid['num']; $i++) {
|
||||
$dev = $this->_lookup_device_usb($vid[$i], $pid[$i]);
|
||||
$devs[] = [
|
||||
'id' => str_replace('0x', '', $vid[$i] . ':' . $pid[$i]),
|
||||
'vendor_id' => $vid[$i],
|
||||
'product_id' => $pid[$i],
|
||||
'product' => $dev['product_name'],
|
||||
'vendor' => $dev['vendor_name']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $devs;
|
||||
@@ -2291,7 +2354,7 @@
|
||||
'mac' => $macs[$i],
|
||||
'network' => $net[0],
|
||||
'model' => $model[0],
|
||||
'boot' => $boot[0]
|
||||
'boot' => $boot[0] ?? ""
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2469,6 +2532,12 @@
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
//list all snapshots for domain
|
||||
function domain_snapshot_get_xml($domain) {
|
||||
$tmp = libvirt_domain_snapshot_get_xml($domain);
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
// create a snapshot and metadata node for description
|
||||
function domain_snapshot_create($domain) {
|
||||
$this->domain_set_metadata($domain);
|
||||
@@ -2478,10 +2547,9 @@
|
||||
}
|
||||
|
||||
//delete snapshot and metadata
|
||||
function domain_snapshot_delete($domain, $name) {
|
||||
$this->snapshot_remove_metadata($domain, $name);
|
||||
function domain_snapshot_delete($domain, $name, $flags=0) {
|
||||
$name = $this->domain_snapshot_lookup_by_name($domain, $name);
|
||||
$tmp = libvirt_domain_snapshot_delete($name);
|
||||
$tmp = libvirt_domain_snapshot_delete($name,$flags);
|
||||
return ($tmp) ? $tmp : $this->_set_last_error();
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ private static $encoding = 'UTF-8';
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
|
||||
require_once "$docroot/webGui/include/Custom.php";
|
||||
|
||||
// Load emhttp variables if needed.
|
||||
if (!isset($var)){
|
||||
@@ -755,6 +756,15 @@ private static $encoding = 'UTF-8';
|
||||
$arrWhitelistGPUClassIDregex = '/^(0001|03)/';
|
||||
$arrWhitelistAudioClassIDregex = '/^(0403)/';
|
||||
|
||||
# "System peripheral [0880]" "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]" -pff "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]"
|
||||
# typeid productid
|
||||
# file is csv typeid:productid
|
||||
#
|
||||
if (is_file("/boot/config/VMPCIOverride.cfg")) {
|
||||
$arrWhiteListOverride = str_getcsv(file_get_contents("/boot/config/VMPCIOverride.cfg")) ;
|
||||
}
|
||||
$arrWhiteListOverride[] = "0880:089a" ;
|
||||
|
||||
$arrValidPCIDevices = [];
|
||||
|
||||
exec("lspci -m -nn 2>/dev/null", $arrAllPCIDevices);
|
||||
@@ -769,6 +779,9 @@ private static $encoding = 'UTF-8';
|
||||
$boolBlacklisted = true;
|
||||
}
|
||||
|
||||
$overrideCheck = "${arrMatch['typeid']}:${arrMatch['productid']}" ;
|
||||
if (in_array($overrideCheck,$arrWhiteListOverride) ) $boolBlacklisted = false;
|
||||
|
||||
$strClass = 'other';
|
||||
if (preg_match($arrWhitelistGPUClassIDregex, $arrMatch['typeid'])) {
|
||||
$strClass = 'vga';
|
||||
@@ -1203,6 +1216,7 @@ private static $encoding = 'UTF-8';
|
||||
$arrDisks[] = [
|
||||
'new' => $strPath,
|
||||
'size' => '',
|
||||
'driver' => $disk['type'],
|
||||
'driver' => 'raw',
|
||||
'dev' => $disk['device'],
|
||||
'bus' => $disk['bus'],
|
||||
@@ -1370,7 +1384,7 @@ private static $encoding = 'UTF-8';
|
||||
$vendor=$USB->source->vendor->attributes()->id ;
|
||||
$product=$USB->source->product->attributes()->id ;
|
||||
$startupPolicy=$USB->source->attributes()->startupPolicy ;
|
||||
$usbboot= $USB->boot->attributes()->order ;
|
||||
$usbboot= $USB->boot->attributes()->order ?? "" ;
|
||||
$id = str_replace('0x', '', $vendor . ':' . $product) ;
|
||||
$found = false ;
|
||||
foreach($arrValidUSBDevices as $key => $data) {
|
||||
@@ -1420,7 +1434,7 @@ private static $encoding = 'UTF-8';
|
||||
global $lv ;
|
||||
$xml = new SimpleXMLElement($lv->domain_get_xml($res)) ;
|
||||
$data = $xml->xpath('//channel/target[@name="org.qemu.guest_agent.0"]/@state') ;
|
||||
$data = $data[0]->state ;
|
||||
$data = $data[0]->state ?? null ;
|
||||
return $data ;
|
||||
}
|
||||
|
||||
@@ -1454,4 +1468,779 @@ private static $encoding = 'UTF-8';
|
||||
if ($spicevmc || $qemuvdaagent) $copypaste = true ; else $copypaste = false ;
|
||||
return $copypaste ;
|
||||
}
|
||||
|
||||
function vm_clone($vm, $clone ,$overwrite,$start,$edit, $free, $waitID) {
|
||||
global $lv,$domain_cfg ;
|
||||
/*
|
||||
Clone.
|
||||
|
||||
Stopped only.
|
||||
|
||||
Get new VM Name
|
||||
Extract XML for VM to be cloned.
|
||||
Check if directory exists.
|
||||
Check for disk space
|
||||
|
||||
Stop VM Starting until clone is finished or fails.
|
||||
|
||||
Create new directory for Clone.
|
||||
Update paths with new directory
|
||||
|
||||
Create new UUID
|
||||
Create new MAC Address for NICs
|
||||
|
||||
Create VM Disks from source. Options full or Sparce. Method of copy?
|
||||
|
||||
release orginal VM to start.
|
||||
|
||||
If option to edit, show VMUpdate
|
||||
*/
|
||||
$uuid = $lv->domain_get_uuid($clone) ;
|
||||
write("addLog\0".htmlspecialchars(_("Checking if clone exists")));
|
||||
if ($uuid) { $arrResponse = ['error' => _("Clone VM name already inuse")]; return false ;}
|
||||
#VM must be shutdown.
|
||||
$res = $lv->get_domain_by_name($vm);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
$state = $lv->domain_state_translate($dom['state']);
|
||||
$vmxml = $lv->domain_get_xml($res) ;
|
||||
file_put_contents("/tmp/cloningxml" ,$vmxml) ;
|
||||
# if VM running shutdown. Record was running.
|
||||
if ($state != 'shutoff') {write("addLog\0".htmlspecialchars(_("Shuting down $vm current $state"))); $arrResponse = $lv->domain_destroy($vm) ; }
|
||||
# Wait for shutdown?
|
||||
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
|
||||
$capacity = 0 ;
|
||||
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$pathinfo = pathinfo($file) ;
|
||||
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
|
||||
$capacity = $capacity + $disk["capacity"] ;
|
||||
}
|
||||
$dirpath = $pathinfo["dirname"] ;
|
||||
|
||||
#Check free space.
|
||||
write("addLog\0".htmlspecialchars("Checking for free space"));
|
||||
$dirfree = disk_free_space($pathinfo["dirname"]) ;
|
||||
$sourcedir = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($pathinfo["dirname"])." 2>/dev/null"));
|
||||
$repdir = str_replace('/mnt/user/', "/mnt/$sourcedir/", $pathinfo["dirname"]);
|
||||
$repdirfree = disk_free_space($repdir) ;
|
||||
$reflink = true ;
|
||||
$capacity *= 1 ;
|
||||
|
||||
if ($free == "yes" && $repdirfree < $capacity) { $reflink = false ;}
|
||||
if ($free == "yes" && $dirfree < $capacity) { write("addLog\0".htmlspecialchars(_("Insufficent storage for clone"))); return false ;}
|
||||
|
||||
#Clone XML
|
||||
$uuid = $lv->domain_get_uuid($vm) ;
|
||||
$config=domain_to_config($uuid) ;
|
||||
|
||||
$config["domain"]["name"] = $clone ;
|
||||
$config["domain"]["uuid"] = $lv->domain_generate_uuid() ;
|
||||
foreach($config["nic"] as $index => $detail) {
|
||||
$config["nic"][$index]["mac"] = $lv->generate_random_mac_addr() ;
|
||||
}
|
||||
$config["domain"]["type"] = "kvm";
|
||||
|
||||
$usbs = getVMUSBs($vmxml) ;
|
||||
foreach($usbs as $i => $usb) {
|
||||
if ($usb["checked"] == "checked") continue ;
|
||||
unset($usbs[$i]) ;
|
||||
}
|
||||
$config["usb"] = $usbs ;
|
||||
|
||||
$files_exist = false ;
|
||||
$files_clone = array() ;
|
||||
foreach ($config["disk"] as $diskid => $disk) {
|
||||
$file_clone[$diskid]["source"] = $config["disk"][$diskid]["new"] ;
|
||||
$config["disk"][$diskid]["new"] = str_replace($vm,$clone,$config["disk"][$diskid]["new"]) ;
|
||||
$pi = pathinfo($config["disk"][$diskid]["new"]) ;
|
||||
$isdir = is_dir($pi['dirname']) ;
|
||||
if (is_file($config["disk"][$diskid]["new"])) $file_exists = true ;
|
||||
$file_clone[$diskid]["target"] = $config["disk"][$diskid]["new"] ;
|
||||
}
|
||||
|
||||
$clonedir = $domain_cfg['DOMAINDIR'].$clone ;
|
||||
if (!is_dir($clonedir)) {
|
||||
mkdir($clonedir,0777,true) ;
|
||||
chown($clonedir, 'nobody');
|
||||
chgrp($clonedir, 'users');
|
||||
}
|
||||
write("addLog\0".htmlspecialchars("Checking for image files"));
|
||||
if ($file_exists && $overwrite != "yes") { write("addLog\0".htmlspecialchars(_("New image file names exist and Overwrite is not allowed"))); return( false) ; }
|
||||
|
||||
#Create duplicate files.
|
||||
foreach($file_clone as $diskid => $disk) {
|
||||
$target = $disk['target'] ;
|
||||
$source = $disk['source'] ;
|
||||
if ($target == $source) { write("addLog\0".htmlspecialchars(_("New image file is same as old"))); return( false) ; }
|
||||
$sourcerealdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($source)." 2>/dev/null"));
|
||||
$reptgt = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $target);
|
||||
$repsrc = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $source);
|
||||
#var_dump($repsrc,$reptgt) ;
|
||||
|
||||
$cmdstr = "cp --reflink=always '$repsrc' '$reptgt'" ;
|
||||
if ($reflink == true) { $refcmd = $cmdstr ; } else {$refcmd = false; }
|
||||
$cmdstr = "rsync -ahPIXS --out-format=%f --info=flist0,misc0,stats0,name1,progress2 '$source' '$target'" ;
|
||||
$error = execCommand_nchan($cmdstr,$path,$refcmd) ;
|
||||
if (!$error) { write("addLog\0".htmlspecialchars("Image copied failed.")); return( false) ; }
|
||||
}
|
||||
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Completing Clone").": </legend><p class='logLine'></p><span id='wait-$waitID'></span></fieldset>");
|
||||
write("addLog\0".htmlspecialchars("Creating new XML $clone"));
|
||||
|
||||
$xml = $lv->config_to_xml($config, true) ;
|
||||
file_put_contents("/tmp/clonexml" ,$xml) ;
|
||||
$rtn = $lv->domain_define($xml) ;
|
||||
return($rtn) ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function compare_creationtime($a, $b) {
|
||||
return strnatcmp($a['creationtime'], $b['creationtime']);
|
||||
}
|
||||
|
||||
function compare_creationtimelt($a, $b) {
|
||||
return $a['creationtime'] < $b['creationtime'];
|
||||
}
|
||||
|
||||
function getvmsnapshots($vm) {
|
||||
$snaps=array() ;
|
||||
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
|
||||
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
|
||||
$snaps = json_decode($snaps_json,true) ;
|
||||
if (is_array($snaps)) uasort($snaps,'compare_creationtime') ;
|
||||
return $snaps ;
|
||||
}
|
||||
|
||||
function write_snapshots_database($vm,$name) {
|
||||
global $lv ;
|
||||
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
|
||||
if (!is_dir($dbpath)) mkdir($dbpath) ;
|
||||
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
|
||||
$snaps = json_decode($snaps_json,true) ;
|
||||
$snapshot_res=$lv->domain_snapshot_lookup_by_name($vm,$name) ;
|
||||
$snapshot_xml=$lv->domain_snapshot_get_xml($snapshot_res) ;
|
||||
$a = simplexml_load_string($snapshot_xml) ;
|
||||
$a = json_encode($a) ;
|
||||
$b= json_decode($a, TRUE);
|
||||
$vmsnap = $b["name"] ;
|
||||
$snaps[$vmsnap]["name"]= $b["name"];
|
||||
$snaps[$vmsnap]["parent"]= $b["parent"] ;
|
||||
$snaps[$vmsnap]["state"]= $b["state"];
|
||||
$snaps[$vmsnap]["desc"]= $b["description"];
|
||||
$snaps[$vmsnap]["memory"]= $b["memory"];
|
||||
$snaps[$vmsnap]["creationtime"]= $b["creationTime"];
|
||||
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$output = "" ;
|
||||
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
|
||||
foreach($output as $key => $line) {
|
||||
$line=str_replace("image: ","",$line) ;
|
||||
$output[$key] = $line ;
|
||||
}
|
||||
|
||||
$snaps[$vmsnap]['backing'][$disk["device"]] = $output ;
|
||||
$rev = "r".$disk["device"] ;
|
||||
$reversed = array_reverse($output) ;
|
||||
$snaps[$vmsnap]['backing'][$rev] = $reversed ;
|
||||
}
|
||||
$parentfind = $snaps[$vmsnap]['backing'][$disk["device"]] ;
|
||||
$parendfileinfo = pathinfo($parentfind[1]) ;
|
||||
$snaps[$vmsnap]["parent"]= $parendfileinfo["extension"];
|
||||
$snaps[$vmsnap]["parent"] = str_replace("qcow2",'',$snaps[$vmsnap]["parent"]) ;
|
||||
if (isset($parentfind[1]) && !isset($parentfind[2])) $snaps[$vmsnap]["parent"]="Base" ;
|
||||
|
||||
if (array_key_exists(0 , $b["disks"]["disk"])) $snaps[$vmsnap]["disks"]= $b["disks"]["disk"]; else $snaps[$vmsnap]["disks"][0]= $b["disks"]["disk"];
|
||||
|
||||
|
||||
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
|
||||
file_put_contents($dbpath."/snapshots.db",$value) ;
|
||||
}
|
||||
|
||||
function refresh_snapshots_database($vm) {
|
||||
global $lv ;
|
||||
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
|
||||
if (!is_dir($dbpath)) mkdir($dbpath) ;
|
||||
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
|
||||
$snaps = json_decode($snaps_json,true) ;
|
||||
foreach($snaps as $vmsnap=>$snap)
|
||||
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$output = "" ;
|
||||
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
|
||||
foreach($output as $key => $line) {
|
||||
$line=str_replace("image: ","",$line) ;
|
||||
$output[$key] = $line ;
|
||||
}
|
||||
|
||||
$snaps[$vmsnap]['backing'][$disk["device"]] = $output ;
|
||||
$rev = "r".$disk["device"] ;
|
||||
$reversed = array_reverse($output) ;
|
||||
$snaps[$vmsnap]['backing'][$rev] = $reversed ;
|
||||
}
|
||||
$parentfind = $snaps[$vmsnap]['backing'][$disk["device"]] ;
|
||||
$parendfileinfo = pathinfo($parentfind[1]) ;
|
||||
$snaps[$vmsnap]["parent"]= $parendfileinfo["extension"];
|
||||
$snaps[$vmsnap]["parent"] = str_replace("qcow2",'',$snaps[$vmsnap]["parent"]) ;
|
||||
if (isset($parentfind[1]) && !isset($parentfind[2])) $snaps[$vmsnap]["parent"]="Base" ;
|
||||
|
||||
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
|
||||
$res = $lv->get_domain_by_name($vm);
|
||||
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_create_snapshot($lv->domain_get_uuid($vm),$name) ;
|
||||
|
||||
|
||||
#Remove any NVRAMs that are no longer valid.
|
||||
# Get uuid
|
||||
$vmuuid = $lv->domain_get_uuid($vm) ;
|
||||
#Get list of files
|
||||
#$filepath = "/etc/libvirt/qemu/nvram/'.$uuid*" ; #$snapshotname"
|
||||
$filepath = "/etc/libvirt/qemu/nvram/$vmuuid*" ; #$snapshotname"
|
||||
$nvram_files=glob($filepath) ;
|
||||
foreach($nvram_files as $key => $nvram_file) {
|
||||
if ($nvram_file == "/etc/libvirt/qemu/nvram/$vmuuid"."_VARS-pure-efi.fd" || $nvram_file == "/etc/libvirt/qemu/nvram/$vmuuid"."_VARS-pure-efi-tpm.fd" ) unset($nvram_files[$key]) ;
|
||||
foreach ($snaps as $snapshotname => $snap) {
|
||||
$tpmfilename = "/etc/libvirt/qemu/nvram/".$vmuuid.$snapshotname."_VARS-pure-efi-tpm.fd" ;
|
||||
$nontpmfilename = "/etc/libvirt/qemu/nvram/".$vmuuid.$snapshotname."_VARS-pure-efi.fd" ;
|
||||
if ($nvram_file == $tpmfilename || $nvram_file == $nontpmfilename ) {
|
||||
unset($nvram_files[$key]) ;}
|
||||
}
|
||||
}
|
||||
foreach ($nvram_files as $nvram_file) unlink($nvram_file) ;
|
||||
|
||||
|
||||
file_put_contents($dbpath."/snapshots.db",$value) ;
|
||||
}
|
||||
|
||||
function delete_snapshots_database($vm,$name) {
|
||||
global $lv ;
|
||||
$dbpath = "/etc/libvirt/qemu/snapshot/$vm" ;
|
||||
$snaps_json = file_get_contents($dbpath."/snapshots.db") ;
|
||||
$snaps = json_decode($snaps_json,true) ;
|
||||
unset($snaps[$name]) ;
|
||||
$value = json_encode($snaps,JSON_PRETTY_PRINT) ;
|
||||
file_put_contents($dbpath."/snapshots.db",$value) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
function vm_snapshot($vm,$snapshotname, $snapshotdesc, $free = "yes", $memorysnap = "yes") {
|
||||
global $lv ;
|
||||
|
||||
#Get State
|
||||
$res = $lv->get_domain_by_name($vm);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
$state = $lv->domain_state_translate($dom['state']);
|
||||
|
||||
#Get disks for --diskspec
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
$diskspec = "" ;
|
||||
$capacity = 0 ;
|
||||
if ($snapshotname == "--generate") $name= "S" . date("YmdHis") ; else $name=$snapshotname ;
|
||||
if ($snapshotdesc != "") $snapshotdesc = " --description '$snapshotdesc'" ;
|
||||
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$pathinfo = pathinfo($file) ;
|
||||
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
|
||||
$diskspec .= " --diskspec '".$disk["device"]."',snapshot=external,file='".$filenew."'" ;
|
||||
$capacity = $capacity + $disk["capacity"] ;
|
||||
}
|
||||
$dirpath = $pathinfo["dirname"] ;
|
||||
#get memory
|
||||
$mem = $lv->domain_get_memory_stats($vm) ;
|
||||
$memory = $mem[6] ;
|
||||
|
||||
if ($memorysnap = "yes") $memspec = ' --memspec "'.$pathinfo["dirname"].'/memory'.$name.'.mem",snapshot=external' ; else $memspec = "" ;
|
||||
$cmdstr = "virsh snapshot-create-as '$vm' --name '$name' $snapshotdesc --atomic" ;
|
||||
|
||||
|
||||
if ($state == "running") {
|
||||
$cmdstr .= " --live ".$memspec.$diskspec ;
|
||||
$capacity = $capacity + $memory ;
|
||||
|
||||
} else {
|
||||
$cmdstr .= " --disk-only ".$diskspec ;
|
||||
}
|
||||
|
||||
#Check free space.
|
||||
$dirfree = disk_free_space($pathinfo["dirname"]) ;
|
||||
|
||||
$capacity *= 1 ;
|
||||
|
||||
if ($free == "yes" && $dirfree < $capacity) { $arrResponse = ['error' => _("Insufficent Storage for Snapshot")]; return $arrResponse ;}
|
||||
|
||||
#Copy nvram
|
||||
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_create_snapshot($lv->domain_get_uuid($vm),$name) ;
|
||||
|
||||
$xmlfile = $pathinfo["dirname"]."/".$name.".running" ;
|
||||
file_put_contents("/tmp/xmltst", "$xmlfile" ) ;
|
||||
if ($state == "running") exec("virsh dumpxml '$vm' > ".escapeshellarg($xmlfile),$outxml,$rtnxml) ;
|
||||
|
||||
$output= [] ;
|
||||
$test = false ;
|
||||
if ($test) exec($cmdstr." --print-xml 2>&1",$output,$return) ; else exec($cmdstr." 2>&1",$output,$return) ;
|
||||
|
||||
if (strpos(" ".$output[0],"error") ) {
|
||||
$arrResponse = ['error' => substr($output[0],6) ] ;
|
||||
} else {
|
||||
$arrResponse = ['success' => true] ;
|
||||
write_snapshots_database("$vm","$name") ;
|
||||
#remove meta data
|
||||
$ret = $lv->domain_snapshot_delete($vm, "$name" ,2) ;
|
||||
}
|
||||
return $arrResponse ;
|
||||
|
||||
}
|
||||
|
||||
function vm_revert($vm, $snap="--current",$action="no",$actionmeta = 'yes') {
|
||||
global $lv ;
|
||||
$snapslist= getvmsnapshots($vm) ;
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
|
||||
switch ($snapslist[$snap]['state']) {
|
||||
case "shutoff":
|
||||
case "running":
|
||||
#VM must be shutdown.
|
||||
$res = $lv->get_domain_by_name($vm);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
$state = $lv->domain_state_translate($dom['state']);
|
||||
# if VM running shutdown. Record was running.
|
||||
if ($state != 'shutdown') $arrResponse = $lv->domain_destroy($vm) ;
|
||||
# Wait for shutdown?
|
||||
# GetXML
|
||||
$strXML= $lv->domain_get_xml($res) ;
|
||||
$xmlobj = custom::createArray('domain',$strXML) ;
|
||||
|
||||
# Process disks and update path.
|
||||
$disks=($snapslist[$snap]['disks']) ;
|
||||
foreach ($disks as $disk) {
|
||||
$diskname = $disk["@attributes"]["name"] ;
|
||||
if ($diskname == "hda" || $diskname == "hdb") continue ;
|
||||
$path = $disk["source"]["@attributes"]["file"] ;
|
||||
if ($diskname == "hdc") {
|
||||
$primarypathinfo = pathinfo($path) ;
|
||||
$primarypath = $primarypathinfo['dirname'] ;
|
||||
}
|
||||
$item = array_search($path,$snapslist[$snap]['backing'][$diskname]) ;
|
||||
$newpath = $snapslist[$snap]['backing'][$diskname][$item + 1];
|
||||
$json_info = getDiskImageInfo($newpath) ;
|
||||
foreach($xmlobj['devices']['disk'] as $ddk => $dd){
|
||||
if ($dd['target']["@attributes"]['dev'] == $diskname) {
|
||||
$xmlobj['devices']['disk'][$ddk]['source']["@attributes"]['file'] = "$newpath" ;
|
||||
$xmlobj['devices']['disk'][$ddk]['driver']["@attributes"]['type'] = $json_info["format"] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
$xml = custom::createXML('domain',$xmlobj)->saveXML();
|
||||
$new = $lv->domain_define($xml);
|
||||
if ($new)
|
||||
$arrResponse = ['success' => true] ; else
|
||||
$arrResponse = ['error' => $lv->get_last_error()] ;
|
||||
|
||||
# remove snapshot meta data and images for all snpahots.
|
||||
|
||||
foreach ($disks as $disk) {
|
||||
$diskname = $disk["@attributes"]["name"] ;
|
||||
if ($diskname == "hda" || $diskname == "hdb") continue ;
|
||||
$path = $disk["source"]["@attributes"]["file"] ;
|
||||
if (is_file($path) && $action == "yes") unlink("$path") ;
|
||||
$item = array_search($path,$snapslist[$snap]['backing']["r".$diskname]) ;
|
||||
$item++ ;
|
||||
while($item > 0)
|
||||
{
|
||||
if (!isset($snapslist[$snap]['backing']["r".$diskname][$item])) break ;
|
||||
$newpath = $snapslist[$snap]['backing']["r".$diskname][$item] ;
|
||||
if (is_file($newpath) && $action == "yes") unlink("$newpath") ;
|
||||
$item++ ;
|
||||
}
|
||||
}
|
||||
|
||||
uasort($snapslist,'compare_creationtimelt') ;
|
||||
foreach($snapslist as $s) {
|
||||
$name = $s['name'] ;
|
||||
|
||||
$xmlfile = $primarypath."/$name.running" ;
|
||||
$memoryfile = $primarypath."/memory$name.mem" ;
|
||||
|
||||
if ($snapslist[$snap]['state'] == "running") {
|
||||
# Set XML to saved XML
|
||||
$xml = file_get_contents($xmlfile) ;
|
||||
$xmlobj = custom::createArray('domain',$xml) ;
|
||||
$xml = custom::createXML('domain',$xmlobj)->saveXML();
|
||||
$rtn = $lv->domain_define($xml) ;
|
||||
|
||||
# Restore Memory.
|
||||
|
||||
$makerun = true ;
|
||||
if ($makerun == true) exec("virsh restore ".escapeshellarg($memoryfile)) ;
|
||||
#exec("virsh restore $memoryfile") ;
|
||||
}
|
||||
#Delete Metadata only.
|
||||
if ($actionmeta == "yes") {
|
||||
$ret = delete_snapshots_database("$vm","$name") ;
|
||||
}
|
||||
if (is_file($memoryfile) && $action == "yes") unlink($memoryfile) ;
|
||||
if (is_file($xmlfile) && $action == "yes") unlink($xmlfile) ;
|
||||
if ($s['name'] == $snap) break ;
|
||||
}
|
||||
#if VM was started restart.
|
||||
if ($state == 'running' && $snapslist[$snap]['state'] != "running") {
|
||||
$arrResponse = $lv->domain_start($vm) ;
|
||||
}
|
||||
|
||||
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_revert_snapshot($lv->domain_get_uuid($vm),$name) ;
|
||||
break ;
|
||||
|
||||
}
|
||||
$arrResponse = ['success' => true] ;
|
||||
return($arrResponse) ;
|
||||
}
|
||||
|
||||
function vm_snapimages($vm, $snap, $only) {
|
||||
global $lv ;
|
||||
$snapslist= getvmsnapshots($vm) ;
|
||||
$data = "<br><br>Images and metadata to remove if tickbox checked.<br>" ;
|
||||
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$output = "" ;
|
||||
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
|
||||
foreach($output as $key => $line) {
|
||||
$line=str_replace("image: ","",$line) ;
|
||||
$output[$key] = $line ;
|
||||
}
|
||||
$snaps[$vm][$disk["device"]] = $output ;
|
||||
$rev = "r".$disk["device"] ;
|
||||
$reversed = array_reverse($output) ;
|
||||
$snaps[$vm][$rev] = $reversed ;
|
||||
$pathinfo = pathinfo($file) ;
|
||||
$filenew = $pathinfo["dirname"].'/'.$pathinfo["filename"].'.'.$name.'qcow2' ;
|
||||
$diskspec .= " --diskspec ".$disk["device"].",snapshot=external,file=".$filenew ;
|
||||
$capacity = $capacity + $disk["capacity"] ;
|
||||
}
|
||||
|
||||
$snapdisks= $snapslist[$snap]['disks'] ;
|
||||
|
||||
foreach ($snapdisks as $diskkey => $snapdisk) {
|
||||
$diskname = $snapdisk["@attributes"]["name"] ;
|
||||
if ($diskname == "hda" || $diskname == "hdb") continue ;
|
||||
$path = $snapdisk["source"]["@attributes"]["file"] ;
|
||||
if (is_file($path)) $data .= "$path<br>" ;
|
||||
$item = array_search($path,$snaps[$vm]["r".$diskname]) ;
|
||||
$item++ ;
|
||||
if ($only == 0) $item = 0 ;
|
||||
while($item > 0)
|
||||
{
|
||||
if (!isset($snaps[$vm]["r".$diskname][$item])) break ;
|
||||
$newpath = $snaps[$vm]["r".$diskname][$item] ;
|
||||
if (is_file($path)) $data .= "$newpath<br>" ;
|
||||
$item++ ;
|
||||
|
||||
}
|
||||
}
|
||||
$data .= "<br>Snapshots metadata to remove." ;
|
||||
if ($only == 0) {
|
||||
$data .= "<br>$snap";
|
||||
} else {
|
||||
uasort($snapslist,'compare_creationtimelt') ;
|
||||
foreach($snapslist as $s) {
|
||||
$name = $s['name'] ;
|
||||
$data .= "<br>$name";
|
||||
if ($s['name'] == $snap) break ;
|
||||
}
|
||||
}
|
||||
return($data) ;
|
||||
}
|
||||
|
||||
|
||||
function vm_snapremove($vm, $snap) {
|
||||
global $lv ;
|
||||
$snapslist= getvmsnapshots($vm) ;
|
||||
$res = $lv->get_domain_by_name($vm);
|
||||
$dom = $lv->domain_get_info($res);
|
||||
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$output = "" ;
|
||||
exec("qemu-img info --backing-chain -U $file | grep image:",$output) ;
|
||||
foreach($output as $key => $line) {
|
||||
$line=str_replace("image: ","",$line) ;
|
||||
$output[$key] = $line ;
|
||||
}
|
||||
|
||||
$snaps[$vm][$disk["device"]] = $output ;
|
||||
$rev = "r".$disk["device"] ;
|
||||
$reversed = array_reverse($output) ;
|
||||
$snaps[$vm][$rev] = $reversed ;
|
||||
$pathinfo = pathinfo($file) ;
|
||||
}
|
||||
|
||||
# GetXML
|
||||
$strXML= $lv->domain_get_xml($res) ;
|
||||
$xmlobj = custom::createArray('domain',$strXML) ;
|
||||
|
||||
# Process disks.
|
||||
$disks=($snapslist[$snap]['disks']) ;
|
||||
foreach ($disks as $disk) {
|
||||
$diskname = $disk["@attributes"]["name"] ;
|
||||
if ($diskname == "hda" || $diskname == "hdb") continue ;
|
||||
$path = $disk["source"]["@attributes"]["file"] ;
|
||||
$item = array_search($path,$snaps[$vm][$diskname]) ;
|
||||
if ($item!==false) {
|
||||
$data = ["error" => "Image currently active for this domain."] ;
|
||||
return ($data) ;
|
||||
}
|
||||
}
|
||||
|
||||
$disks=($snapslist[$snap]['disks']) ;
|
||||
foreach ($disks as $disk) {
|
||||
$diskname = $disk["@attributes"]["name"] ;
|
||||
if ($diskname == "hda" || $diskname == "hdb") continue ;
|
||||
$path = $disk["source"]["@attributes"]["file"] ;
|
||||
if (is_file($path)) {
|
||||
if(!unlink("$path")) {
|
||||
$data = ["error" => "Unable to remove image file $path"] ;
|
||||
return ($data) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Delete NVRAM
|
||||
if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_delete_snapshot($lv->domain_get_uuid($vm),$snap) ;
|
||||
|
||||
$ret = delete_snapshots_database("$vm","$snap") ;
|
||||
|
||||
if(!$ret)
|
||||
$data = ["error" => "Unable to remove snap metadata $snap"] ;
|
||||
else
|
||||
$data = ["success => 'true"] ;
|
||||
|
||||
return($data) ;
|
||||
}
|
||||
|
||||
function vm_blockcommit($vm, $snap ,$path,$base,$top,$pivot,$action) {
|
||||
global $lv ;
|
||||
/*
|
||||
NAME
|
||||
blockcommit - Start a block commit operation.
|
||||
|
||||
SYNOPSIS
|
||||
blockcommit <domain> <path> [--bandwidth <number>] [--base <string>] [--shallow] [--top <string>] [--active] [--delete] [--wait] [--verbose] [--timeout <number>] [--pivot] [--keep-overlay] [--async] [--keep-relative] [--bytes]
|
||||
|
||||
DESCRIPTION
|
||||
Commit changes from a snapshot down to its backing image.
|
||||
|
||||
OPTIONS
|
||||
[--domain] <string> domain name, id or uuid
|
||||
[--path] <string> fully-qualified path of disk
|
||||
--bandwidth <number> bandwidth limit in MiB/s
|
||||
--base <string> path of base file to commit into (default bottom of chain)
|
||||
--shallow use backing file of top as base
|
||||
--top <string> path of top file to commit from (default top of chain)
|
||||
--active trigger two-stage active commit of top file
|
||||
--delete delete files that were successfully committed
|
||||
--wait wait for job to complete (with --active, wait for job to sync)
|
||||
--verbose with --wait, display the progress
|
||||
--timeout <number> implies --wait, abort if copy exceeds timeout (in seconds)
|
||||
--pivot implies --active --wait, pivot when commit is synced
|
||||
--keep-overlay implies --active --wait, quit when commit is synced
|
||||
--async with --wait, don't wait for cancel to finish
|
||||
--keep-relative keep the backing chain relatively referenced
|
||||
--bytes the bandwidth limit is in bytes/s rather than MiB/s
|
||||
|
||||
blockcommit Debian --path /mnt/user/domains/Debian/vdisk1.S20230513120410qcow2 --verbose --pivot --delete
|
||||
*/
|
||||
# Error if VM Not running.
|
||||
|
||||
$snapslist= getvmsnapshots($vm) ;
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
|
||||
foreach($disks as $disk) {
|
||||
$path = $disk['file'] ;
|
||||
$cmdstr = "virsh blockcommit '$vm' --path '$path' --verbose " ;
|
||||
if ($pivot == "yes") $cmdstr .= " --pivot " ;
|
||||
if ($action == "yes") $cmdstr .= " --delete " ;
|
||||
# Process disks and update path.
|
||||
$snapdisks=($snapslist[$snap]['disks']) ;
|
||||
if ($base != "--base" && $base != "") {
|
||||
#get file name from snapshot.
|
||||
$snapdisks=($snapslist[$base]['disks']) ;
|
||||
$basepath = "" ;
|
||||
foreach ($snapdisks as $snapdisk) {
|
||||
$diskname = $snapdisk["@attributes"]["name"] ;
|
||||
if ($diskname != $disk['device']) continue ;
|
||||
$basepath = $snapdisk["source"]["@attributes"]["file"] ;
|
||||
}
|
||||
if ($basepath != "") $cmdstr .= " --base '$basepath' ";
|
||||
}
|
||||
if ($top != "--top" && $top !="") {
|
||||
#get file name from snapshot.
|
||||
$snapdisks=($snapslist[$top]['disks']) ;
|
||||
$toppath = "" ;
|
||||
foreach ($snapdisks as $snapdisk) {
|
||||
$diskname = $snapdisk["@attributes"]["name"] ;
|
||||
if ($diskname != $disk['device']) continue ;
|
||||
$toppath = $snapdisk["source"]["@attributes"]["file"] ;
|
||||
}
|
||||
if ($toppath != "") $cmdstr .= " --top '$toppath' ";
|
||||
}
|
||||
|
||||
$error = execCommand_nchan($cmdstr,$path) ;
|
||||
if (!$error) {
|
||||
$arrResponse = ['error' => substr($output[0],6) ] ;
|
||||
return($arrResponse) ;
|
||||
} else {
|
||||
$arrResponse = ['success' => true] ;
|
||||
}
|
||||
|
||||
}
|
||||
# Delete NVRAM
|
||||
#if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_delete_snapshot($lv->domain_get_uuid($vm),$snap) ;
|
||||
|
||||
refresh_snapshots_database($vm) ;
|
||||
$ret = $ret = delete_snapshots_database("$vm","$snap") ; ;
|
||||
if($ret)
|
||||
$data = ["error" => "Unable to remove snap metadata $snap"] ;
|
||||
else
|
||||
$data = ["success => 'true"] ;
|
||||
return $data ;
|
||||
|
||||
}
|
||||
|
||||
function vm_blockpull($vm, $snap ,$path,$base,$top,$pivot,$action) {
|
||||
global $lv ;
|
||||
/*
|
||||
NAME
|
||||
blockpull - Populate a disk from its backing image.
|
||||
|
||||
SYNOPSIS
|
||||
blockpull <domain> <path> [--bandwidth <number>] [--base <string>] [--wait] [--verbose] [--timeout <number>] [--async] [--keep-relative] [--bytes]
|
||||
|
||||
DESCRIPTION
|
||||
Populate a disk from its backing image.
|
||||
|
||||
OPTIONS
|
||||
[--domain] <string> domain name, id or uuid
|
||||
[--path] <string> fully-qualified path of disk
|
||||
--bandwidth <number> bandwidth limit in MiB/s
|
||||
--base <string> path of backing file in chain for a partial pull
|
||||
--wait wait for job to finish
|
||||
--verbose with --wait, display the progress
|
||||
--timeout <number> with --wait, abort if pull exceeds timeout (in seconds)
|
||||
--async with --wait, don't wait for cancel to finish
|
||||
--keep-relative keep the backing chain relatively referenced
|
||||
--bytes the bandwidth limit is in bytes/s rather than MiB/s
|
||||
|
||||
|
||||
*/
|
||||
$snapslist= getvmsnapshots($vm) ;
|
||||
$disks =$lv->get_disk_stats($vm) ;
|
||||
foreach($disks as $disk) {
|
||||
$file = $disk["file"] ;
|
||||
$output = "" ;
|
||||
exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ;
|
||||
foreach($output as $key => $line) {
|
||||
$line=str_replace("image: ","",$line) ;
|
||||
$output[$key] = $line ;
|
||||
}
|
||||
$snaps[$vm][$disk["device"]] = $output ;
|
||||
$rev = "r".$disk["device"] ;
|
||||
$reversed = array_reverse($output) ;
|
||||
$snaps[$vm][$rev] = $reversed ;
|
||||
}
|
||||
$snaps_json=json_encode($snaps,JSON_PRETTY_PRINT) ;
|
||||
$pathinfo = pathinfo($file) ;
|
||||
$dirpath = $pathinfo["dirname"] ;
|
||||
file_put_contents("$dirpath/image.tracker",$snaps_json) ;
|
||||
|
||||
foreach($disks as $disk) {
|
||||
$path = $disk['file'] ;
|
||||
$cmdstr = "virsh blockpull '$vm' --path '$path' --verbose --pivot --delete" ;
|
||||
$cmdstr = "virsh blockpull '$vm' --path '$path' --verbose --wait " ;
|
||||
# Process disks and update path.
|
||||
$snapdisks=($snapslist[$snap]['disks']) ;
|
||||
if ($base != "--base" && $base != "") {
|
||||
#get file name from snapshot.
|
||||
$snapdisks=($snapslist[$base]['disks']) ;
|
||||
$basepath = "" ;
|
||||
foreach ($snapdisks as $snapdisk) {
|
||||
$diskname = $snapdisk["@attributes"]["name"] ;
|
||||
if ($diskname != $disk['device']) continue ;
|
||||
$basepath = $snapdisk["source"]["@attributes"]["file"] ;
|
||||
}
|
||||
if ($basepath != "") $cmdstr .= " --base '$basepath' ";
|
||||
}
|
||||
|
||||
if ($action) $cmdstr .= " $action ";
|
||||
|
||||
|
||||
$error = execCommand_nchan($cmdstr,$path) ;
|
||||
|
||||
if (!$error) {
|
||||
$arrResponse = ['error' => substr($output[0],6) ] ;
|
||||
return($arrResponse) ;
|
||||
} else {
|
||||
# Remove nvram snapshot
|
||||
$arrResponse = ['success' => true] ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
refresh_snapshots_database($vm) ;
|
||||
if($ret)
|
||||
$data = ["error" => "Unable to remove snap metadata $snap"] ;
|
||||
else
|
||||
$data = ["success => 'true"] ;
|
||||
|
||||
return $data ;
|
||||
|
||||
}
|
||||
|
||||
function vm_blockcopy($vm,$path,$base,$top,$pivot,$action) {
|
||||
/*
|
||||
NAME
|
||||
blockcopy - Start a block copy operation.
|
||||
|
||||
SYNOPSIS
|
||||
blockcopy <domain> <path> [--dest <string>] [--bandwidth <number>] [--shallow] [--reuse-external] [--blockdev] [--wait] [--verbose] [--timeout <number>] [--pivot] [--finish] [--async] [--xml <string>] [--format <string>] [--granularity <number>] [--buf-size <number>] [--bytes] [--transient-job] [--synchronous-writes] [--print-xml]
|
||||
|
||||
DESCRIPTION
|
||||
Copy a disk backing image chain to dest.
|
||||
|
||||
OPTIONS
|
||||
[--domain] <string> domain name, id or uuid
|
||||
[--path] <string> fully-qualified path of source disk
|
||||
--dest <string> path of the copy to create
|
||||
--bandwidth <number> bandwidth limit in MiB/s
|
||||
--shallow make the copy share a backing chain
|
||||
--reuse-external reuse existing destination
|
||||
--blockdev copy destination is block device instead of regular file
|
||||
--wait wait for job to reach mirroring phase
|
||||
--verbose with --wait, display the progress
|
||||
--timeout <number> implies --wait, abort if copy exceeds timeout (in seconds)
|
||||
--pivot implies --wait, pivot when mirroring starts
|
||||
--finish implies --wait, quit when mirroring starts
|
||||
--async with --wait, don't wait for cancel to finish
|
||||
--xml <string> filename containing XML description of the copy destination
|
||||
--format <string> format of the destination file
|
||||
--granularity <number> power-of-two granularity to use during the copy
|
||||
--buf-size <number> maximum amount of in-flight data during the copy
|
||||
--bytes the bandwidth limit is in bytes/s rather than MiB/s
|
||||
--transient-job the copy job is not persisted if VM is turned off
|
||||
--synchronous-writes the copy job forces guest writes to be synchronously written to the destination
|
||||
--print-xml print the XML used to start the copy job instead of starting the job
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -62,7 +62,7 @@ function ajaxVMDispatchconsoleRV(params, spin){
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, console="web"){
|
||||
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, console="web", preview=false){
|
||||
var opts = [];
|
||||
var path = location.pathname;
|
||||
var x = path.indexOf("?");
|
||||
@@ -106,6 +106,12 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch( {action:"domain-destroy", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({divider:true});
|
||||
|
||||
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
|
||||
e.preventDefault();
|
||||
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
|
||||
}});
|
||||
} else if (state == "pmsuspended") {
|
||||
opts.push({text:_("Resume"), icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
@@ -141,14 +147,26 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
|
||||
ajaxVMDispatchconsoleRV({action:"domain-start-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
|
||||
}});
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
opts.push({divider:true});
|
||||
if (log !== "") {
|
||||
opts.push({text:_("Logs"), icon:"fa-navicon", action:function(e){e.preventDefault(); openTerminal('log',name,log);}});
|
||||
}
|
||||
opts.push({text:_("Edit"), icon:"fa-pencil", href:path+'/UpdateVM?uuid='+uuid});
|
||||
|
||||
if (state == "shutoff") {
|
||||
|
||||
opts.push({text:_("Clone"), icon:"fa-clone", action:function(e) {
|
||||
e.preventDefault();
|
||||
var clonename = VMClone(uuid,name) ;
|
||||
}});
|
||||
|
||||
opts.push({divider:true});
|
||||
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
|
||||
e.preventDefault();
|
||||
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
|
||||
}});
|
||||
opts.push({text:_("Remove VM"), icon:"fa-minus", action:function(e) {
|
||||
e.preventDefault();
|
||||
swal({
|
||||
@@ -182,6 +200,50 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, c
|
||||
}
|
||||
context.attach('#vm-'+uuid, opts);
|
||||
}
|
||||
function addVMSnapContext(name, uuid, template, state, snapshotname, preview=false){
|
||||
var opts = [];
|
||||
var path = location.pathname;
|
||||
var x = path.indexOf("?");
|
||||
if (x!=-1) path = path.substring(0,x);
|
||||
|
||||
context.settings({right:false,above:false});
|
||||
if (state == "running") {
|
||||
|
||||
opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) {
|
||||
e.preventDefault();
|
||||
selectsnapshot(uuid, name, snapshotname, "revert",true) ;
|
||||
}});
|
||||
|
||||
opts.push({text:_("Block Commit"), icon:"fa-hdd-o", action:function(e) {
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
e.preventDefault();
|
||||
selectblock(uuid, name, snapshotname, "commit",true) ;
|
||||
}});
|
||||
|
||||
opts.push({text:_("Block Pull"), icon:"fa-hdd-o", action:function(e) {
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
e.preventDefault();
|
||||
selectblock(uuid, name, snapshotname, "pull",true) ;
|
||||
}});
|
||||
if (preview) {
|
||||
opts.push({text:_("Block Copy"), icon:"fa-stop", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-stop", uuid:uuid}, "loadlist");
|
||||
}}); }
|
||||
} else {
|
||||
opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) {
|
||||
e.preventDefault();
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
selectsnapshot(uuid, name, snapshotname, "revert",true) ;
|
||||
}});
|
||||
}
|
||||
opts.push({text:_("Remove snapshot"), icon:"fa-trash", action:function(e) {
|
||||
e.preventDefault();
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
selectsnapshot(uuid, name, snapshotname, "remove",true) ;
|
||||
}});
|
||||
context.attach('#vmsnap-'+uuid, opts);
|
||||
}
|
||||
function startAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
for (var i=0,vm; vm=kvm[i]; i++) if (vm.state!='running') $('#vm-'+vm.id).parent().find('i').removeClass('fa-square').addClass('fa-refresh fa-spin');
|
||||
@@ -225,3 +287,5 @@ function addVM() {
|
||||
if (x!=-1) path = path.substring(0,x);
|
||||
location = path+"/VMTemplates";
|
||||
}
|
||||
|
||||
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
function write(...$messages){
|
||||
$com = curl_init();
|
||||
curl_setopt_array($com,[
|
||||
CURLOPT_URL => 'http://localhost/pub/vmaction?buffer_length=1',
|
||||
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
|
||||
CURLOPT_POST => 1,
|
||||
CURLOPT_RETURNTRANSFER => true
|
||||
]);
|
||||
foreach ($messages as $message) {
|
||||
curl_setopt($com, CURLOPT_POSTFIELDS, $message);
|
||||
curl_exec($com);
|
||||
}
|
||||
curl_close($com);
|
||||
}
|
||||
function execCommand_nchan($command,$idx) {
|
||||
$waitID = mt_rand();
|
||||
[$cmd,$args] = explode(' ',$command,2);
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br> -",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
|
||||
write("addLog\0<br>") ;
|
||||
write("addToID\0$idx\0 $action") ;
|
||||
$proc = popen("$command 2>&1",'r');
|
||||
while ($out = fgets($proc)) {
|
||||
$out = preg_replace("%[\t\n\x0B\f\r]+%", '',$out);
|
||||
if (substr($out,0,1) == "B") { ;
|
||||
write("progress\0$idx\0".htmlspecialchars(substr($out,strrpos($out,"Block Pull")))) ;
|
||||
} else echo write("addToID\0$idx\0 ".htmlspecialchars($out));
|
||||
}
|
||||
$retval = pclose($proc);
|
||||
$out = $retval ? _('The command failed').'.' : _('The command finished successfully').'!';
|
||||
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
|
||||
return $retval===0;
|
||||
}
|
||||
|
||||
#{action:"snap-", uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc}
|
||||
#VM ID [ 99]: pull. .Block Pull: [ 0 %]Block Pull: [100 %].Pull complete.
|
||||
$url = rawurldecode($argv[1]??'');
|
||||
$waitID = mt_rand();
|
||||
$style = ["<style>"];
|
||||
$style[] = ".logLine{font-family:bitstream!important;font-size:1.2rem!important;margin:0;padding:0}";
|
||||
$style[] = "fieldset.docker{border:solid thin;margin-top:8px}";
|
||||
$style[] = "legend{font-size:1.1rem!important;font-weight:bold}";
|
||||
$style[] = "</style>";
|
||||
|
||||
foreach (explode('&', $url) as $chunk) {
|
||||
$param = explode("=", $chunk);
|
||||
if ($param) {
|
||||
${urldecode($param[0])} = urldecode($param[1]) ;
|
||||
}
|
||||
}
|
||||
$id = 1 ;
|
||||
write(implode($style)."<p class='logLine'></p>");
|
||||
$process = " " ;
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Options for Block $action").": </legend><p class='logLine'></p><span id='wait-$waitID'>"._('Please wait')." </span></fieldset>");
|
||||
write("addLog\0".htmlspecialchars("VMName $name "));
|
||||
write("addLog\0".htmlspecialchars("SNAP $snapshotname "));
|
||||
write("addLog\0".htmlspecialchars("Base $targetbase "));
|
||||
if ($action == "commit") {
|
||||
write("addLog\0".htmlspecialchars("Top $targettop "));
|
||||
write("addLog\0".htmlspecialchars("Pivot $targetpivot "));
|
||||
write("addLog\0".htmlspecialchars("Delete $targetdelete "));
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case "commit":
|
||||
vm_blockcommit($name,$snapshotname,$path,$targetbase,$targettop,$targetpivot,$targetdelete) ;
|
||||
break ;
|
||||
case "copy":
|
||||
vm_blockcopy($name,$snapshotname,$path,$targetbase,$targettop,$pivot,' ') ;
|
||||
break;
|
||||
case "pull":
|
||||
vm_blockpull($name,$snapshotname,$path,$targetbase,$targettop,$pivot,' ') ;
|
||||
break ;
|
||||
|
||||
}
|
||||
#execCommand_nchan("ls /") ;
|
||||
write("stop_Wait\0$waitID") ;
|
||||
write('_DONE_','');
|
||||
|
||||
?>
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
function write(...$messages){
|
||||
$com = curl_init();
|
||||
curl_setopt_array($com,[
|
||||
CURLOPT_URL => 'http://localhost/pub/vmaction?buffer_length=1',
|
||||
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
|
||||
CURLOPT_POST => 1,
|
||||
CURLOPT_RETURNTRANSFER => true
|
||||
]);
|
||||
foreach ($messages as $message) {
|
||||
curl_setopt($com, CURLOPT_POSTFIELDS, $message);
|
||||
curl_exec($com);
|
||||
}
|
||||
curl_close($com);
|
||||
}
|
||||
function execCommand_nchan($command,$idx,$refcmd=false) {
|
||||
$waitID = mt_rand();
|
||||
if ($refcmd) {
|
||||
[$cmd,$args] = explode(' ',$refcmd,2);
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br> -",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
|
||||
$rtn = exec("$refcmd 2>&1", $output,$return) ;
|
||||
if ($return == 0) $reflinkok = true ; else {
|
||||
$reflinkok = false ;
|
||||
write("addLog\0<br><b>{$output[0]}</b>");
|
||||
}
|
||||
$out = $return ? _('The command failed revert to rsync')."." : _('The command finished successfully').'!';
|
||||
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
|
||||
}
|
||||
|
||||
if ($reflinkok) {
|
||||
return true ;
|
||||
} else {
|
||||
$waitID = mt_rand();
|
||||
[$cmd,$args] = explode(' ',$command,2);
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._('Command execution')."</legend>".basename($cmd).' '.str_replace(" -","<br> -",htmlspecialchars($args))."<br><span id='wait-$waitID'>"._('Please wait')." </span><p class='logLine'></p></fieldset>","show_Wait\0$waitID");
|
||||
|
||||
write("addToID\0$idx\0Cloning VM: ") ;
|
||||
$proc = popen("$command 2>&1 &",'r');
|
||||
while ($out = fread($proc,100)) {
|
||||
$out = preg_replace("%[\t\n\x0B\f\r]+%", '',$out);
|
||||
$out = trim($out) ;
|
||||
$values = explode(' ',$out) ;
|
||||
$string = _("Data copied: ").$values[0].' '._(" Percentage: ").$values[1].' '._(" Transfer Rate: ").$values[2].' '._(" Time remaining: ").$values[4].$values[5] ;
|
||||
write("progress\0$idx\0".htmlspecialchars($string)) ;
|
||||
if ($out) $stringsave=$string ;
|
||||
}
|
||||
$retval = pclose($proc);
|
||||
write("progress\0$idx\0".htmlspecialchars($stringsave)) ;
|
||||
$out = $retval ? _('The command failed').'.' : _('The command finished successfully').'!';
|
||||
write("stop_Wait\0$waitID","addLog\0<br><b>$out</b>");
|
||||
return $retval===0;
|
||||
}
|
||||
}
|
||||
|
||||
#{action:"snap-", uuid:uuid , snapshotname:target , remove:remove, free:free ,removemeta:removemeta ,keep:keep, desc:desc}
|
||||
#VM ID [ 99]: pull. .Block Pull: [ 0 %]Block Pull: [100 %].Pull complete.
|
||||
$url = rawurldecode($argv[1]??'');
|
||||
$waitID = mt_rand();
|
||||
$style = ["<style>"];
|
||||
$style[] = ".logLine{font-family:bitstream!important;font-size:1.2rem!important;margin:0;padding:0}";
|
||||
$style[] = "fieldset.docker{border:solid thin;margin-top:8px}";
|
||||
$style[] = "legend{font-size:1.1rem!important;font-weight:bold}";
|
||||
$style[] = "</style>";
|
||||
|
||||
foreach (explode('&', $url) as $chunk) {
|
||||
$param = explode("=", $chunk);
|
||||
if ($param) {
|
||||
${urldecode($param[0])} = urldecode($param[1]) ;
|
||||
}
|
||||
}
|
||||
$id = 1 ;
|
||||
write(implode($style)."<p class='logLine'></p>");
|
||||
$process = " " ;
|
||||
$actiontxt = ucfirst($action) ;
|
||||
write("<p class='logLine'></p>","addLog\0<fieldset class='docker'><legend>"._("Options for $actiontxt").": </legend><p class='logLine'></p></fieldset>");
|
||||
write("addLog\0".htmlspecialchars("Cloning $name to $clone"));
|
||||
|
||||
switch ($action) {
|
||||
case "clone":
|
||||
$rtn = vm_clone($name,$clone,$overwrite,$start,$edit,$free,$waitID) ;
|
||||
break ;
|
||||
}
|
||||
write("stop_Wait\0$waitID") ;
|
||||
if ($rtn) write('_DONE_',''); else write('_ERROR_','');
|
||||
?>
|
||||
@@ -1,10 +1,13 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# Intialize libvirt config storage
|
||||
# Invoked by emhttp after mounting libvirt loopback but before starting libvirt.
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
|
||||
# missing qemu directory would indicate new libvirt image file created
|
||||
if [ ! -d /etc/libvirt/qemu ]; then
|
||||
logger "initializing /etc/libvirt"
|
||||
log "initializing /etc/libvirt"
|
||||
# initialize with default settings
|
||||
cp -rp /etc/libvirt-/* /etc/libvirt
|
||||
# check if libvirt image file exists on USB flash
|
||||
|
||||
@@ -568,8 +568,8 @@ function formatWarning(val) {
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Unclean shutdown detected)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
|
||||
<td>**_(Start)_** _(will bring the array on-line)_.</td></tr>
|
||||
<? elseif (missing_cache()):?>
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing Cache disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
|
||||
<td>**_(Start)_** _(will remove the missing cache disk and then bring the array on-line)_.
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing pool disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
|
||||
<td>**_(Start)_** _(will remove the missing pool disk and then bring the array on-line)_.
|
||||
<br><input type="checkbox" name="confirmStart" value="OFF" onclick="$('#cmdStart').prop('disabled',!arrayOps.confirmStart.checked)"><small>_(Yes, I want to do this)_</small></td></tr>
|
||||
<? else:?>
|
||||
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
|
||||
|
||||
+1015
-32
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,343 @@
|
||||
Menu="Buttons:3a"
|
||||
Title="File Manager"
|
||||
Icon="icon-u-duplicate"
|
||||
Code="e963"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$dfm = [
|
||||
'browser' => $myPage['name']=='Browse',
|
||||
'running' => file_exists('/var/tmp/file.manager.active'),
|
||||
'jobs' => file_exists('/var/tmp/file.manager.jobs'),
|
||||
'zfs' => is_executable('/usr/sbin/zfs')
|
||||
];
|
||||
if ($dfm['running'] || $dfm['browser']) eval('?>'.parse_file("$docroot/webGui/include/Templates.php"));
|
||||
?>
|
||||
<script>
|
||||
function BrowseButton() {
|
||||
location.replace('/<?=$task?>/Browse?dir=/mnt');
|
||||
}
|
||||
// Prototypes
|
||||
String.prototype.dfm_patch = function(){return this.replace('rw','x+rw').replace('r-','wx+r').replace('--','rwx');}
|
||||
String.prototype.dfm_proxy = function(){return this.replace('name','row');}
|
||||
String.prototype.dfm_fetch = function(tag){return this.replace('check',tag);}
|
||||
String.prototype.dfm_bring = function(tag){return this.replace('row',tag);}
|
||||
String.prototype.dfm_strip = function(){return this.replace(/\/$/,'');}
|
||||
String.prototype.dfm_quote = function(){return this.replace(/"/g,'"');}
|
||||
String.prototype.dfm_alter = function(...a){var t=this;for(var i=0;i<a.length;i+=2){t=t.replace(a[i],a[i+1]);} return t;}
|
||||
String.prototype.dfm_build = function(){return this.replace(/\n(<!--!|!-->)\n/g,'');}
|
||||
String.prototype.dfm_wedge = function(len){len=len||70;return this.length<=len ? this : this.slice(0,Math.round(len/2)-2)+'...'+this.slice(-1-Math.round(len/2));}
|
||||
|
||||
// General variables
|
||||
const dfm = {window:null, dialog:false, running:false, previous:'', height:0, tsize:{0:0,1:6,2:3,3:3,4:3,11:2,12:2,14:0,15:3}};
|
||||
var dfm_read = {};
|
||||
|
||||
function dfm_footer(action,text) {
|
||||
switch (action) {
|
||||
case 'show':
|
||||
$('#countdown').show();
|
||||
$('#user-notice').show();
|
||||
break;
|
||||
case 'hide':
|
||||
$('#countdown').hide();
|
||||
$('#user-notice').hide();
|
||||
break;
|
||||
case 'write':
|
||||
if ($('#countdown').html()=='') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
|
||||
$('#user-notice').html(text);
|
||||
break;
|
||||
case 'clear':
|
||||
$('#countdown').html('');
|
||||
$('#user-notice').html('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
function dfm_done() {
|
||||
dfm_footer('write',"<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
|
||||
}
|
||||
function dfm_minimize() {
|
||||
dfm.window.dialog('close');
|
||||
dfm_footer('show');
|
||||
}
|
||||
function dfm_close_button() {
|
||||
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-window-minimize"></i>').prop({'title':"_(Minimize)_"}).prop('onclick',null).off('click').click(function(){dfm_minimize();}).show();
|
||||
}
|
||||
function dfm_htmlspecialchars(text) {
|
||||
var map = {'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
||||
return text.replace(/[&<>"']/g,function(m){return map[m];});
|
||||
}
|
||||
function dfm_escapeHTML(name) {
|
||||
const data = document.createElement('div');
|
||||
const text = document.createTextNode(name);
|
||||
data.appendChild(text);
|
||||
return data.innerHTML;
|
||||
}
|
||||
function dfm_createSource(source) {
|
||||
var select = dfm.window.find('#dfm_source');
|
||||
if (Array.isArray(source)) {
|
||||
for (var i=0,object; object=source[i]; i++) {
|
||||
if (i < 10) {
|
||||
select.html(select.html()+'<option'+(i==0?' selected':'')+'>'+object+'</option>');
|
||||
} else {
|
||||
select.html(select.html()+'<option><_(more)_> ...</option>');
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
select.html('<option selected>'+source+'</option>');
|
||||
}
|
||||
}
|
||||
function dfm_showProgress(data) {
|
||||
if (!data) return 0;
|
||||
let file = null;
|
||||
let text = data.split('\n');
|
||||
let line = text[0].split('... ');
|
||||
let strict = /^mnt|^boot/;
|
||||
let footer = false;
|
||||
if (text[0]=='#cat#') {
|
||||
let loc = [], cat = [];
|
||||
for (let i=1,row; row=text[i]; i++) {
|
||||
if (!row) continue;
|
||||
row = row.split('\0');
|
||||
loc.push(row[0]);
|
||||
cat.push(row[1].dfm_wedge(80));
|
||||
}
|
||||
if (cat.length > 0) {
|
||||
dfm.window.find('.dfm_loc').html(loc.join('<br>'));
|
||||
dfm.window.find('.dfm_text').html(cat.join('<br>'));
|
||||
dfm.window.find('#dfm_files').html(loc.length+" "+"_(files)_");
|
||||
}
|
||||
return cat.length;
|
||||
} else if (text.length==1) {
|
||||
text = text[0].dfm_wedge(80);
|
||||
footer = text.indexOf("_(Searching)_") != -1;
|
||||
} else {
|
||||
if (strict.test(text[1])) {
|
||||
file = text[1];
|
||||
text = dfm.previous;
|
||||
} else {
|
||||
file = line[1];
|
||||
text = text[1].split(/\s+/);
|
||||
text = "<i class='fa fa-circle-o-notch fa-spin dfm'></i>_(Completed)_: "+text[1]+", _(Speed)_: "+text[2]+", _(ETA)_: "+text[3];
|
||||
dfm.previous = text;
|
||||
footer = true;
|
||||
}
|
||||
}
|
||||
if (file==null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
|
||||
if (footer) dfm_footer('write',text);
|
||||
return 0;
|
||||
}
|
||||
function dfm_fileManager(action) {
|
||||
switch (action) {
|
||||
case 'start':
|
||||
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
|
||||
<?if ($dfm['browser']):?>
|
||||
$('.dfm_control').prop('disabled',true);
|
||||
$('.dfm_control.jobs').prop('disabled',$.cookie('dfm_control.jobs')?false:true);
|
||||
<?endif;?>
|
||||
if (!dfm.running) nchan_filemanager.start();
|
||||
dfm.running = true;
|
||||
break;
|
||||
case 'stop':
|
||||
if (dfm.running) nchan_filemanager.stop();
|
||||
<?if ($dfm['browser']):?>
|
||||
dfm.window.find('.dfm_text').removeClass('orange-text').html('');
|
||||
$('.dfm_control.basic').prop('disabled',false);
|
||||
$('.dfm_control.common').prop('disabled',$.cookie('dfm_control.common')?true:false);
|
||||
<?endif;?>
|
||||
dfm_footer('clear');
|
||||
dfm.running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
function dfm_makeDialog(open) {
|
||||
if (open && dfm_read.action==15) {
|
||||
dfm.window.dialog('open');
|
||||
dfm_footer('hide');
|
||||
return;
|
||||
}
|
||||
dfm.window = $('#dfm_dialogWindow');
|
||||
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
|
||||
var dfm_source = dfm_read.source.split('\r').slice(0,9);
|
||||
switch (dfm_read.action) {
|
||||
case 0: // create folder/object
|
||||
dfm.window.html($('#dfm_templateCreateFolder').html());
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 1: // delete folder/object
|
||||
dfm.window.html($('#dfm_templateDeleteFolder').html());
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 2: // rename folder/object
|
||||
dfm.window.html($('#dfm_templateRenameFolder').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target.strip().split('/').pop());
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 3: // copy folder/object
|
||||
dfm.window.html($('#dfm_templateCopyFolder').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
|
||||
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
|
||||
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
|
||||
dfm.height = 630;
|
||||
break;
|
||||
case 4: // move folder/object (rsync)
|
||||
case 5: // move folder/object (mv)
|
||||
dfm.window.html($('#dfm_templateMoveFolder').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
|
||||
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
|
||||
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
|
||||
dfm.height = 630;
|
||||
break;
|
||||
case 6: // delete file
|
||||
dfm.window.html($('#dfm_templateDeleteFile').html());
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 8: // copy file
|
||||
dfm.window.html($('#dfm_templateCopyFile').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
|
||||
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true : false);
|
||||
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
|
||||
dfm.height = 630;
|
||||
break;
|
||||
case 9: // move file (rsync)
|
||||
case 10: // move file (mv)
|
||||
dfm.window.html($('#dfm_templateMoveFile').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
|
||||
dfm.window.find('#dfm_sparse').prop('checked',dfm_read.sparse ? true :false);
|
||||
dfm.window.find('#dfm_exist').prop('checked',dfm_read.exist ? false : true);
|
||||
dfm.height = 630;
|
||||
break;
|
||||
case 11: // change owner
|
||||
dfm.window.html($('#dfm_templateChangeOwner').html());
|
||||
dfm.window.find('#dfm_target').prop('disabled',true);
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 12: // change permission
|
||||
dfm.window.html($('#dfm_templateChangePermission').html());
|
||||
dfm.window.find('#dfm_owner').prop('disabled',true);
|
||||
dfm.window.find('#dfm_group').prop('disabled',true);
|
||||
dfm.window.find('#dfm_other').prop('disabled',true);
|
||||
dfm.height = 330;
|
||||
break;
|
||||
case 15: // search
|
||||
dfm.window.html($('#dfm_templateSearch').html());
|
||||
dfm.window.find('#dfm_target').val(dfm_read.target).prop('disabled',true);
|
||||
dfm.window.find('.dfm_loc').html(' ').css({'line-height':'normal'});
|
||||
dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
|
||||
dfm.height = 630;
|
||||
break;
|
||||
}
|
||||
dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[dfm_read.action],dfm_source.length));
|
||||
dfm_createSource(dfm_source);
|
||||
dfm.window.find('#dfm_sparse').prop('disabled',true);
|
||||
dfm.window.find('#dfm_exist').prop('disabled',true);
|
||||
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
|
||||
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
|
||||
dfm.window.dialog({
|
||||
dialogClass: 'ui-dfm',
|
||||
autoOpen: open||dfm.dialog,
|
||||
title: dfm_read.title,
|
||||
resizable: false,
|
||||
width: 900,
|
||||
height: dfm.height,
|
||||
modal: true,
|
||||
buttons: {
|
||||
"_(Start)_": function(){
|
||||
if (dfm_read.action==15) {
|
||||
var dfm_target = dfm.window.find('#dfm_target').val();
|
||||
dfm.window.find('.dfm_loc').html(' ');
|
||||
dfm.window.find('.dfm_text').html("_(Running)_...");
|
||||
dfm_footer('hide');
|
||||
dfm_fileManager('start');
|
||||
$.post('/webGui/include/Control.php',{mode:'file',action:15,title:encodeURIComponent(dfm_read.title),source:encodeURIComponent(dfm_read.source),target:encodeURIComponent(dfm_target),hdlink:'',sparse:'',exist:'',zfs:''});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
"_(Queue)_": function(){
|
||||
return;
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
dfm_fileManager('stop');
|
||||
dfm.window.dialog('destroy');
|
||||
$.post('/webGui/include/Control.php',{mode:'file',action:99},function(){<?if ($dfm['browser']):?>setTimeout(loadList,500);<?endif;?>});
|
||||
}
|
||||
}
|
||||
});
|
||||
dfm_close_button();
|
||||
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',true);
|
||||
setTimeout(function(){$('.ui-dfm .ui-dialog-buttonset button:eq(2)').focus();});
|
||||
if (open||dfm.dialog) dfm_footer('hide'); else dfm_footer('show');
|
||||
}
|
||||
function dfm_openDialog(open) {
|
||||
$.post('/webGui/include/Control.php',{mode:'read'},function(data){
|
||||
if (data) {
|
||||
dfm_read = JSON.parse(data);
|
||||
dfm_read.action = parseInt(dfm_read.action);
|
||||
}
|
||||
dfm_makeDialog(open);
|
||||
});
|
||||
}
|
||||
var nchan_filemanager = new NchanSubscriber('/sub/filemanager',{subscriber:'websocket'});
|
||||
nchan_filemanager.on('message', function(msg) {
|
||||
let data = $.parseJSON(msg);
|
||||
if (data.error) {
|
||||
dfm_fileManager('stop');
|
||||
dfm.window.find('.dfm_text').addClass('orange-text').html(data.error);
|
||||
dfm.window.find('#dfm_target').prop('disabled',false);
|
||||
dfm.window.find('#dfm_sparse').prop('disabled',false);
|
||||
dfm.window.find('#dfm_exist').prop('disabled',false);
|
||||
dfm.window.find('#dfm_owner').prop('disabled',false);
|
||||
dfm.window.find('#dfm_group').prop('disabled',false);
|
||||
dfm.window.find('#dfm_other').prop('disabled',false);
|
||||
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',false);
|
||||
} else {
|
||||
let cat = dfm_showProgress(data.status);
|
||||
if (data.done==1) {
|
||||
setTimeout(function(){$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
|
||||
switch (parseInt(queue)) {
|
||||
case 0:
|
||||
dfm_fileManager('stop');
|
||||
dfm.window.dialog('destroy');
|
||||
<?if ($dfm['browser']):?>
|
||||
setTimeout(loadList);
|
||||
<?endif;?>
|
||||
break;
|
||||
case 1:
|
||||
<?if ($dfm['browser']):?>
|
||||
$('.dfm_control.jobs').prop('disabled',true);
|
||||
<?endif;?>
|
||||
$.removeCookie('dfm_control.jobs');
|
||||
case 2:
|
||||
dfm_openDialog();
|
||||
break;
|
||||
}
|
||||
})});
|
||||
} else if (data.done==2) {
|
||||
nchan_filemanager.stop();
|
||||
dfm.running = false;
|
||||
dfm.window.find('#dfm_target').prop('disabled',false).focus();
|
||||
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',false);
|
||||
if (cat==0) dfm.window.find('.dfm_text').html("_(No results found)_");
|
||||
if ($('#user-notice:visible')) dfm_done();
|
||||
}
|
||||
}
|
||||
});
|
||||
<?if ($dfm['running']):?>
|
||||
$(function(){
|
||||
dfm_openDialog();
|
||||
dfm_fileManager('start');
|
||||
});
|
||||
<?endif;?>
|
||||
</script>
|
||||
@@ -22,6 +22,14 @@ function makeList($list) {
|
||||
function sharename($share) {
|
||||
return basename($share,'.cfg');
|
||||
}
|
||||
$subpools = array( "special", "logs", "dedup", "cache", "spares");
|
||||
function isSubpool($name) {
|
||||
global $subpools;
|
||||
// pool name ending in any of these => zfs subpool
|
||||
$tildaPosition = strpos($name, '~');
|
||||
$subpool = ($tildaPosition!==false) ? substr($name, $tildaPosition+1) : false;
|
||||
return ($subpool!==false && in_array($subpool, $subpools)) ? $subpool : false;
|
||||
}
|
||||
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
@@ -31,7 +39,7 @@ table.divider{margin-top:20px}
|
||||
</style>
|
||||
<script>
|
||||
function validate(poolname) {
|
||||
var valid = /^[a-z]([a-z0-9_-]*[a-z_-])*$/;
|
||||
var valid = /^[a-z]([a-z0-9~._-]*[a-z_-])*$/;
|
||||
var reserved = [<?=makeList(explode(',',_var($var,'reservedNames')))?>];
|
||||
var shares = [<?=makeList(array_map('sharename',glob('boot/config/shares/*.cfg',GLOB_NOSORT)))?>];
|
||||
var pools = [<?=makeList($pools)?>];
|
||||
@@ -82,6 +90,59 @@ function addPoolPopup() {
|
||||
$(".ui-widget-content").css({'background':'<?=$bgcolor?>'});
|
||||
$(".ui-button-text").css({'padding':'0px 5px'});
|
||||
}
|
||||
function removeOption(inputString,value) {
|
||||
// Define a regular expression to match <option>...</option> substrings
|
||||
const optionPattern = /<option .*?<\/option>/g;
|
||||
// Replace all matching substrings that contain "value" with an empty string
|
||||
const result = inputString.replace(optionPattern, (match) => {
|
||||
if (match.includes(value)) {
|
||||
return ''; // Remove the entire substring
|
||||
} else {
|
||||
return match; // Keep the substring as is
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function addSubpoolPopup(poolname,currentsubpools) {
|
||||
var popup = $('#dialogAddSubpool');
|
||||
// Load popup with the template info
|
||||
popup.html($("#templatePopupSubpool").html());
|
||||
// Remove the options specifed by currentsubpools
|
||||
if (currentsubpools.trim().length !== 0) {
|
||||
var subpools = currentsubpools.split(',');
|
||||
subpools.forEach(function(subpool) {
|
||||
popup.html(function(index, oldHtml) {
|
||||
return removeOption(oldHtml, subpool);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Start Dialog section
|
||||
popup.dialog({
|
||||
title: "_(Add ZFS Subpool)_",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
modal: true,
|
||||
show : {effect:'fade', duration:250},
|
||||
hide : {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
"_(Add)_": function() {
|
||||
subpool=$(this).find('select[name="subpool"]').val();
|
||||
$(this).find('input[name="poolName"]').val(poolname + "~" + subpool);
|
||||
$(this).find('form').submit();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
|
||||
$('.ui-dialog .ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
|
||||
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$(".ui-widget-content").css({'background':'<?=$bgcolor?>'});
|
||||
$(".ui-button-text").css({'padding':'0px 5px'});
|
||||
}
|
||||
|
||||
<?if (_var($var,'fsState')=="Started"):?>
|
||||
$('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
|
||||
@@ -92,7 +153,11 @@ $('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
|
||||
<?foreach ($pools as $pool):?>
|
||||
<?if (isset($disks[$pool]['devices']) or _var($var,'fsState')=="Stopped"):?>
|
||||
<table class="disk_status wide<?=$i?' divider':''?>">
|
||||
<?if (isSubpool($pool)):?>
|
||||
<thead></thead>
|
||||
<?else:?>
|
||||
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
|
||||
<?endif;?>
|
||||
<tbody id="pool_device<?=$i++?>">
|
||||
<?foreach (cache_filter($disks) as $disk) if (prefix($disk['name'])==$pool) echo "<tr><td colspan='11'> </td></tr>"?>
|
||||
</tbody>
|
||||
@@ -109,6 +174,30 @@ $('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
|
||||
_(Name)_:
|
||||
: <input type="text" name="poolName" maxlength="40" value="<?=count($pools)==0?'cache':''?>">
|
||||
|
||||
_(Slots)_:
|
||||
: <select name="poolSlots">
|
||||
<?for ($n=1; $n<=_var($var,'MAX_CACHESZ',0); $n++):?>
|
||||
<?=mk_option(1,$n,$n)?>
|
||||
<?endfor;?>
|
||||
</select>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="dialogAddSubpool" style="display:none"></div>
|
||||
<div id="templatePopupSubpool" style="display:none">
|
||||
<form markdown="1" method="POST" action="/update.htm" target="progressFrame">
|
||||
<input type="hidden" name="changeSlots" value="apply">
|
||||
<input type="hidden" name="poolName" value="">
|
||||
_(Name)_:
|
||||
: <select name="subpool">
|
||||
<?=mk_option("","special","special - Special Allocation Class")?>
|
||||
<?=mk_option("","logs","logs - ZFS Intent Log")?>
|
||||
<?=mk_option("","dedup","dedup - Deduplication Tables")?>
|
||||
<?=mk_option("","cache","cache - Cache Devices")?>
|
||||
<?=mk_option("","spares","spares - Hot Spares")?>
|
||||
</select>
|
||||
|
||||
_(Slots)_:
|
||||
: <select name="poolSlots">
|
||||
<?for ($n=1; $n<=_var($var,'MAX_CACHESZ',0); $n++):?>
|
||||
|
||||
@@ -19,6 +19,8 @@ Tag="trophy"
|
||||
|
||||
**Community Applications** Copyright © 2015-2023, Andrew Zawadzki
|
||||
|
||||
**GUI Search** Copyright © 2021-2023, Andrew Zawadzki
|
||||
|
||||
The Software comprising the Unraid webGui, which is all files within this repository **except** for
|
||||
files listed below, is licensed under GPL version 2.
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ exec("sed -ri 's/^\.logLine\{color:#......;/.logLine{color:$fgcolor;/' $docroot/
|
||||
|
||||
exec("/etc/rc.d/rc.docker status >/dev/null",$dummy,$dockerd);
|
||||
exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd);
|
||||
$domain_cfg = parse_ini_file("/boot/config/domain.cfg");
|
||||
$dockerd = $dockerd==0;
|
||||
$libvirtd = $libvirtd==0;
|
||||
$apcupsd = file_exists('/var/run/apcupsd.pid');
|
||||
@@ -181,6 +182,7 @@ div.last{padding-bottom:12px}
|
||||
div.leftside{float:left;width:66%}
|
||||
div.rightside{float:right;margin:0;text-align:center}
|
||||
div[id$=chart]{margin:-12px 8px -24px -18px}
|
||||
div.template,div#dialogWindow,input#upload{display:none}
|
||||
span.green,span.red,span.orange{padding-left:0}
|
||||
span.ctrl{float:right;margin-top:0;margin-right:10px}
|
||||
span.ctrl span{font-size:2rem!important}
|
||||
@@ -814,6 +816,63 @@ var netchart = new ApexCharts(document.querySelector('#netchart'), options_net);
|
||||
if ($.cookie('port_select')!=null && !ports.includes($.cookie('port_select'))) $.removeCookie('port_select');
|
||||
var port_select = $.cookie('port_select')||ports[0];
|
||||
|
||||
function selectsnapshot(uuid, name ,snaps, opt, getlist){
|
||||
var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow2");
|
||||
box.html($("#templatesnapshot"+opt).html());
|
||||
var height = 200;
|
||||
const Capopt = opt.charAt(0).toUpperCase() + opt.slice(1);
|
||||
var optiontext = Capopt + " Snapshot";
|
||||
box.find('#VMName').html(name);
|
||||
box.find('#targetsnap').val(snaps);
|
||||
box.find('#targetsnapl').html(snaps);
|
||||
if (getlist) {
|
||||
var only = (opt == "remove") ? 0 : 1;
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", {action:"snap-images", uuid:uuid, snapshotname:snaps, only:only}, function(data){if (data.html) box.find('#targetsnapimages').html(data.html);},'json');
|
||||
}
|
||||
document.getElementById("targetsnapfspc").checked = true;
|
||||
box.dialog({
|
||||
title: "_("+optiontext+ ")_",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
"_(Proceed)_": function(){
|
||||
var target = box.find('#targetsnap');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
if (!target) {errorTarget(); return;}
|
||||
} else target = '';
|
||||
var remove = 'yes';
|
||||
var removemeta = 'yes';
|
||||
var keep = 'yes';
|
||||
var free = 'yes';
|
||||
var desc = '';
|
||||
box.find('#targetsnap').prop('disabled',true);
|
||||
if (opt == "revert") {
|
||||
remove = box.find('#targetsnaprmv').prop('checked') ? 'yes' : 'no';
|
||||
removemeta = box.find('#targetsnaprmvmeta').prop('checked') ? 'yes' : 'no';
|
||||
keep = box.find('#targetsnapkeep').prop('checked') ? 'yes' : 'no';
|
||||
}
|
||||
if (opt == "create") {
|
||||
free = box.find('#targetsnapfspc').prop('checked') ? 'yes' : 'no';
|
||||
desc = box.find("#targetsnapdesc").prop('value');
|
||||
}
|
||||
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid, snapshotname:target, remove:remove, free:free, desc:desc}, "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function initCharts(clear) {
|
||||
$.post('/webGui/include/InitCharts.php',{cmd:'get'},function(data) {
|
||||
data = JSON.parse(data);
|
||||
@@ -1504,4 +1563,104 @@ $(function() {
|
||||
$.post('/webGui/include/InitCharts.php',{cmd:'set',data:JSON.stringify(data)});
|
||||
});
|
||||
});
|
||||
function dialogStyle() {
|
||||
$('.ui-dialog-titlebar-close').css({'background':'transparent','border':'none','font-size':'1.8rem','margin-top':'-14px','margin-right':'-18px'}).html('<i class="fa fa-times"></i>').prop('title');
|
||||
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
|
||||
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-button-text').css({'padding':'0px 5px'});
|
||||
}
|
||||
function VMClone(uuid, name){
|
||||
//var root = <?= '"'.$domain_cfg["MEDIADIR"].'"';?>;
|
||||
var match= ".iso";
|
||||
var box = $("#dialogWindow");
|
||||
var height = 200;
|
||||
box.html($("#templateClone").html());
|
||||
box.find('#VMBeingCloned').html(name).change() ;
|
||||
box.find('#target').val(name + "_clone") ;
|
||||
document.getElementById("Free").checked = true ;
|
||||
document.getElementById("Overwrite").checked = true ;
|
||||
var Cancel = _("Cancel") ;
|
||||
box.dialog({
|
||||
title: "VM Clone",
|
||||
resizable: false,
|
||||
width: 600,
|
||||
height: 500,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration:250},
|
||||
hide: {effect:'fade', duration:250},
|
||||
buttons: {
|
||||
"_(Clone)_": function(){
|
||||
var target = box.find('#target');
|
||||
if (target.length) {
|
||||
target = target.val();
|
||||
//if (!target ) {errorTarget(); return;}
|
||||
} else target = '';
|
||||
var clone = box.find("#target").prop('value');
|
||||
var start = box.find('#Start').prop('checked') ? 'yes' : 'no';
|
||||
var edit = box.find('#Edit').prop('checked') ? 'yes' : 'no';
|
||||
var overwrite = box.find('#Overwrite').prop('checked') ? 'yes' : 'no';
|
||||
var free = box.find('#Free').prop('checked') ? 'yes' : 'no';
|
||||
var scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free}));
|
||||
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
"_(Cancel)_": function(){
|
||||
box.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogStyle();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="dialogWindow"></div>
|
||||
<div markdown="1" id="templateClone" class="template">
|
||||
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=1600">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="referrer" content="same-origin">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
|
||||
</head>
|
||||
<body>
|
||||
<br>
|
||||
<table>
|
||||
<tr><td>_(VM Being Cloned)_:</td>
|
||||
<td><span id="VMBeingCloned"></span></td></tr>
|
||||
|
||||
<tr><td>_(New VM)_:</td>
|
||||
<td><input type="text" id="target" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
|
||||
|
||||
<tr><td>_(Overwrite)_:</td>
|
||||
<td><input type="checkbox" id="Overwrite" value="" ></td></tr>
|
||||
|
||||
<tr hidden><td>_(Start Cloned VM)_:</td>
|
||||
<td><input type="checkbox" id="Start" value="" ></td></tr>
|
||||
|
||||
<tr hidden><td>_(Edit VM after clone)_:</td>
|
||||
<td><input type="checkbox" id="Edit" value="" ></td></tr>
|
||||
|
||||
<tr><td>_(Check Free Space)_:</td>
|
||||
<td><input type="checkbox" id="Free" value="" ></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
|
||||
<div id="dialogWindow2"></div>
|
||||
<div markdown="1" id="templatesnapshotcreate" class="template">
|
||||
<table id='snapshot'>
|
||||
<br><br>
|
||||
<tr><td> _(VM Name)_:</td><td>
|
||||
<label id="VMName"></label></td></tr>
|
||||
<tr><td>_(Snapshot Name)_:</td><td>
|
||||
<input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">
|
||||
_(Check free space)_:
|
||||
<input type="checkbox" id="targetsnapfspc" checked></td></tr>
|
||||
<tr><td>_(Description )_:</td><td>
|
||||
<input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
Regular → Executable
+66
-32
@@ -80,6 +80,13 @@ function maintenance_mode() {
|
||||
global $var;
|
||||
return _var($var,'fsState')=="Started" && _var($var,'startMode')=="Maintenance" && _var($disk,'luksState',0)<=1;
|
||||
}
|
||||
function isSubpool($name) {
|
||||
// pool name ending in any of these => zfs subpool
|
||||
$subpools = array( "special", "logs", "dedup", "cache", "spares");
|
||||
$tildaPosition = strpos($name, '~');
|
||||
$subpool = ($tildaPosition!==false) ? substr($name, $tildaPosition+1) : false;
|
||||
return ($subpool!==false && in_array($subpool, $subpools)) ? $subpool : false;
|
||||
}
|
||||
function isPool($name) {
|
||||
global $pools;
|
||||
return in_array($name,$pools);
|
||||
@@ -220,8 +227,8 @@ function selectDiskFsWidth(num_devices,selected_width) {
|
||||
} else {
|
||||
var width, min_width;
|
||||
if ($('#diskFsProfileZFS').val() == 'raidz1') min_width = 3;
|
||||
else if ($('#diskFsProfileZFS').val() == 'raidz2') min_width = 4;
|
||||
else if ($('#diskFsProfileZFS').val() == 'raidz3') min_width = 5;
|
||||
else if ($('#diskFsProfileZFS').val() == 'raidz2') min_width = 3;
|
||||
else if ($('#diskFsProfileZFS').val() == 'raidz3') min_width = 4;
|
||||
for (width=min_width; width<=num_devices; width++) {
|
||||
if ((num_devices % width) == 0) {
|
||||
var groups = num_devices / width;
|
||||
@@ -235,7 +242,7 @@ function selectDiskFsWidth(num_devices,selected_width) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function selectDiskFsProfile(num_devices, width, init) {
|
||||
function selectDiskFsProfile(num_slots, width, init) {
|
||||
var t = init ? null : 'slow';
|
||||
if (($('#diskFsType').val()||'').indexOf('auto') != -1) {
|
||||
$('#diskFsProfileBTRFS').prop('disabled',true).hide();
|
||||
@@ -260,7 +267,7 @@ function selectDiskFsProfile(num_devices, width, init) {
|
||||
}
|
||||
$('#diskFsProfileZFS').show();
|
||||
$('#diskFsWidthZFS').show();
|
||||
selectDiskFsWidth(num_devices, width);
|
||||
selectDiskFsWidth(num_slots, width);
|
||||
$('#compression').show(t);
|
||||
<?if (diskType('Cache')):?>
|
||||
$('#autotrim').show(t);
|
||||
@@ -452,7 +459,7 @@ function updateMode(form,mode) {
|
||||
$(form).find('input[name="#arg[3]"]').val(mode);
|
||||
}
|
||||
function validate(poolname) {
|
||||
var valid = /^[a-z_]([a-z0-9_-]*[a-z_])*$/;
|
||||
var valid = /^[a-z_]([a-z0-9~._-]*[a-z_])*$/;
|
||||
var reserved = [<?=makeList(explode(',',_var($var,'reservedNames')))?>];
|
||||
var shares = [<?=makeList(array_map('sharename',glob('boot/config/shares/*.cfg',GLOB_NOSORT)))?>];
|
||||
var pools = [<?=makeList($pools)?>];
|
||||
@@ -537,7 +544,7 @@ function eraseDisk(name) {
|
||||
</script>
|
||||
|
||||
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="setFloor()">
|
||||
<?if (_var($var,'fsState')=="Stopped" && isPool($name)):?>
|
||||
<?if (_var($var,'fsState')=="Stopped" && isPool($name) && !isSubpool($name)):?>
|
||||
_(Name)_:
|
||||
: <a onclick="renamePoolPopup()" style="cursor:pointer" title="_(Rename Pool)_"><?=$name?></a>
|
||||
|
||||
@@ -556,7 +563,7 @@ _(Identification)_:
|
||||
|
||||
<?endif;?>
|
||||
<?if (!$unassigned):?>
|
||||
<?if (diskType('Data') || (diskType('Cache') && isPool(_var($disk,'name')))):?>
|
||||
<?if (diskType('Data') || (diskType('Cache') && isPool($name) && !isSubpool($name))):?>
|
||||
_(Comments)_:
|
||||
: <input type="text" name="diskComment.<?=_var($disk,'idx',0)?>" maxlength="256" value="<?=htmlspecialchars(_var($disk,'comment'))?>">
|
||||
|
||||
@@ -569,11 +576,13 @@ _(Partition size)_:
|
||||
_(Partition format)_:
|
||||
: <?=_(_var($disk,'format'))?>
|
||||
|
||||
<?endif;?>
|
||||
<?if (_var($var,'spinupGroups')=="yes" && diskType('Data','Parity')):?>
|
||||
_(Spinup group(s))_:
|
||||
: <input type="text" name="diskSpinupGroup.<?=_var($disk,'idx',0)?>" maxlength="256" value="<?=_var($disk,'spinupGroup')?>">
|
||||
|
||||
<?endif;?>
|
||||
<?if (diskType('Data') || isPool($tag)):?>
|
||||
_(Spin down delay)_:
|
||||
: <select name="diskSpindownDelay.<?=_var($disk,'idx',0)?>">
|
||||
<?=mk_option(_var($disk,'spindownDelay'), "-1", _('Use default'))?>
|
||||
@@ -591,14 +600,12 @@ _(Spin down delay)_:
|
||||
<?=mk_option(_var($disk,'spindownDelay'), "8", "8 "._('hours'))?>
|
||||
<?=mk_option(_var($disk,'spindownDelay'), "9", "9 "._('hours'))?>
|
||||
</select><span id="smart_selftest" class='orange-text'></span>
|
||||
<?endif;?>
|
||||
|
||||
<?if (diskType('Data') || isPool($tag)):?>
|
||||
_(File system status)_:
|
||||
: <?=_(_var($disk,'fsStatus'))?>
|
||||
|
||||
<?$disabled = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid') ? "disabled" : ""?>
|
||||
<?if (diskType('Data') || _var($disk,'slots',0)==1):?>
|
||||
<?$disabled = (_var($var,'fsState')=="Stopped" && _var($disk,'uuid')) || (_var($var,'fsState')=="Started" && _var($disk,'fsStatus')=='Mounted') ? "disabled" : ""?>
|
||||
<?if (diskType('Data') || (!isSubpool($name) && _var($disk,'slots',0)==1)):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
|
||||
@@ -614,9 +621,9 @@ _(File system type)_:
|
||||
|
||||
:info_file_system_help:
|
||||
|
||||
<?elseif (_var($disk,'slots',0)>1):?>
|
||||
<?elseif (!isSubpool($name) && _var($disk,'slots',0)>1):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
<?=mk_option(_var($disk,'fsType'), "btrfs", _('btrfs'))?>
|
||||
@@ -625,26 +632,55 @@ _(File system type)_:
|
||||
</select>
|
||||
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsProfile'),"single", _('single'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
|
||||
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
|
||||
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
|
||||
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
|
||||
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
|
||||
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
|
||||
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
|
||||
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
|
||||
</select>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
|
||||
<?if (_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
<?if ((_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
|
||||
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
|
||||
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
|
||||
<?if (_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
<?if ((_var($disk,'slots',0)%2)==0 || (_var($disk,'slots',0)%3)==0 || (_var($disk,'slots',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
|
||||
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
|
||||
<?if (_var($disk,'slots',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
|
||||
<?if (_var($disk,'slots',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
|
||||
</select>
|
||||
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
</select>
|
||||
<?elseif (isSubpool($name)=="special" || isSubpool($name)=="logs" || isSubpool($name)=="dedup"):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
</select>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
<?if ((_var($disk,'slots',0)%2)==0 || (_var($disk,'slots',0)%3)==0 || (_var($disk,'slots',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
|
||||
</select>
|
||||
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
</select>
|
||||
<?elseif (isSubpool($name)=="cache"):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
</select>
|
||||
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsWidth(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?if (_var($disk,'slots',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
|
||||
<?if (_var($disk,'slots',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
|
||||
</select>
|
||||
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
|
||||
</select>
|
||||
<?elseif (isSubpool($name)=="spares"):?>
|
||||
_(File system type)_:
|
||||
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'slots',0)?>,0)" <?=$disabled?>>
|
||||
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
|
||||
</select>
|
||||
<?endif;?>
|
||||
|
||||
<?if (isSubpool($name)===false):?>
|
||||
<div markdown="1" id="compression" style="display:none">
|
||||
_(Compression)_:
|
||||
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
|
||||
@@ -693,6 +729,7 @@ _(Critical disk utilization threshold)_ (%):
|
||||
|
||||
:info_critical_utilization_help:
|
||||
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
|
||||
: <input type="submit" name="changeDisk" value="_(Apply)_" disabled><input type="button" id="doneButton" value="_(Done)_" onclick="done()">
|
||||
@@ -973,7 +1010,7 @@ _(btrfs check status)_:
|
||||
<?endif;?>
|
||||
</form>
|
||||
<?endif;?>
|
||||
<?if (fsType('zfs')):?>
|
||||
<?if (fsType('zfs') && !isSubpool($name)):?>
|
||||
<div class="title nocontrol"><span class="left"><i class="title fa fa-info"></i>_(Pool Status)_</span></div>
|
||||
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareFS(this,'zfs-scrub-<?=$tag?>','<?=$tag?>')">
|
||||
<?if (_var($disk,'fsStatus')=="Mounted"):?>
|
||||
@@ -1303,10 +1340,7 @@ $(function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
var groups = <?=_var($disk,'fsGroups',0)?:0?>;
|
||||
var width = <?=_var($disk,'fsWidth',0)?:0?>;
|
||||
var devices = (groups==0 || width==0) ? <?=_var($disk,'devices',0)?:0?> : groups * width;
|
||||
selectDiskFsProfile(devices,width,true);
|
||||
selectDiskFsProfile(<?=_var($disk,'slots',0)?>,true);
|
||||
<?if (fsType('btrfs')):?>
|
||||
presetBTRFS(document.balance_schedule,'#balance-hour');
|
||||
presetBTRFS(document.scrub_schedule,'#scrub-hour');
|
||||
|
||||
@@ -19,6 +19,11 @@ Tag="icon-disk"
|
||||
require_once "$docroot/webGui/include/Preselect.php";
|
||||
$events = explode('|',$var['smEvents'] ?? $numbers);
|
||||
|
||||
$reply = '/var/tmp/luks.reply';
|
||||
$keyfile = is_file($var['luksKeyfile']);
|
||||
$encrypt = false;
|
||||
foreach ($disks as $disk) if (isset($disk['fsType']) && strncmp($disk['fsType'],'luks:',5)===0) $encrypt = true;
|
||||
|
||||
function displayTemp($temp) {
|
||||
global $display;
|
||||
return (is_numeric($temp) && _var($display,'unit')=='F') ? round(9/5*$temp)+32 : $temp;
|
||||
@@ -27,7 +32,11 @@ function displayTemp($temp) {
|
||||
<style>
|
||||
span.code{display:inline-block;width:186px}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function base64(str) {
|
||||
return window.btoa(unescape(encodeURIComponent(str)));
|
||||
}
|
||||
function doDispatch(form) {
|
||||
var fields = {};
|
||||
<?if (_var($display,'unit')=='F'):?>
|
||||
@@ -55,11 +64,66 @@ function prepareDiskSettings(form) {
|
||||
function setIndex(form) {
|
||||
form.smIndex.value = form.smType.selectedIndex;
|
||||
}
|
||||
function prepareForm(form) {
|
||||
<?if (!$keyfile):?>
|
||||
form.oldluks.value = base64(form.oldtext.value);
|
||||
form.oldtext.disabled = true;
|
||||
form.oldfile.disabled = true;
|
||||
<?endif;?>
|
||||
form.newluks.value = base64(form.newtext.value);
|
||||
form.newtext.disabled = true;
|
||||
form.newcopy.disabled = true;
|
||||
form.newfile.disabled = true;
|
||||
}
|
||||
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) {
|
||||
$('div#oldfile').hide('slow');
|
||||
$('div#oldtext').show('slow');
|
||||
} else {
|
||||
$('div#newfile').hide('slow');
|
||||
$('div#newtext').show('slow');
|
||||
$('input[name="newkey"]').prop('disabled',$('input[name="newtext"]').val()=='' || $('input[name="newtext"]').val()!=$('input[name="newcopy"]').val());
|
||||
}
|
||||
} else if (val=='file') {
|
||||
if (old==true) {
|
||||
$('div#oldtext').hide('slow');
|
||||
$('div#oldfile').show('slow');
|
||||
} else {
|
||||
$('div#newtext').hide('slow');
|
||||
$('div#newfile').show('slow');
|
||||
$('input[name="newkey"]').prop('disabled',$('input[name="newfile"]').val()=='');
|
||||
}
|
||||
}
|
||||
}
|
||||
function showInput(show,old) {
|
||||
if (old==true) {
|
||||
var input = $('input[name="oldtext"]');
|
||||
} else {
|
||||
var input = $('input[name="newtext"],input[name="newcopy"]');
|
||||
}
|
||||
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);
|
||||
}
|
||||
<?if (is_file($reply)):?>
|
||||
<?[$text,$type] = explode("\0",file_get_contents($reply)); unlink($reply);?>
|
||||
$(function() {
|
||||
swal({title:"_(Encryption Key Update)_",text:"<?=$text?>",html:true,type:"<?=$type?>",confirmButtonText:"_(Ok)_"});
|
||||
});
|
||||
<?endif;?>
|
||||
</script>
|
||||
|
||||
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="doDispatch(this)">
|
||||
_(Enable auto start)_:
|
||||
: <select name="startArray" size="1">
|
||||
: <select name="startArray">
|
||||
<?=mk_option($var['startArray'], "no", _('No'))?>
|
||||
<?=mk_option($var['startArray'], "yes", _('Yes'))?>
|
||||
</select>
|
||||
@@ -67,7 +131,7 @@ _(Enable auto start)_:
|
||||
:disk_enable_autostart_help:
|
||||
|
||||
_(Default spin down delay)_:
|
||||
: <select name="spindownDelay" size="1">
|
||||
: <select name="spindownDelay">
|
||||
<?=mk_option($var['spindownDelay'], "0", _('Never'))?>
|
||||
<?=mk_option($var['spindownDelay'], "15", "15 "._('minutes'))?>
|
||||
<?=mk_option($var['spindownDelay'], "30", "30 "._('minutes'))?>
|
||||
@@ -86,7 +150,7 @@ _(Default spin down delay)_:
|
||||
:disk_spindown_delay_help:
|
||||
|
||||
_(Enable spinup groups)_:
|
||||
: <select name="spinupGroups" size="1">
|
||||
: <select name="spinupGroups">
|
||||
<?=mk_option($var['spinupGroups'], "no", _('No'))?>
|
||||
<?=mk_option($var['spinupGroups'], "yes", _('Yes'))?>
|
||||
</select>
|
||||
@@ -94,7 +158,7 @@ _(Enable spinup groups)_:
|
||||
:disk_spinup_groups_help:
|
||||
|
||||
_(Default file system)_:
|
||||
: <select name="defaultFsType" size="1">
|
||||
: <select name="defaultFsType">
|
||||
<?=mk_option($var['defaultFsType'], "xfs", _('xfs'));?>
|
||||
<?=mk_option($var['defaultFsType'], "zfs", _('zfs'));?>
|
||||
<?=mk_option($var['defaultFsType'], "btrfs", _('btrfs'));?>
|
||||
@@ -118,7 +182,7 @@ _(Tunable (poll_attributes))_:
|
||||
:disk_tunable_poll_attributes_help:
|
||||
|
||||
_(Tunable (enable NCQ))_:
|
||||
: <select name="queueDepth" size="1">
|
||||
: <select name="queueDepth">
|
||||
<?=mk_option($var['queueDepth'], "auto", _('Auto'))?>
|
||||
<?=mk_option($var['queueDepth'], "1", _('No'))?>
|
||||
</select>
|
||||
@@ -131,7 +195,7 @@ _(Tunable (nr_requests))_:
|
||||
:disk_tunable_nr_requests_help:
|
||||
|
||||
_(Tunable (scheduler))_:
|
||||
: <select name="md_scheduler" size="1">
|
||||
: <select name="md_scheduler">
|
||||
<?=mk_option($var['md_scheduler'], "auto", _('Auto'))?>
|
||||
<?=mk_option($var['md_scheduler'], "mq-deadline", _('mq-deadline'))?>
|
||||
<?=mk_option($var['md_scheduler'], "kyber", _('kyber'))?>
|
||||
@@ -157,7 +221,7 @@ _(Tunable (md_sync_limit))_:
|
||||
:disk_tunable_md_sync_limit_help:
|
||||
|
||||
_(Tunable (md_write_method))_:
|
||||
: <select name="md_write_method" size="1">
|
||||
: <select name="md_write_method">
|
||||
<?=mk_option($var['md_write_method'], "auto", _('Auto'))?>
|
||||
<?=mk_option($var['md_write_method'], "0", _('read/modify/write'))?>
|
||||
<?=mk_option($var['md_write_method'], "1", _('reconstruct write'))?>
|
||||
@@ -189,8 +253,62 @@ _(Default critical disk temperature threshold)_ (°<?=_var($display,'unit','C
|
||||
: <input type="submit" name="changeDisk" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
|
||||
<div class="title"><span class="left"><i class="title fa fa-plus-square"></i>_(Global SMART Settings)_</span></div>
|
||||
<?if ($encrypt && $var['fsState']=='Started'):?>
|
||||
<div class="title"><span class="left"><i class="title fa fa-key"></i>_(Change Encryption Key)_</span></div>
|
||||
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareForm(this)">
|
||||
<input type="hidden" name="#file" value="">
|
||||
<input type="hidden" name="#include" value="/webGui/include/update.encryption.php">
|
||||
<input type="hidden" name="#reply" value="<?=$reply?>">
|
||||
<input type="hidden" name="newdata" value="">
|
||||
<input type="hidden" name="newluks" value="">
|
||||
<?if (!$keyfile):?>
|
||||
<input type="hidden" name="olddata" value="">
|
||||
<input type="hidden" name="oldluks" value="">
|
||||
<?endif;?>
|
||||
_(Existing encryption key)_:
|
||||
: <select name="oldinput" class="lock" onchange='selectInput(this.value,true)' <?=$keyfile?'disabled':''?>>
|
||||
<?=mk_option(1,'text',_('Passphrase'))?>
|
||||
<?=mk_option(1,'file',_('Keyfile'),$keyfile ? 'selected' : '')?>
|
||||
</select><br>
|
||||
|
||||
<?if (!$keyfile):?>
|
||||
<div markdown="1" id="oldtext">
|
||||
_(Enter existing passphrase)_:
|
||||
: <input type="password" name="oldtext" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false"><input name="showPass" type="checkbox" class="lock" onchange="showInput(this.checked,true)">_(show passphrase)_
|
||||
|
||||
</div>
|
||||
<div markdown="1" id="oldfile" style="display:none">
|
||||
_(Select existing keyfile)_:
|
||||
: <input type="file" name="oldfile" class="lock" onchange="getFileContent(event,this.form,'olddata')">
|
||||
|
||||
</div>
|
||||
<?endif;?>
|
||||
|
||||
_(Change encryption key)_:
|
||||
: <select name="newinput" class="lock" onchange='selectInput(this.value,false)'>
|
||||
<?=mk_option(1,'text',_('Passphrase'))?>
|
||||
<?=mk_option(1,'file',_('Keyfile'))?>
|
||||
</select><br>
|
||||
|
||||
<div markdown="1" id="newtext">
|
||||
_(Type new passphrase)_:
|
||||
: <input type="password" name="newtext" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false" onkeyup="checkInput(this.form)" placeholder="_(use printable characters only)_"><input name="showPass" type="checkbox" class="lock" onchange="showInput(this.checked,false)">_(show passphrase)_
|
||||
|
||||
_(Retype new passphrase)_:
|
||||
: <input type="password" name="newcopy" class="lock" maxlength="512" value="" autocomplete="off" spellcheck="false" onkeyup="checkInput(this.form)">
|
||||
|
||||
</div>
|
||||
<div markdown="1" id="newfile" style="display:none">
|
||||
_(Select new keyfile)_:
|
||||
: <input type="file" name="newfile" onchange="getFileContent(event,this.form,'newdata')">
|
||||
|
||||
</div>
|
||||
|
||||
: <input type="submit" name="newkey" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
</form>
|
||||
<?endif;?>
|
||||
|
||||
<div class="title"><span class="left"><i class="title fa fa-plus-square"></i>_(Global SMART Settings)_</span></div>
|
||||
<form markdown="1" name="smart_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareDiskSettings(this)">
|
||||
<input type="hidden" name="#file" value="/boot/config/smart-all.cfg">
|
||||
<input type="hidden" name="#include" value="webGui/include/update.smart.php">
|
||||
@@ -199,7 +317,7 @@ _(Default critical disk temperature threshold)_ (°<?=_var($display,'unit','C
|
||||
<input type="hidden" name="smEvents" value="">
|
||||
<input type="hidden" name="smIndex" value="0">
|
||||
_(Default SMART notification value)_:
|
||||
: <select name="smSelect" size="1">
|
||||
: <select name="smSelect">
|
||||
<?=mk_option(_var($var,'smSelect'), "0", _('Raw'))?>
|
||||
<?=mk_option(_var($var,'smSelect'), "1", _('Normalized'))?>
|
||||
</select>
|
||||
@@ -207,7 +325,7 @@ _(Default SMART notification value)_:
|
||||
:disk_default_smart_notification_help:
|
||||
|
||||
_(Default SMART notification tolerance level)_:
|
||||
: <select name="smLevel" size="1">
|
||||
: <select name="smLevel">
|
||||
<?=mk_option(_var($var,'smLevel'), "1.00", _('Absolute'))?>
|
||||
<?=mk_option(_var($var,'smLevel'), "1.05", "5%")?>
|
||||
<?=mk_option(_var($var,'smLevel'), "1.10", "10%")?>
|
||||
@@ -220,7 +338,7 @@ _(Default SMART notification tolerance level)_:
|
||||
:disk_default_smart_tolerance_help:
|
||||
|
||||
_(Default SMART controller type)_:
|
||||
: <select name="smType" size="1" onchange="setIndex(this.form)">
|
||||
: <select name="smType" onchange="setIndex(this.form)">
|
||||
<?=mk_option(_var($var,'smType'), "", _('Automatic'))?>
|
||||
<?=mk_option(_var($var,'smType'), "-d ata", "ATA")?>
|
||||
<?=mk_option(_var($var,'smType'), "-d nvme", "NVMe")?>
|
||||
|
||||
@@ -92,9 +92,31 @@ refresh(); // automatically include new ethernet ports
|
||||
Array.prototype.same = function(){return this.sort().filter(function(v,i,o){return i&&v===o[i-1]?v:0;}).length;}
|
||||
|
||||
function prepareSettings(form) {
|
||||
var metrics = [];
|
||||
var metrics6 = [];
|
||||
var bondnics = [], brnics = [];
|
||||
for (var i=0,nic; nic=form.BONDNICS.options[i]; i++) {
|
||||
if (nic.selected) {
|
||||
bondnics.push(nic.value);
|
||||
nic.selected = false;
|
||||
}
|
||||
}
|
||||
nic = form.BONDNICS.options[0];
|
||||
nic.value = bondnics.join(',');
|
||||
nic.selected = true;
|
||||
nic.disabled = false;
|
||||
for (var i=0,nic; nic=form.BRNICS.options[i]; i++) {
|
||||
if (nic.selected) {
|
||||
brnics.push(nic.value);
|
||||
nic.selected = false;
|
||||
}
|
||||
}
|
||||
nic = form.BRNICS.options[0];
|
||||
nic.value = form.BONDING.value=='yes' ? form.BONDNAME.value : brnics.join(',');
|
||||
nic.selected = true;
|
||||
nic.disabled = false;
|
||||
if (brnics.length>1) form.BRSTP.value = 'yes';
|
||||
if ($(form).find('input[name="#arg[1]"]').val()=='none') return true;
|
||||
|
||||
var metrics = [], metrics6 = [];
|
||||
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
|
||||
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
|
||||
if (metrics.same() || metrics6.same()) {
|
||||
@@ -123,31 +145,6 @@ function prepareSettings(form) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var member = '';
|
||||
for (var i=0,item; item=form.BONDNICS.options[i]; i++) {
|
||||
if (item.selected) {
|
||||
if (member.length) member += ',';
|
||||
member += item.value;
|
||||
item.selected = false;
|
||||
}
|
||||
}
|
||||
item = form.BONDNICS.options[0];
|
||||
item.value = member;
|
||||
item.selected = true;
|
||||
item.disabled = false;
|
||||
var member = '';
|
||||
for (var i=0,item; item=form.BRNICS.options[i]; i++) {
|
||||
if (item.selected) {
|
||||
if (member.length) member += ',';
|
||||
member += item.value;
|
||||
item.selected = false;
|
||||
}
|
||||
}
|
||||
item = form.BRNICS.options[0];
|
||||
item.value = form.BONDING.value=='yes' ? form.BONDNAME.value : member;
|
||||
item.selected = true;
|
||||
item.disabled = false;
|
||||
if (member.indexOf(',')>0) form.BRSTP.value = 'yes';
|
||||
$(form).find('select[name^="PROTOCOL:"]').each(function() {
|
||||
var protocol = $(this).val() || 'ipv4';
|
||||
var i = $(this).attr('name').split(':')[1];
|
||||
|
||||
@@ -14,59 +14,20 @@ Tag="server"
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
global $var ;
|
||||
$theme = $display['theme'] ;
|
||||
?>
|
||||
|
||||
<style>
|
||||
table.t1{margin-top:0; border-collapse: collapse; border-spacing: 0;}
|
||||
table tr td{padding:0 0 3px 0;margin:0}
|
||||
table tr td.thin{line-height:8px;height:8px}
|
||||
table.t1 tr>td{width: 1%; ; text-align:centre ;white-space: nowrap;}
|
||||
table.t1 tr>td+td{width: 1%; white-space: nowrap; }
|
||||
table.t1 tr>td+td+td{width:auto ; text-align:left;}
|
||||
table.t1 tr>td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
|
||||
table.t1 tr>td+td+td+td+td+td+td+td+td+td+td+td+td{text-align:left;}
|
||||
.tablesorter .filtered {
|
||||
display: none;
|
||||
}
|
||||
<?if ($theme == "black"):?>
|
||||
table.tablesorter tbody tr.alt-row {background-color:#212121;}
|
||||
table.tablesorter tbody tr.normal-row {background-color:#1c1b1b;}
|
||||
input.search {color:#f2f2f2;background-color:#1c1b1b;}
|
||||
<?endif;?>
|
||||
<?if ($theme == "white"):?>
|
||||
table.tablesorter tbody tr.alt-row {background-color:#ededed;}
|
||||
table.tablesorter tbody tr.normal-row {background-color:#f2f2f2;}
|
||||
input.search {color:#1c1b1b;background-color:#f2f2f2;}
|
||||
<?endif;?>
|
||||
<?if ($theme == "gray"):?>
|
||||
table.tablesorter tbody tr.alt-row {solid #0c0f0b;}
|
||||
table.tablesorter tbody tr.normal-row {background-color:#1b1d1b;}
|
||||
input.search {color:#606e7f;background-color:#1b1d1b;}
|
||||
table.tablesorter thead th {color:#606e7f;background-color:#1b1d1b;}
|
||||
div.tablesorter-header-inner {color:#606e7f;background-color:#1b1d1b;}
|
||||
<?endif;?>
|
||||
<?if ($theme == "azure"):?>
|
||||
table.tablesorter tbody tr.alt-row {background-color:#e4e2e4; }
|
||||
table.tablesorter tbody tr.normal-row {solid #f3f0f4;}
|
||||
input.search {color:#606e7f;background-color:#e4e2e4;}
|
||||
table.tablesorter thead th {color:#606e7f;background-color:#e4e2e4;}
|
||||
div.tablesorter-header-inner {color:#606e7f;background-color:#e4e2e4;}
|
||||
<?endif;?>
|
||||
|
||||
table.t1 tr td{padding:0 0 3px 0;margin:0}
|
||||
table.t1 tr td.thin{line-height:8px;height:8px}
|
||||
table.t1 tr>td{width:1%;text-align:centre;white-space: nowrap}
|
||||
table.t1 tr>td+td{width:1%;white-space:nowrap}
|
||||
table.t1 tr>td+td+td{width:auto;text-align:left}
|
||||
table.t1 tr>td+td+td+td{text-align:left}
|
||||
table.t1 tr>td+td+td+td+td{text-align:left}
|
||||
.t1.tablesorter .filtered{display:none}
|
||||
</style>
|
||||
<script type="text/javascript" src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/webGui/javascript/jquery.tablesorter.widgets.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function showDrivers(options, init = false) {
|
||||
@@ -75,36 +36,32 @@ function showDrivers(options, init = false) {
|
||||
$('#driversearch').prop('disabled', true);
|
||||
$('#select').prop('disabled', true);
|
||||
$('#rebuild').prop('disabled', true);
|
||||
|
||||
$.post('/webGui/include/SysDrivers.php',{table:'t1load',option:"all"},function(data){
|
||||
clearTimeout(timers.refresh);
|
||||
$("#t1").trigger("destroy");
|
||||
$("#t1").trigger("destroy");
|
||||
$('#t1').html(data.html);
|
||||
$('#t1').tablesorter({
|
||||
sortList:[[0,0]],
|
||||
sortAppend:[[0,0]],
|
||||
widgets: ['stickyHeaders','filter', 'zebra'],
|
||||
widgetOptions: {
|
||||
// on black and white, offset is height of #menu
|
||||
// on azure and gray, offset is height of #header
|
||||
stickyHeaders_offset: ( $('#menu').height() < 50 ) ? $('#menu').height() : $('#header').height(),
|
||||
filter_columnFilters: false,
|
||||
zebra : [ "normal-row", "alt-row" ]
|
||||
}
|
||||
|
||||
sortList:[[0,0]],
|
||||
sortAppend:[[0,0]],
|
||||
widgets: ['stickyHeaders','filter', 'zebra'],
|
||||
widgetOptions: {
|
||||
// on black and white, offset is height of #menu
|
||||
// on azure and gray, offset is height of #header
|
||||
stickyHeaders_offset: ( $('#menu').height() < 50 ) ? $('#menu').height() : $('#header').height(),
|
||||
filter_columnFilters: false,
|
||||
zebra : [ "normal-row", "alt-row" ]
|
||||
}
|
||||
});
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
$('#driversearch').prop('disabled', false);
|
||||
$('#select').prop('disabled', false);
|
||||
$('#rebuild').prop('disabled', data.init);
|
||||
|
||||
},"json");
|
||||
} else {
|
||||
|
||||
filter = [];
|
||||
filterDrivers() ;
|
||||
filterDrivers() ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function filterDrivers() {
|
||||
var totalColumns = $('#t1')[0].config.columns;
|
||||
@@ -124,7 +81,7 @@ function showDriversupdate() {
|
||||
$('#rebuild').prop('disabled', false);
|
||||
showDrivers("all",true) ;
|
||||
$('div.spinner.fixed').hide('slow');
|
||||
}) ;
|
||||
});
|
||||
}
|
||||
|
||||
function textedit(module) {
|
||||
@@ -132,11 +89,9 @@ function textedit(module) {
|
||||
$('#text'+module).prop('disabled', false);
|
||||
$('#save'+module).attr('hidden', false);
|
||||
$('#text'+module).attr('hidden', false);
|
||||
|
||||
}
|
||||
|
||||
function removecfg(module)
|
||||
{
|
||||
function removecfg(module) {
|
||||
swal({title:"_(Proceed)_?",text:"_(Remove custom modprobe.d configuration?)_: "+module,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) textsave(module, true); else return false;});
|
||||
}
|
||||
|
||||
@@ -146,7 +101,7 @@ function textsave(module,remove = false) {
|
||||
$('#save'+module).attr('hidden', true);
|
||||
var x = (remove) ? "" : document.getElementById("text" + module).value;
|
||||
$.post('/webGui/include/SysDrivers.php',{table:'update',module:module,conf:x},function(data){
|
||||
if(data) {
|
||||
if (data) {
|
||||
formHasUnsavedChanges=false;
|
||||
$('#text'+module).val(data.modprobe) ;
|
||||
$('#status'+module).html(data.state) ;
|
||||
@@ -159,24 +114,22 @@ function textsave(module,remove = false) {
|
||||
if (data.supportpage == true) {
|
||||
if (data.support == true) {
|
||||
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='" + _("Support page")_ + "' class='fa fa-phone-square'></i></a>" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#t1').trigger("updateCell",[document.getElementById('text'+module), false, null]);
|
||||
$('#t1').trigger("updateCell",[document.getElementById('status'+module), false, null]);
|
||||
var message = "_(System Drivers)_: _(A reboot is required to apply changes)_";
|
||||
addRebootNotice(message);
|
||||
},"json");
|
||||
},"json");
|
||||
}
|
||||
|
||||
$('.tabs').append("<span class='status'><span class='lite label'>_(Select View)_:</span><select id='select' onchange='showDrivers(this.value)'><option value='all' >All Drivers</option><option value='inuse' selected >Inuse Drivers</option></select>");
|
||||
showDrivers("all",true) ;
|
||||
|
||||
</script>
|
||||
|
||||
:sysdrivers_intro_help:
|
||||
|
||||
<form autocomplete="off" onsubmit="return false;"><span><input class="search" id="driversearch" type="search" placeholder="Search..." onchange="filterDrivers();"></span></form>
|
||||
<pre><form id="sysdrivers" class="js-confirm-leave" onsubmit="return false"><table id='t1' class="t1 disk_status tablesorter " ><tr><td><div class="spinner"></div></td></tr></table></form></pre><br>
|
||||
<form autocomplete="off" onsubmit="return false;"><span><input class="t1 search" id="driversearch" type="search" placeholder="Search..." onchange="filterDrivers();"></span></form>
|
||||
<pre><form id="sysdrivers" class="js-confirm-leave" onsubmit="return false"><table id='t1' class="t1 disk_status tablesorter"><tr><td><div class="spinner"></div></td></tr></table></form></pre><br>
|
||||
<input type="button" value="_(Done)_" onclick="done()"><input type="button" id="rebuild" value="_(Rebuild Modules)_" onclick="showDriversupdate()">
|
||||
|
||||
|
||||
@@ -18,19 +18,28 @@ Tag="list"
|
||||
<?
|
||||
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
|
||||
$log = '/var/log/syslog';
|
||||
$prev = '/boot/logs/syslog-previous';
|
||||
$cfg = '/boot/config/rsyslog.cfg';
|
||||
$max = 5000;
|
||||
$select = [];
|
||||
$logs = [];
|
||||
if (file_exists($cfg)) {
|
||||
$syslog = parse_ini_file($cfg);
|
||||
if (isset($syslog['local_server']) && isset($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
|
||||
if (!empty($syslog['local_server']) && !empty($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
|
||||
natsort($logs);
|
||||
$select[] = "<select onchange='showLog(this.value)'>";
|
||||
$select[] = mk_option(1,$log,'syslog');
|
||||
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
|
||||
$select[] = "</select>";
|
||||
}
|
||||
}
|
||||
if (file_exists($prev)) {
|
||||
// add syslog-previous to front of logs array
|
||||
array_unshift($logs, $prev);
|
||||
}
|
||||
if (count($logs)) {
|
||||
// add syslog to front of logs array
|
||||
array_unshift($logs, $log);
|
||||
$select[] = "<select onchange='showLog(this.value)'>";
|
||||
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
|
||||
$select[] = "</select>";
|
||||
}
|
||||
$select = implode($select);
|
||||
?>
|
||||
<style>
|
||||
|
||||
@@ -139,7 +139,7 @@ $dnsserver = _var($$ethX,'DNS_SERVER1');
|
||||
|
||||
$link = iflink($ethX);
|
||||
$postUp0 = "$script add $link WireGuard-<wg> $server <port> <port> udp";
|
||||
$postUp1 = "logger -t wireguard 'Tunnel WireGuard-<wg> started';$services";
|
||||
$postUp1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> started';$services";
|
||||
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>;iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
|
||||
$postUpX = "iptables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
||||
@@ -149,7 +149,7 @@ $postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>;ip6tables -A WIREGUARD -o $link -
|
||||
$postUpX6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
|
||||
$postUpZ6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;ip6tables -A WIREGUARD_DROP_<WG> -j RETURN";
|
||||
$postDown0 = "$script del $link <port> udp";
|
||||
$postDown1 = "logger -t wireguard 'Tunnel WireGuard-<wg> stopped';$services";
|
||||
$postDown1 = "logger -t wireguard -- 'Tunnel WireGuard-<wg> stopped';$services";
|
||||
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
$postDown3 = "iptables -F WIREGUARD_DROP_<WG>;iptables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;iptables -X WIREGUARD_DROP_<WG>";
|
||||
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#!/bin/bash
|
||||
/usr/bin/logger "Submitting SysDrivers Build"
|
||||
/usr/local/emhttp/plugins/dynamix/include/SysDriversInit.php &> /dev/null &
|
||||
|
||||
# run & log functions
|
||||
. /etc/rc.d/rc.runlog
|
||||
|
||||
log "Submitting SysDrivers Build"
|
||||
/usr/local/emhttp/plugins/dynamix/include/SysDriversInit.php &>/dev/null &
|
||||
|
||||
@@ -119,12 +119,12 @@ function verifyTwoFactorToken(string $username, string $token): bool {
|
||||
// This should accept 200 or 204 status codes
|
||||
if ($httpCode !== 200 && $httpCode !== 204) {
|
||||
// Log error to syslog
|
||||
exec("logger -t webGUI ".escapeshellarg("2FA code for {$username} is invalid, blocking access!"));
|
||||
exec("logger -t webGUI -- \"2FA code for {$username} is invalid, blocking access!\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log success to syslog
|
||||
exec("logger -t webGUI ".escapeshellarg("2FA code for {$username} is valid, allowing login!"));
|
||||
exec("logger -t webGUI -- \"2FA code for {$username} is valid, allowing login!\"");
|
||||
|
||||
// Success
|
||||
return true;
|
||||
@@ -199,7 +199,7 @@ if (!empty($username) && !empty($password)) {
|
||||
|
||||
// Check if we're limited
|
||||
if ($failCount >= $maxFails) {
|
||||
if ($failCount == $maxFails) exec("logger -t webGUI ".escapeshellarg("Ignoring login attempts for {$username} from {$remote_addr}"));
|
||||
if ($failCount == $maxFails) exec("logger -t webGUI -- \"Ignoring login attempts for {$username} from {$remote_addr}\"");
|
||||
throw new Exception(_('Too many invalid login attempts'));
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ if (!empty($username) && !empty($password)) {
|
||||
$_SESSION['unraid_user'] = $username;
|
||||
session_regenerate_id(true);
|
||||
session_write_close();
|
||||
exec("logger -t webGUI ".escapeshellarg("Successful login user {$username} from {$remote_addr}"));
|
||||
exec("logger -t webGUI -- \"Successful login user {$username} from {$remote_addr}\"");
|
||||
|
||||
// Redirect the user to the start page
|
||||
header("Location: /".$var['START_PAGE']);
|
||||
@@ -226,7 +226,7 @@ if (!empty($username) && !empty($password)) {
|
||||
$error = $exception->getMessage();
|
||||
|
||||
// Log error to syslog
|
||||
exec("logger -t webGUI ".escapeshellarg("Unsuccessful login user {$username} from {$remote_addr}"));
|
||||
exec("logger -t webGUI -- \"Unsuccessful login user {$username} from {$remote_addr}\"");
|
||||
appendToFile($failFile, $time."\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) {
|
||||
}
|
||||
|
||||
// Error when attempting to set password
|
||||
exec("logger -t webGUI ".escapeshellarg($VALIDATION_MESSAGES['saveError'] . " [REMOTE_ADDR]: {$REMOTE_ADDR}"));
|
||||
exec("logger -t webGUI -- \"{$VALIDATION_MESSAGES['saveError']} [REMOTE_ADDR]: {$REMOTE_ADDR}\"");
|
||||
return $POST_ERROR = $VALIDATION_MESSAGES['saveError'];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,25 +12,46 @@
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
|
||||
function write(&$rows) {
|
||||
if ($size = count($rows)) echo '<tbody>',implode(array_map(function($row){echo gzinflate($row);},$rows)),'</tbody>';
|
||||
$rows = $size;
|
||||
}
|
||||
function validdir($dir) {
|
||||
$path = realpath($dir);
|
||||
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path : '';
|
||||
}
|
||||
function escapeQuote($data) {
|
||||
return str_replace('"','"',$data);
|
||||
}
|
||||
function add($number, $name, $single='', $plural='s') {
|
||||
return $number.' '._($name.($number==1 ? $single : $plural));
|
||||
}
|
||||
function age($number,$time) {
|
||||
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
|
||||
}
|
||||
function my_age($time) {
|
||||
if (!is_numeric($time)) $time = time();
|
||||
$age = new DateTime('@'.$time);
|
||||
$age = date_create('now')->diff($age);
|
||||
if ($age->y > 0) return age($age->y,'year');
|
||||
if ($age->m > 0) return age($age->m,'month');
|
||||
if ($age->d > 0) return age($age->d,'day');
|
||||
if ($age->h > 0) return age($age->h,'hour');
|
||||
if ($age->i > 0) return age($age->i,'minute');
|
||||
return age($age->s,'second');
|
||||
}
|
||||
function parent_link() {
|
||||
global $dir,$path;
|
||||
$parent = dirname($dir);
|
||||
return $parent=='/' ? false : '<a href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($parent)).'">'._('Parent Directory').'</a>';
|
||||
}
|
||||
function my_devs(&$devs) {
|
||||
function my_devs(&$devs,$name,$menu) {
|
||||
global $disks,$lock;
|
||||
$text = []; $i = 0;
|
||||
foreach ($devs as $dev) {
|
||||
@@ -38,66 +59,75 @@ function my_devs(&$devs) {
|
||||
$text[$i] = '<a class="info" onclick="return false"><i class="lock fa fa-fw fa-hdd-o grey-text"></i></a> ---';
|
||||
} else {
|
||||
switch ($disks[$dev]['luksState']??0) {
|
||||
case 0: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-unlock-alt grey-text'></i><span>"._('Not encrypted')."</span></a>"; break;
|
||||
case 1: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-unlock-alt green-text'></i><span>"._('Encrypted and unlocked')."</span></a>"; break;
|
||||
case 2: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: missing encryption key')."</span></a>"; break;
|
||||
case 3: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: wrong encryption key')."</span></a>"; break;
|
||||
default: $text[$i] = "<a class='info' onclick='return false'><i class='lock fa fa-fw fa-lock red-text'></i><span>"._('Locked: unknown error')."</span></a>"; break;
|
||||
case 0: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-unlock-alt grey-text"></i><span>'._('Not encrypted').'</span></a>'; break;
|
||||
case 1: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-unlock-alt green-text"></i><span>'._('Encrypted and unlocked').'</span></a>'; break;
|
||||
case 2: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: missing encryption key').'</span></a>'; break;
|
||||
case 3: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: wrong encryption key').'</span></a>'; break;
|
||||
default: $text[$i] = '<span class="dfm_device"><a class="info" onclick="return false"><i class="lock fa fa-fw fa-lock red-text"></i><span>'._('Locked: unknown error').'</span></a>'; break;
|
||||
}
|
||||
$text[$i] .= compress($dev,12,0);
|
||||
$root = $dev=='flash' ? "/boot/$name" : "/mnt/$dev/$name";
|
||||
$text[$i] .= '<span id="device_'.$i.'" class="hand" onclick="'.$menu.'(\''.$root.'\','.$i.')" oncontextmenu="'.$menu.'(\''.$root.'\','.$i.');return false">'.compress($dev,11,0).'</span></span>';
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return implode($text);
|
||||
}
|
||||
$dir = validdir(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
|
||||
if (!$dir) {echo '<tbody><tr><td></td><td></td><td colspan="6">',_('Invalid path'),'</td><td></td></tr></tbody>'; exit;}
|
||||
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
$disks = parse_ini_file('state/disks.ini',true);
|
||||
$shares = parse_ini_file('state/shares.ini',true);
|
||||
$dir = realpath(htmlspecialchars_decode(rawurldecode($_GET['dir'])));
|
||||
$path = unscript($_GET['path']);
|
||||
$fmt = "%F {$display['time']}";
|
||||
$dirs = $files = [];
|
||||
$total = $objs = 0;
|
||||
[$null,$root,$main,$rest] = my_explode('/',$dir,4);
|
||||
[$null,$root,$main,$next,$rest] = my_explode('/',$dir,5);
|
||||
$user = $root=='mnt' && in_array($main,['user','user0']);
|
||||
$lock = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
|
||||
$ishare = $root=='mnt' && (!$main || !$next || ($main=='rootshare' && !$rest));
|
||||
$folder = $lock=='---' ? _('DEVICE') : ($ishare ? _('SHARE') : _('FOLDER'));
|
||||
|
||||
if ($user) {
|
||||
exec("shopt -s dotglob; getfattr --no-dereference --absolute-names -n system.LOCATIONS ".escapeshellarg($dir)."/* 2>/dev/null",$tmp);
|
||||
if ($user ) {
|
||||
exec("shopt -s dotglob;getfattr --no-dereference --absolute-names -n system.LOCATIONS ".escapeshellarg($dir)."/* 2>/dev/null",$tmp);
|
||||
for ($i = 0; $i < count($tmp); $i+=3) $set[basename($tmp[$i])] = explode('"',$tmp[$i+1])[1];
|
||||
unset($tmp);
|
||||
}
|
||||
$stat = popen("shopt -s dotglob; stat -L -c'%F|%s|%Y|%n' ".escapeshellarg($dir)."/* 2>/dev/null",'r');
|
||||
$stat = popen("shopt -s dotglob;stat -L -c'%F|%U|%A|%s|%Y|%n' ".escapeshellarg($dir)."/* 2>/dev/null",'r');
|
||||
while (($row = fgets($stat))!==false) {
|
||||
[$type,$size,$time,$name] = explode('|',rtrim($row,"\n"),4);
|
||||
[$type,$owner,$perm,$size,$time,$name] = explode('|',rtrim($row,"\n"),6);
|
||||
$dev = explode('/',$name,5);
|
||||
$devs = explode(',',$user ? $set[basename($name)]??$shares[$dev[3]]['cachePool']??'' : $lock);
|
||||
$objs++;
|
||||
$text = [];
|
||||
if ($type[0]=='d') {
|
||||
$text[] = "<tr>";
|
||||
$text[] = "<td data=''><div class='icon-dir'></div></td>";
|
||||
$text[] = "<td><a href=\"/$path?dir=".rawurlencode(htmlspecialchars($name))."\">".htmlspecialchars(basename($name))."</a></td>";
|
||||
$text[] = "<td data='0'><"._('FOLDER')."></td>";
|
||||
$text[] = "<td data='$time'>".my_time($time,$fmt)."</td>";
|
||||
$text[] = "<td class='loc'>".my_devs($devs)."</td>";
|
||||
$text[] = "</tr>";
|
||||
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
|
||||
$text[] = '<td data=""><div class="icon-dir"></div></td>';
|
||||
$text[] = '<td><a id="name_'.$objs.'" oncontextmenu="folderContextMenu(this.id,\'right\');return false" href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($name)).'">'.htmlspecialchars(basename($name)).'</a></td>';
|
||||
$text[] = '<td id="owner_'.$objs.'">'.$owner.'</td>';
|
||||
$text[] = '<td id="perm_'.$objs.'">'.$perm.'</td>';
|
||||
$text[] = '<td data="0"><'.$folder.'></td>';
|
||||
$text[] = '<td data="'.$time.'"><span class="my_time">'.my_time($time,$fmt).'</span><span class="my_age" style="display:none">'.my_age($time).'</span></td>';
|
||||
$text[] = '<td class="loc">'.my_devs($devs,$dev[3]??$dev[2],'deviceFolderContextMenu').'</td>';
|
||||
$text[] = '<td><i id="row_'.$objs.'" data="'.escapeQuote($name).'" type="d" class="fa fa-plus-square-o" onclick="folderContextMenu(this.id,\'both\')" oncontextmenu="folderContextMenu(this.id,\'both\');return false">...</i></td></tr>';
|
||||
$dirs[] = gzdeflate(implode($text));
|
||||
} else {
|
||||
$ext = strtolower(pathinfo($name,PATHINFO_EXTENSION));
|
||||
$tag = count($devs)>1 ? 'warning' : '';
|
||||
$text[] = "<tr>";
|
||||
$text[] = "<td data='$ext'><div class='icon-file icon-$ext'></div></td>";
|
||||
$text[] = "<td><a href=\"".htmlspecialchars($name)."\" download target=\"_blank\" class=\"".($tag?:'none')."\">".htmlspecialchars(basename($name))."</a></td>";
|
||||
$text[] = "<td data='$size' class='$tag'>".my_scale($size,$unit)." $unit</td>";
|
||||
$text[] = "<td data='$time' class='$tag'>".my_time($time,$fmt)."</td>";
|
||||
$text[] = "<td class='loc $tag'>".my_devs($devs)."</td>";
|
||||
$text[] = "</tr>";
|
||||
$text[] = '<tr><td><i id="check_'.$objs.'" class="fa fa-fw fa-square-o" onclick="selectOne(this.id)"></i></td>';
|
||||
$text[] = '<td class="ext" data="'.$ext.'"><div class="icon-file icon-'.$ext.'"></div></td>';
|
||||
$text[] = '<td id="name_'.$objs.'" class="'.$tag.'" onclick="fileEdit(this.id)" oncontextmenu="fileContextMenu(this.id,\'right\');return false">'.htmlspecialchars(basename($name)).'</td>';
|
||||
$text[] = '<td id="owner_'.$objs.'" class="'.$tag.'">'.$owner.'</td>';
|
||||
$text[] = '<td id="perm_'.$objs.'" class="'.$tag.'">'.$perm.'</td>';
|
||||
$text[] = '<td data="'.$size.'" class="'.$tag.'">'.my_scale($size,$unit).' '.$unit.'</td>';
|
||||
$text[] = '<td data="'.$time.'" class="'.$tag.'"><span class="my_time">'.my_time($time,$fmt).'</span><span class="my_age" style="display:none">'.my_age($time).'</span></td>';
|
||||
$text[] = '<td class="loc '.$tag.'">'.my_devs($devs,$dev[3]??$dev[2],'deviceFileContextMenu').'</td>';
|
||||
$text[] = '<td><i id="row_'.$objs.'" data="'.escapeQuote($name).'" type="f" class="fa fa-plus-square-o" onclick="fileContextMenu(this.id,\'both\')" oncontextmenu="fileContextMenu(this.id,\'both\');return false">...</i></td></tr>';
|
||||
$files[] = gzdeflate(implode($text));
|
||||
$total += $size;
|
||||
}
|
||||
}
|
||||
pclose($stat);
|
||||
if ($link = parent_link()) echo "<tbody class='tablesorter-infoOnly'><tr><td><div><img src='/webGui/icons/folderup.png'></div></td><td>$link</td><td colspan='3'></td></tr></tbody>";
|
||||
echo write($dirs),write($files),'<tfoot><tr><td></td><td colspan="4">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
|
||||
?>
|
||||
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><div><img src="/webGui/icons/folderup.png"></div></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
|
||||
echo write($dirs),write($files),'<tfoot><tr><td></td><td></td><td colspan="7">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';
|
||||
?>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
* Copyright 2012-2021, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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,
|
||||
@@ -14,7 +14,7 @@
|
||||
// Color coding for syslog and disk log
|
||||
$match =
|
||||
[['class' => 'text',
|
||||
'text' => ['to the standard error','non[ -]fatal error','correct gpt errors','error handler\b','(kernel|logger): [|+ #-.]','logger: (naming|log)','tainted: (host-cpu|high-privileges)','root: (>f|cd)\+\+\+\+','root: \.d\.\.t\.','(move: ){2}','kernel: ERST']
|
||||
'text' => ['to the standard error','non[ -]fatal error','correct gpt errors','error handler\b','(kernel|logger): [|+ #-.]','logger: (naming|log)','tainted: (host-cpu|high-privileges)','root: (>f|cd)\+\+\+\+','root: \.d\.\.t\.','(move: ){2}','kernel: ERST','kernel: BTRFS info \(device \S+\):']
|
||||
],
|
||||
['class' => 'login',
|
||||
'text' => ['(accepted|failed) password','sshd\[\d+\]:',' login user ']
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
|
||||
function age($number,$time) {
|
||||
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
|
||||
}
|
||||
function my_age($time) {
|
||||
if (!is_numeric($time)) $time = time();
|
||||
$age = new DateTime('@'.$time);
|
||||
$age = date_create('now')->diff($age);
|
||||
if ($age->y > 0) return age($age->y,'year');
|
||||
if ($age->m > 0) return age($age->m,'month');
|
||||
if ($age->d > 0) return age($age->d,'day');
|
||||
if ($age->h > 0) return age($age->h,'hour');
|
||||
if ($age->i > 0) return age($age->i,'minute');
|
||||
return age($age->s,'second');
|
||||
}
|
||||
function validname($name) {
|
||||
$path = realpath(dirname($name));
|
||||
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path.'/'.basename($name) : '';
|
||||
}
|
||||
function escape($name) {return escapeshellarg(validname($name));}
|
||||
function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',$name)) : escape($name);}
|
||||
|
||||
switch ($_POST['mode']) {
|
||||
case 'upload':
|
||||
$file = validname(htmlspecialchars_decode(rawurldecode($_POST['file'])));
|
||||
if (!$file) die('stop');
|
||||
$local = "/var/tmp/".basename($file).".tmp";
|
||||
if ($_POST['start']==0) {
|
||||
$my = pathinfo($file); $n = 0;
|
||||
while (file_exists($file)) $file = $my['dirname'].'/'.preg_replace('/ \(\d+\)$/','',$my['filename']).' ('.++$n.')'.($my['extension'] ? '.'.$my['extension'] : '');
|
||||
file_put_contents($local,$file);
|
||||
// create file with proper permissions and owner
|
||||
touch($file);
|
||||
chgrp($file,'users');
|
||||
chown($file,'nobody');
|
||||
chmod($file,0666);
|
||||
}
|
||||
$file = file_get_contents($local);
|
||||
if ($_POST['cancel']==1) {
|
||||
delete_file($file);
|
||||
die('stop');
|
||||
}
|
||||
if (file_put_contents($file,base64_decode($_POST['data']),FILE_APPEND)===false) {
|
||||
delete_file($file);
|
||||
die('error');
|
||||
}
|
||||
die();
|
||||
case 'calc':
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
$source = explode("\n",htmlspecialchars_decode(rawurldecode($_POST['source'])));
|
||||
[$null,$root,$main,$rest] = my_explode('/',$source[0],4);
|
||||
if ($root=='mnt' && in_array($main,['user','user0'])) {
|
||||
$disks = parse_ini_file('state/disks.ini',true);
|
||||
$tag = implode('|',array_merge(['disk'],pools_filter($disks)));
|
||||
$loc = array_filter(explode(',',preg_replace("/($tag)/",',$1',exec("shopt -s dotglob; getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($source)."/* 2>/dev/null"))));
|
||||
} else {
|
||||
$loc = [];
|
||||
foreach ($source as $path) {
|
||||
[$null,$root,$main,$rest] = my_explode('/',$path,4);
|
||||
$loc[] = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
|
||||
}
|
||||
}
|
||||
natcasesort($loc);
|
||||
$awk = "awk 'BEGIN{ORS=\" \"}/Number of files|Total file size/{if(\$5==\"(reg:\")print \$4,\$8;if(\$5==\"(dir:\")print \$4,\$6;if(\$3==\"size:\")print \$4}'";
|
||||
[$files,$dirs,$size] = explode(' ',str_replace([',',')'],'',exec("rsync --stats -naI ".quoted($source)." /var/tmp 2>/dev/null|$awk")));
|
||||
$dirs = $dirs ?: 0;
|
||||
$files -= $dirs;
|
||||
$calc = [];
|
||||
$calc[] = _('Name').": ".implode(', ',array_map('basename',$source));
|
||||
$calc[] = _('Location').": ".implode(', ',array_unique($loc));
|
||||
$calc[] = _('Last modified').': '.my_age(max(array_map('filemtime',$source)));
|
||||
$calc[] = _('Total occupied space').": ".my_scale($size,$unit)." $unit";
|
||||
$calc[] = sprintf(_("in %s folder".($dirs==1?'':'s')." and %s file".($files==1?'':'s')),my_number($dirs),my_number($files));
|
||||
$calc = '<div style="text-align:left;margin-left:56px">'.implode('<br>',$calc).'</div>';
|
||||
die($calc);
|
||||
case 'home':
|
||||
$source = explode("\n",htmlspecialchars_decode(rawurldecode($_POST['source'])));
|
||||
$target = htmlspecialchars_decode(rawurldecode($_POST['target']));
|
||||
$disks = parse_ini_file('state/disks.ini',true);
|
||||
$tag = implode('|',array_merge(['disk'],pools_filter($disks)));
|
||||
$loc1 = implode(',',array_unique(array_filter(explode(',',preg_replace("/($tag)/",',$1',exec("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($source)." 2>/dev/null"))))));
|
||||
$loc2 = exec("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($target)." 2>/dev/null");
|
||||
$home = $loc1==$loc2 ? '1' : '0';
|
||||
die($home);
|
||||
case 'jobs':
|
||||
$jobs = [];
|
||||
$file = '/var/tmp/file.manager.jobs';
|
||||
$rows = file_exists($file) ? file($file,FILE_IGNORE_NEW_LINES) : [];
|
||||
$job = 1;
|
||||
for ($x = 0; $x < count($rows); $x+=9) {
|
||||
$data = parse_ini_string(implode("\n",array_slice($rows,$x,9)));
|
||||
$task = $data['task'];
|
||||
$source = explode("\r",$data['source']);
|
||||
$target = $data['target'];
|
||||
$more = count($source) > 1 ? " (".sprintf("and %s more",count($source)-1).") " : "";
|
||||
$jobs[] = '<i id="queue_'.$job.'" class="fa fa-fw fa-square-o blue-text job" onclick="selectOne(this.id,false)"></i>'._('Job')." [".sprintf("%'.04d",$job++)."] - $task ".$source[0].$more.($target ? " --> $target" : "");
|
||||
}
|
||||
$jobs = '<div id="dfm_joblist">'.implode("<br>",$jobs).'</div>';
|
||||
die($jobs);
|
||||
case 'edit':
|
||||
$file = validname(rawurldecode($_POST['file']));
|
||||
die($file ? file_get_contents($file) : '');
|
||||
case 'save':
|
||||
if ($file = validname(rawurldecode($_POST['file']))) file_put_contents($file,rawurldecode($_POST['data']));
|
||||
die();
|
||||
case 'stop':
|
||||
$file = htmlspecialchars_decode(rawurldecode($_POST['file']));
|
||||
delete_file("/var/tmp/$file.tmp");
|
||||
die();
|
||||
case 'start':
|
||||
$active = '/var/tmp/file.manager.active';
|
||||
$jobs = '/var/tmp/file.manager.jobs';
|
||||
$start = '0';
|
||||
if (file_exists($jobs)) {
|
||||
exec("sed -n '2,9 p' $jobs > $active");
|
||||
exec("sed -i '1,9 d' $jobs");
|
||||
$start = filesize($jobs) > 0 ? '2' : '1';
|
||||
if ($start=='1') delete_file($jobs);
|
||||
}
|
||||
die($start);
|
||||
case 'undo':
|
||||
$jobs = '/var/tmp/file.manager.jobs';
|
||||
$undo = '0';
|
||||
if (file_exists($jobs)) {
|
||||
$rows = array_reverse(explode(',',$_POST['row']));
|
||||
foreach ($rows as $row) {
|
||||
$end = $row + 8;
|
||||
exec("sed -i '$row,$end d' $jobs");
|
||||
}
|
||||
$undo = filesize($jobs) > 0 ? '2' : '1';
|
||||
if ($undo=='1') delete_file($jobs);
|
||||
}
|
||||
die($undo);
|
||||
case 'read':
|
||||
$active = '/var/tmp/file.manager.active';
|
||||
$read = file_exists($active) ? json_encode(parse_ini_file($active)) : '';
|
||||
die($read);
|
||||
case 'file':
|
||||
$active = '/var/tmp/file.manager.active';
|
||||
$jobs = '/var/tmp/file.manager.jobs';
|
||||
$data[] = 'action="'.($_POST['action']??'').'"';
|
||||
$data[] = 'title="'.rawurldecode($_POST['title']??'').'"';
|
||||
$data[] = 'source="'.htmlspecialchars_decode(rawurldecode($_POST['source']??'')).'"';
|
||||
$data[] = 'target="'.rawurldecode($_POST['target']??'').'"';
|
||||
$data[] = 'H="'.(empty($_POST['hdlink']) ? '' : 'H').'"';
|
||||
$data[] = 'sparse="'.(empty($_POST['sparse']) ? '' : '--sparse').'"';
|
||||
$data[] = 'exist="'.(empty($_POST['exist']) ? '--ignore-existing' : '').'"';
|
||||
$data[] = 'zfs="'.rawurldecode($_POST['zfs']??'').'"';
|
||||
if (isset($_POST['task'])) {
|
||||
// add task to queue
|
||||
$task = rawurldecode($_POST['task']);
|
||||
$data = "task=\"$task\"\n".implode("\n",$data)."\n";
|
||||
file_put_contents($jobs,$data,FILE_APPEND);
|
||||
} else {
|
||||
// start operation
|
||||
file_put_contents($active,implode("\n",$data));
|
||||
}
|
||||
die();
|
||||
}
|
||||
?>
|
||||
@@ -71,6 +71,7 @@ html{font-size:<?=$display['font']?>%}
|
||||
.upgrade_notice i{float:right;cursor:pointer}
|
||||
.back_to_top{display:none;position:fixed;bottom:30px;right:12px;color:#e22828;font-size:2.5rem;z-index:999}
|
||||
span.big.blue-text{cursor:pointer}
|
||||
span.strong.tour{margin-left:5px;padding-left:0}
|
||||
i.abortOps{font-size:2rem;float:right;margin-right:20px;margin-top:8px;cursor:pointer}
|
||||
pre#swalbody p{margin-block-end:1em}
|
||||
<?
|
||||
@@ -342,6 +343,29 @@ function openDocker(cmd,title,plg,func,start=0,button=0) {
|
||||
$('button.confirm').prop('disabled',button==0);
|
||||
});
|
||||
}
|
||||
function openVMAction(cmd,title,plg,func,start=0,button=0) {
|
||||
// start = 0 : run command only when not already running (default)
|
||||
// start = 1 : run command unconditionally
|
||||
// button = 0 : hide CLOSE button (default)
|
||||
// button = 1 : show CLOSE button
|
||||
nchan_vmaction.start();
|
||||
$.post('/webGui/include/StartCommand.php',{cmd:cmd,start:start},function(pid) {
|
||||
if (pid==0) {
|
||||
nchan_vmaction.stop();
|
||||
$('div.spinner.fixed').hide();
|
||||
$(".upgrade_notice").addClass('alert');
|
||||
return;
|
||||
}
|
||||
swal({title:title,text:"<pre id='swaltext'></pre><hr>",html:true,animation:'none',showConfirmButton:button!=0,confirmButtonText:"<?=_('Close')?>"},function(close){
|
||||
nchan_vmaction.stop();
|
||||
$('div.spinner.fixed').hide();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
setTimeout(function(){bannerAlert("<?=_('Attention - operation continues in background')?> ["+pid.toString().padStart(8,'0')+"]<i class='fa fa-bomb fa-fw abortOps' title=\"<?=_('Abort background process')?>\" onclick='abortOperation("+pid+")'></i>",cmd,plg,func,start);});
|
||||
});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled',button==0);
|
||||
});
|
||||
}
|
||||
function abortOperation(pid) {
|
||||
swal({title:"<?=_('Abort background operation')?>",text:"<?=_('This may leave an unknown state')?>",html:true,animation:'none',type:'warning',showCancelButton:true,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(){
|
||||
$.post('/webGui/include/StartCommand.php',{kill:pid},function() {
|
||||
@@ -387,6 +411,14 @@ function openDone(data) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function openError(data) {
|
||||
if (data == '_ERROR_') {
|
||||
$('div.spinner.fixed').hide();
|
||||
$('button.confirm').text("<?=_('Error')?>").prop('disabled',false).show();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function showStatus(name,plugin,job) {
|
||||
$.post('/webGui/include/ProcessStatus.php',{name:name,plugin:plugin,job:job},function(status){$(".tabs").append(status);});
|
||||
}
|
||||
@@ -739,7 +771,7 @@ unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt
|
||||
// Build footer
|
||||
annotate('Footer');
|
||||
echo '<div id="footer"><span id="statusraid"><span id="statusbar">';
|
||||
$progress = (_var($var,'fsProgress')!='')? "•<span class='blue strong'>{$var['fsProgress']}</span>" : '';
|
||||
$progress = (_var($var,'fsProgress')!='')? "•<span class='blue strong tour'>{$var['fsProgress']}</span>" : '';
|
||||
switch (_var($var,'fsState')) {
|
||||
case 'Stopped':
|
||||
echo "<span class='red strong'><i class='fa fa-stop-circle'></i> "._('Array Stopped')."</span>$progress"; break;
|
||||
@@ -804,7 +836,7 @@ defaultPage.on('message', function(msg,meta) {
|
||||
switch (ini['fsState']) {
|
||||
case 'Stopped' : var status = "<span class='red strong'><i class='fa fa-stop-circle'></i> <?=_('Array Stopped')?></span>"; break;
|
||||
case 'Started' : var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>"; break;
|
||||
case 'Formatting': var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>•<span class='orange strong'><?=_('Formatting device(s)')?></span>"; break;
|
||||
case 'Formatting': var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>•<span class='orange strong tour'><?=_('Formatting device(s)')?></span>"; break;
|
||||
default : var status = "<span class='orange strong'><i class='fa fa-pause-circle'></i> "+_('Array '+ini['fsState'])+"</span>";
|
||||
}
|
||||
if (ini['mdResyncPos'] > 0) {
|
||||
@@ -816,11 +848,11 @@ defaultPage.on('message', function(msg,meta) {
|
||||
default : var action = '';
|
||||
}
|
||||
action += " "+(ini['mdResyncPos']/(ini['mdResyncSize']/100+1)).toFixed(1)+" %";
|
||||
status += "•<span class='orange strong'>"+action.replace('.','<?=_var($display,'number','.,')[0]?>');
|
||||
status += "•<span class='orange strong tour'>"+action.replace('.','<?=_var($display,'number','.,')[0]?>');
|
||||
if (ini['mdResyncDt']==0) status += " • <?=_('Paused')?>";
|
||||
status += "</span>";
|
||||
}
|
||||
if (ini['fsProgress']) status += "•<span class='blue strong'>"+_(ini['fsProgress'])+"</span>";
|
||||
if (ini['fsProgress']) status += "•<span class='blue strong tour'>"+_(ini['fsProgress'])+"</span>";
|
||||
$('#statusbar').html(status);
|
||||
break;
|
||||
case 2:
|
||||
@@ -919,7 +951,54 @@ nchan_docker.on('message', function(data) {
|
||||
}
|
||||
box.scrollTop(box[0].scrollHeight);
|
||||
});
|
||||
|
||||
var nchan_vmaction = new NchanSubscriber('/sub/vmaction',{subscriber:'websocket'});
|
||||
nchan_vmaction.on('message', function(data) {
|
||||
if (!data || openDone(data) || openError(data)) return;
|
||||
var box = $('pre#swaltext');
|
||||
data = data.split('\0');
|
||||
switch (data[0]) {
|
||||
case 'addLog':
|
||||
var rows = document.getElementsByClassName('logLine');
|
||||
if (rows.length) {
|
||||
var row = rows[rows.length-1];
|
||||
row.innerHTML += data[1]+'<br>';
|
||||
}
|
||||
break;
|
||||
case 'progress':
|
||||
var rows = document.getElementsByClassName('progress-'+data[1]);
|
||||
if (rows.length) {
|
||||
rows[rows.length-1].textContent = data[2];
|
||||
}
|
||||
break;
|
||||
case 'addToID':
|
||||
var rows = document.getElementById(data[1]);
|
||||
if (rows === null) {
|
||||
rows = document.getElementsByClassName('logLine');
|
||||
if (rows.length) {
|
||||
var row = rows[rows.length-1];
|
||||
row.innerHTML += '<span id="'+data[1]+'">'+data[1]+': <span class="content">'+data[2]+'</span><span class="progress-'+data[1]+'"></span>.</span><br>';
|
||||
}
|
||||
} else {
|
||||
var rows_content = rows.getElementsByClassName('content');
|
||||
if (!rows_content.length || rows_content[rows_content.length-1].textContent != data[2]) {
|
||||
rows.innerHTML += '<span class="content">'+data[2]+'</span><span class="progress-'+data[1]+'"></span>.';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'show_Wait':
|
||||
progress_span[data[1]] = document.getElementById('wait-'+data[1]);
|
||||
progress_dots[data[1]] = setInterval(function(){if (((progress_span[data[1]].innerHTML += '.').match(/\./g)||[]).length > 9) progress_span[data[1]].innerHTML = progress_span[data[1]].innerHTML.replace(/\.+$/,'');},500);
|
||||
break;
|
||||
case 'stop_Wait':
|
||||
clearInterval(progress_dots[data[1]]);
|
||||
progress_span[data[1]].innerHTML = '';
|
||||
break;
|
||||
default:
|
||||
box.html(box.html()+data[0]);
|
||||
break;
|
||||
}
|
||||
box.scrollTop(box[0].scrollHeight);
|
||||
});
|
||||
var backtotopoffset = 250;
|
||||
var backtotopduration = 500;
|
||||
$(window).scroll(function() {
|
||||
|
||||
@@ -215,9 +215,9 @@ EOF
|
||||
echo "${RET}"
|
||||
} >>"${LOG}"
|
||||
# if there was an error with the submission, log details and exit loop
|
||||
[[ "${RET}" != *"retry_after"* ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" "Failed sending notification" && break
|
||||
[[ "${RET}" != *"retry_after"* ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" -- "Failed sending notification" && break
|
||||
# if retries exhausted, log failure
|
||||
[[ "${i}" -eq "${MAX}" ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" "Failed sending notification - rate limited" && break
|
||||
[[ "${i}" -eq "${MAX}" ]] && echo "${DATA}" >>"${LOG}" && logger -t "${SCRIPTNAME}" -- "Failed sending notification - rate limited" && break
|
||||
# we were rate limited, try again after a delay
|
||||
sleep 1
|
||||
done
|
||||
|
||||
@@ -32,7 +32,7 @@ function build_pages($pattern) {
|
||||
foreach (glob($pattern,GLOB_NOSORT) as $entry) {
|
||||
[$header, $content] = my_explode("\n---\n",file_get_contents($entry));
|
||||
$page = @parse_ini_string($header);
|
||||
if (!$page) {exec("logger -t 'webGUI' Invalid .page format: $entry"); continue;}
|
||||
if (!$page) {exec("logger -t webGUI -- \"Invalid .page format: $entry\""); continue;}
|
||||
$page['file'] = $entry;
|
||||
$page['root'] = dirname($entry);
|
||||
$page['name'] = basename($entry, '.page');
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
function SysDriverslog($m, $type = "NOTICE") {
|
||||
|
||||
if ($type == "DEBUG" ) return NULL;
|
||||
$m = print_r($m,true);
|
||||
$m = str_replace("\n", " ", $m);
|
||||
$m = str_replace('"', "'", $m);
|
||||
$cmd = "/usr/bin/logger ".'"'.$m.'"'." -tSysDrivers";
|
||||
exec($cmd);
|
||||
if ($type == "DEBUG") return NULL;
|
||||
$m = print_r($m,true);
|
||||
$m = str_replace("\n", " ", $m);
|
||||
$m = str_replace('"', "'", $m);
|
||||
exec("logger -t webGUI -- \"$m\"");
|
||||
}
|
||||
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
// add translations
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/SysDriversHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
$kernel = shell_exec("uname -r") ;
|
||||
$kernel = trim($kernel,"\n") ;
|
||||
@@ -28,6 +25,6 @@ $arrModtoPlg = json_decode(file_get_contents("/tmp/modulestoplg.json") ,TRUE) ;
|
||||
file_put_contents("/tmp/sysdrivers.init","1") ;
|
||||
SysDriverslog("SysDrivers Build Starting") ;
|
||||
modtoplg() ;
|
||||
createlist() ;
|
||||
createlist() ;
|
||||
SysDriverslog("SysDrivers Build Complete") ;
|
||||
?>
|
||||
@@ -0,0 +1,367 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$dfm['hover'] = in_array($theme,['white','azure']) ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)';
|
||||
$dfm['bgcolor'] = in_array($theme,['white','azure']) ? '#f2f2f2' : '#1c1c1c';
|
||||
$dfm['fgcolor'] = in_array($theme,['white','azure']) ? '#1c1c1c' : '#f2f2f2';
|
||||
$dfm['incolor'] = $theme!='gray' ? $dfm['bgcolor'] : '#121510';
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
|
||||
<style>
|
||||
#countdown{float:left;margin-left:100px}
|
||||
#user-notice{float:left}
|
||||
div.dfm_info{position:absolute;bottom:4px;width:74%;margin-left:23%}
|
||||
div.dfm_template{display:none}
|
||||
div#dfm_dialogWindow{overflow-x:hidden}
|
||||
div#dfm_dialogWindow dt{width:23%}
|
||||
div#dfm_joblist{text-align:left;margin-top:20px;margin-left:56px}
|
||||
span.dfm_filter{position:relative;margin-left:<?=$themes1?'12':'0'?>px;top:-<?=$themes1?'2':'8'?>px}
|
||||
span.dfm_filter i{position:absolute;left:10px;top:<?=$themes1?'4':'8'?>px;font-size:1.4rem}
|
||||
span.dfm_loc{display:inline-block}
|
||||
span.dfm_text{display:inline-block;width:75%;white-space:normal}
|
||||
span.dfm_device{display:inline-block;float:left}
|
||||
span.dfm_percent{display:inline-block;width:40px}
|
||||
span.dfm_speed{display:inline-block;margin-left:10px;width:140px}
|
||||
input.dfm_filter{border:none;width:100px;background-color:<?=$dfm['incolor']?>;margin:-8px 0 0 0;padding-left:30px}
|
||||
input.dfm_filter:focus{background-color:<?=$dfm['incolor']?>}
|
||||
input#dfm_sparse,input#dfm_exist{margin-left:0}
|
||||
input#dfm_target{color:<?=$dfm['fgcolor']?>;width:500px}
|
||||
input#dfm_target+.fileTree{background:<?=$dfm['bgcolor']?>;width:500px;max-height:320px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
select.dfm{margin:0 40px 0 10px}
|
||||
select#dfm_source{min-width:none;max-width:none;border:none;background-image:none;width:660px;cursor:default}
|
||||
select#dfm_source option{background-color:transparent}
|
||||
i.dfm{margin-right:8px}
|
||||
i.dfm_filter{margin-top:-<?=$themes1?'2':'4'?>px}
|
||||
i.job{cursor:pointer;font-size:1.8rem;vertical-align:middle}
|
||||
.ui-dfm .ui-dialog-titlebar-close{background:transparent;border:none;font-size:1.8rem!important;margin-top:-14px!important;margin-right:-18px!important}
|
||||
.ui-dfm .ui-dialog-titlebar-close:hover{background:transparent;color:#ff8c2f}
|
||||
.ui-dfm .ui-dialog-title{text-align:center;width:100%;font-size:1.8rem}
|
||||
.ui-dfm .ui-dialog-content{padding-top:15px;vertical-align:bottom}
|
||||
.ui-dfm .ui-button-text{padding:0px 5px}
|
||||
.ui-dfm .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled],
|
||||
.ui-dfm .ui-dialog-buttonpane .ui-dialog-buttonset button[disabled]:hover
|
||||
{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
</style>
|
||||
|
||||
<div class="dfm_template">
|
||||
<div id="dfm_dialogWindow"></div>
|
||||
<input type="file" id="dfm_upload" value="" onchange="startUpload(this.files)" multiple>
|
||||
|
||||
<div markdown="1" id="dfm_templateCreateFolder">
|
||||
|
||||
:
|
||||
|
||||
_(New folder name)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This creates a folder at the current level)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateDeleteFolder">
|
||||
_(Folder name)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This deletes the folder and all its content")?></div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateRenameFolder">
|
||||
_(Current folder name)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(rename to)_ ...
|
||||
|
||||
_(New folder name)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the folder to the new name)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateCopyFolder">
|
||||
_(Source folder)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(copy to)_ ...
|
||||
|
||||
_(Target folder)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This copies the folder and all its content to another folder")?></div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateMoveFolder">
|
||||
_(Source folder)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(move to)_ ...
|
||||
|
||||
_(Target folder)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="HIDE_FILES_FILTER" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i><?=_("This moves the folder and all its content to another folder")?></div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateDeleteFile">
|
||||
_(File name)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This deletes the selected file)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateRenameFile">
|
||||
_(Current file name)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(rename to)_ ...
|
||||
|
||||
_(New file name)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" value="">
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the selected file)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateCopyFile">
|
||||
_(Source file)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(copy to)_ ...
|
||||
|
||||
_(Target file)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This copies the selected file)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateMoveFile">
|
||||
_(Source file)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(move to)_ ...
|
||||
|
||||
_(Target file)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This moves the selected file)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateDeleteObject">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This deletes all selected sources)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateRenameObject">
|
||||
_(Source)_:
|
||||
: <span id="dfm_source"></span>
|
||||
|
||||
|
||||
: _(rename to)_ ...
|
||||
|
||||
_(Target)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="">
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This renames the selected source)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateCopyObject">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
|
||||
: _(copy to)_ ...
|
||||
|
||||
_(Target)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This copies all the selected sources)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateMoveObject">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
|
||||
: _(move to)_ ...
|
||||
|
||||
_(Target)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value="" data-pickcloseonfile="true" data-pickfolders="true" data-pickfilter="" data-pickmatch="" data-pickroot="" data-picktop="">
|
||||
|
||||
<input type="checkbox" id="dfm_sparse" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_sparse">_(Use sparse option)_</span><br>
|
||||
<input type="checkbox" id="dfm_exist" value="" onchange="this.value=this.checked?'1':''"><span class="dfm_exist">_(Overwrite existing files)_</span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This moves all the selected sources)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateChangeOwner">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
|
||||
: _(change owner)_ ...
|
||||
|
||||
_(New owner)_:
|
||||
: <select id="dfm_target">
|
||||
<?foreach ($users as $user) echo mk_option(0,$user['name'],$user['name']);
|
||||
echo mk_option(0,'nobody','nobody');
|
||||
?></select>
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This changes the owner of the source recursively)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateChangePermission">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
|
||||
: _(change permission)_ ...
|
||||
|
||||
_(New permission)_:
|
||||
: <input type="hidden" id="dfm_target" value="">
|
||||
_(Owner)_:<select id="dfm_owner" class="narrow dfm">
|
||||
<?=mk_option(0,'u-rwx',_('No Access'))?>
|
||||
<?=mk_option(0,'u-wx+r',_('Read-only'))?>
|
||||
<?=mk_option(0,'u-x+rw',_('Read/Write'))?>
|
||||
</select>
|
||||
_(Group)_:<select id="dfm_group" class="narrow dfm">
|
||||
<?=mk_option(0,'g-rwx',_('No Access'))?>
|
||||
<?=mk_option(0,'g-wx+r',_('Read-only'))?>
|
||||
<?=mk_option(0,'g-x+rw',_('Read/Write'))?>
|
||||
</select>
|
||||
_(Other)_:<select id="dfm_other" class="narrow dfm">
|
||||
<?=mk_option(0,'o-rwx',_('No Access'))?>
|
||||
<?=mk_option(0,'o-wx+r',_('Read-only'))?>
|
||||
<?=mk_option(0,'o-x+rw',_('Read/Write'))?>
|
||||
</select>
|
||||
|
||||
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
<div class="dfm_info"><i class="fa fa-warning dfm"></i>_(This changes the permission of the source recursively)_</div>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="dfm_templateSearch">
|
||||
_(Source)_:
|
||||
: <select id="dfm_source"></select>
|
||||
|
||||
_(Search pattern)_:
|
||||
: <input type="text" id="dfm_target" autocomplete="off" spellcheck="false" value=""><span id="dfm_files"></span>
|
||||
|
||||
<span class="dfm_loc"> </span>
|
||||
: <span class="dfm_text"></span>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="dfm_templateEditFile">
|
||||
<!--!
|
||||
<style>div#dfm_editor{position:absolute;top:0;bottom:0;left:0;right:0}</style>
|
||||
<div id="dfm_editor"></div>
|
||||
<script src="<?autov('/plugins/dynamix.file.manager/javascript/ace/ace.js')?>"></script>
|
||||
<script src="<?autov('/plugins/dynamix.file.manager/javascript/ace/ext-modelist.js')?>"></script>
|
||||
<script>
|
||||
function getMode(file){
|
||||
var modelist = require('ace/ext/modelist');
|
||||
return modelist.getModeForPath(file).mode;
|
||||
}
|
||||
var source = "{$0}";
|
||||
var editor = ace.edit('dfm_editor');
|
||||
editor.session.setMode(getMode(source));
|
||||
editor.setOptions({
|
||||
showPrintMargin:false,
|
||||
fontSize:13,
|
||||
fontFamily:'bitstream',
|
||||
theme:'ace/theme/<?if (in_array($theme,['black','gray'])):?>tomorrow_night<?else:?>tomorrow<?endif;?>'
|
||||
});
|
||||
timers.editor = setTimeout(function(){$('div.spinner.fixed').show();},500);
|
||||
$.post('/plugins/dynamix.file.manager/include/Control.php',{mode:'edit',file:encodeURIComponent(source)},function(data){
|
||||
clearTimeout(timers.editor);
|
||||
$('div.spinner.fixed').hide();
|
||||
editor.session.setValue(data);
|
||||
});
|
||||
</script>
|
||||
!-->
|
||||
</div>
|
||||
|
||||
<div id="dfm_templateViewFile">
|
||||
<!--!
|
||||
<img id="dfm_viewer" href="{$0}">
|
||||
<script src="<?autov('/plugins/dynamix.file.manager/javascript/EZView.js')?>"></script>
|
||||
<script>
|
||||
$('#dfm_viewer').EZView();
|
||||
$('#dfm_viewer').click();
|
||||
</script>
|
||||
!-->
|
||||
</div>
|
||||
|
||||
<div id="dfm_templateJobs">
|
||||
<!--!
|
||||
<style>div#dfm_jobs{position:absolute;top:0;bottom:0;left:0;right:0;line-height:3rem}</style>
|
||||
<div id="dfm_jobs"></div>
|
||||
<script>
|
||||
$.post('/plugins/dynamix.file.manager/include/Control.php',{mode:'jobs'},function(jobs){
|
||||
$('#dfm_jobs').html(jobs);
|
||||
});
|
||||
</script>
|
||||
!-->
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,14 +74,14 @@ function ipaddr($ethX='eth0', $prot=4) {
|
||||
global $$ethX;
|
||||
switch (_var($$ethX,'PROTOCOL:0')) {
|
||||
case 'ipv4':
|
||||
return $$ethX['IPADDR:0'];
|
||||
return _var($$ethX,'IPADDR:0');
|
||||
case 'ipv6':
|
||||
return $$ethX['IPADDR6:0'];
|
||||
return _var($$ethX,'IPADDR6:0');
|
||||
case 'ipv4+ipv6':
|
||||
switch ($prot) {
|
||||
case 4: return $$ethX['IPADDR:0'];
|
||||
case 6: return $$ethX['IPADDR6:0'];
|
||||
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
|
||||
case 4: return _var($$ethX,'IPADDR:0');
|
||||
case 6: return _var($$ethX,'IPADDR6:0');
|
||||
default:return [_var($$ethX,'IPADDR:0'),_var($$ethX,'IPADDR6:0')];}
|
||||
default:
|
||||
return _var($$ethX,'IPADDR:0');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2020, Lime Technology
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -10,14 +10,15 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
/* This file provides basic local setup for php cli and is
|
||||
* named in /etc/php/php.ini like this:
|
||||
* auto_prepend_file="/usr/local/emhttp/webGui/include/local_prepend.php"
|
||||
*/
|
||||
// This file provides basic local setup for php cli and is
|
||||
// named in /etc/php/php.ini like this:
|
||||
// auto_prepend_file="/usr/local/emhttp/webGui/include/local_prepend.php"
|
||||
|
||||
function csrf_terminate($reason) {
|
||||
shell_exec("logger error: " . escapeshellarg($_SERVER['REQUEST_URI']) . ": $reason csrf_token");
|
||||
exit;
|
||||
exec("logger -t webGUI -- \"error: {$_SERVER['REQUEST_URI']} - {$reason} csrf_token\"");
|
||||
exit;
|
||||
}
|
||||
|
||||
putenv('PATH=.:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin');
|
||||
chdir('/usr/local/emhttp');
|
||||
setlocale(LC_ALL,'en_US.UTF-8');
|
||||
@@ -28,14 +29,14 @@ ini_set("session.use_strict_mode", "1");
|
||||
// ini_set("session.cookie_samesite", $secure?'Strict':'Lax');
|
||||
ini_set("session.cookie_samesite", 'Lax');
|
||||
if (array_key_exists('HTTP_HOST', $_SERVER)) {
|
||||
session_name("unraid_".md5(strstr($_SERVER['HTTP_HOST'].':', ':', true)));
|
||||
session_name("unraid_".md5(strstr($_SERVER['HTTP_HOST'].':', ':', true)));
|
||||
}
|
||||
session_set_cookie_params(0, '/', null, $secure, true);
|
||||
if ($_SERVER['SCRIPT_NAME'] != '/login.php' && $_SERVER['SCRIPT_NAME'] != '/auth-request.php' && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!isset($var)) $var = parse_ini_file('state/var.ini');
|
||||
if (!isset($var['csrf_token'])) csrf_terminate("uninitialized");
|
||||
if (!isset($_POST['csrf_token'])) csrf_terminate("missing");
|
||||
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
|
||||
unset($_POST['csrf_token']);
|
||||
if (!isset($var)) $var = parse_ini_file('state/var.ini');
|
||||
if (!isset($var['csrf_token'])) csrf_terminate("uninitialized");
|
||||
if (!isset($_POST['csrf_token'])) csrf_terminate("missing");
|
||||
if ($var['csrf_token'] != $_POST['csrf_token']) csrf_terminate("wrong");
|
||||
unset($_POST['csrf_token']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, 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.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'settings';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
$save = false;
|
||||
$disks = parse_ini_file('state/disks.ini',true);
|
||||
$newkey = parse_ini_file('state/var.ini')['luksKeyfile'] ?: '/root/keyfile';
|
||||
$oldkey = dirname($newkey).'/oldfile';
|
||||
$delkey = !is_file($newkey);
|
||||
$crypto = [];
|
||||
|
||||
foreach (glob('/dev/disk/by-id/*CRYPT-LUKS*',GLOB_NOSORT) as $disk) {
|
||||
$disk = explode('-',$disk);
|
||||
$crypto[] = array_pop($disk);
|
||||
}
|
||||
if (count($crypto)==0) die();
|
||||
|
||||
function delete_file(...$file) {
|
||||
array_map('unlink',array_filter($file,'is_file'));
|
||||
}
|
||||
function removeKey($key,$disk) {
|
||||
$match = $slots = 0;
|
||||
$dump = popen("cryptsetup luksDump /dev/$disk",'r');
|
||||
while (($row = fgets($dump))!==false) {
|
||||
if (strncmp($row,'Version:',8)==0) {
|
||||
switch (trim(explode(':',$row)[1])) {
|
||||
case 1: $match = '/^Key Slot \d+: ENABLED$/'; break;
|
||||
case 2: $match = '/^\s+\d+: luks2$/'; break;
|
||||
}
|
||||
}
|
||||
if ($match && preg_match($match,$row)) $slots++;
|
||||
}
|
||||
pclose($dump);
|
||||
if ($slots > 1) exec("cryptsetup luksRemoveKey /dev/$disk $key &>/dev/null");
|
||||
}
|
||||
function diskname($name) {
|
||||
global $disks;
|
||||
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;
|
||||
$reply = _var($_POST,'#reply');
|
||||
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);
|
||||
die();
|
||||
}
|
||||
|
||||
if (isset($_POST['oldinput'])) {
|
||||
switch ($_POST['oldinput']) {
|
||||
case 'text':
|
||||
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]));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
} else $error = 1;
|
||||
|
||||
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')));
|
||||
$luks = 'luksKey';
|
||||
$data = _var($_POST,'newluks');
|
||||
break;
|
||||
case 'file':
|
||||
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);
|
||||
}
|
||||
if (count($bad)==0) {
|
||||
// all okay, remove the old key
|
||||
foreach ($good as $disk) removeKey($oldkey,$disk);
|
||||
exec("emcmd 'changeDisk=apply&$luks=$data'");
|
||||
reply(_('Key successfully changed'),'success');
|
||||
} else {
|
||||
// something went wrong, restore key
|
||||
foreach ($good as $disk) removeKey($newkey,$disk);
|
||||
reply(_('Changing key failed for disks').': '.implode(' ',$bad),'error');
|
||||
}
|
||||
}
|
||||
reply(_('Missing new key'),'warning');
|
||||
?>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/beautify",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";function i(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../token_iterator").TokenIterator;t.singletonTags=["area","base","br","col","command","embed","hr","html","img","input","keygen","link","meta","param","source","track","wbr"],t.blockTags=["article","aside","blockquote","body","div","dl","fieldset","footer","form","head","header","html","nav","ol","p","script","section","style","table","tbody","tfoot","thead","ul"],t.formatOptions={lineBreaksAfterCommasInCurlyBlock:!0},t.beautify=function(e){var n=new r(e,0,0),s=n.getCurrentToken(),o=e.getTabString(),u=t.singletonTags,a=t.blockTags,f=t.formatOptions||{},l,c=!1,h=!1,p=!1,d="",v="",m="",g=0,y=0,b=0,w=0,E=0,S=0,x=0,T,N=0,C=0,k=[],L=!1,A,O=!1,M=!1,_=!1,D=!1,P={0:0},H=[],B=!1,j=function(){l&&l.value&&l.type!=="string.regexp"&&(l.value=l.value.replace(/^\s*/,""))},F=function(){var e=d.length-1;for(;;){if(e==0)break;if(d[e]!==" ")break;e-=1}d=d.slice(0,e+1)},I=function(){d=d.trimRight(),c=!1};while(s!==null){N=n.getCurrentTokenRow(),k=n.$rowTokens,l=n.stepForward();if(typeof s!="undefined"){v=s.value,E=0,_=m==="style"||e.$modeId==="ace/mode/css",i(s,"tag-open")?(M=!0,l&&(D=a.indexOf(l.value)!==-1),v==="</"&&(D&&!c&&C<1&&C++,_&&(C=1),E=1,D=!1)):i(s,"tag-close")?M=!1:i(s,"comment.start")?D=!0:i(s,"comment.end")&&(D=!1),!M&&!C&&s.type==="paren.rparen"&&s.value.substr(0,1)==="}"&&C++,N!==T&&(C=N,T&&(C-=T));if(C){I();for(;C>0;C--)d+="\n";c=!0,!i(s,"comment")&&!s.type.match(/^(comment|string)$/)&&(v=v.trimLeft())}if(v){s.type==="keyword"&&v.match(/^(if|else|elseif|for|foreach|while|switch)$/)?(H[g]=v,j(),p=!0,v.match(/^(else|elseif)$/)&&d.match(/\}[\s]*$/)&&(I(),h=!0)):s.type==="paren.lparen"?(j(),v.substr(-1)==="{"&&(p=!0,O=!1,M||(C=1)),v.substr(0,1)==="{"&&(h=!0,d.substr(-1)!=="["&&d.trimRight().substr(-1)==="["?(I(),h=!1):d.trimRight().substr(-1)===")"?I():F())):s.type==="paren.rparen"?(E=1,v.substr(0,1)==="}"&&(H[g-1]==="case"&&E++,d.trimRight().substr(-1)==="{"?I():(h=!0,_&&(C+=2))),v.substr(0,1)==="]"&&d.substr(-1)!=="}"&&d.trimRight().substr(-1)==="}"&&(h=!1,w++,I()),v.substr(0,1)===")"&&d.substr(-1)!=="("&&d.trimRight().substr(-1)==="("&&(h=!1,w++,I()),F()):s.type!=="keyword.operator"&&s.type!=="keyword"||!v.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)?s.type==="punctuation.operator"&&v===";"?(I(),j(),p=!0,_&&C++):s.type==="punctuation.operator"&&v.match(/^(:|,)$/)?(I(),j(),v.match(/^(,)$/)&&x>0&&S===0&&f.lineBreaksAfterCommasInCurlyBlock?C++:(p=!0,c=!1)):s.type==="support.php_tag"&&v==="?>"&&!c?(I(),h=!0):i(s,"attribute-name")&&d.substr(-1).match(/^\s$/)?h=!0:i(s,"attribute-equals")?(F(),j()):i(s,"tag-close")?(F(),v==="/>"&&(h=!0)):s.type==="keyword"&&v.match(/^(case|default)$/)&&B&&(E=1):(I(),j(),h=!0,p=!0);if(c&&(!s.type.match(/^(comment)$/)||!!v.substr(0,1).match(/^[/#]$/))&&(!s.type.match(/^(string)$/)||!!v.substr(0,1).match(/^['"@]$/))){w=b;if(g>y){w++;for(A=g;A>y;A--)P[A]=w}else g<y&&(w=P[g]);y=g,b=w,E&&(w-=E),O&&!S&&(w++,O=!1);for(A=0;A<w;A++)d+=o}s.type==="keyword"&&v.match(/^(case|default)$/)?B===!1&&(H[g]=v,g++,B=!0):s.type==="keyword"&&v.match(/^(break)$/)&&H[g-1]&&H[g-1].match(/^(case|default)$/)&&(g--,B=!1),s.type==="paren.lparen"&&(S+=(v.match(/\(/g)||[]).length,x+=(v.match(/\{/g)||[]).length,g+=v.length),s.type==="keyword"&&v.match(/^(if|else|elseif|for|while)$/)?(O=!0,S=0):!S&&v.trim()&&s.type!=="comment"&&(O=!1);if(s.type==="paren.rparen"){S-=(v.match(/\)/g)||[]).length,x-=(v.match(/\}/g)||[]).length;for(A=0;A<v.length;A++)g--,v.substr(A,1)==="}"&&H[g]==="case"&&g--}s.type=="text"&&(v=v.replace(/\s+$/," ")),h&&!c&&(F(),d.substr(-1)!=="\n"&&(d+=" ")),d+=v,p&&(d+=" "),c=!1,h=!1,p=!1;if(i(s,"tag-close")&&(D||a.indexOf(m)!==-1)||i(s,"doctype")&&v===">")D&&l&&l.value==="</"?C=-1:C=1;l&&u.indexOf(l.value)===-1&&(i(s,"tag-open")&&v==="</"?g--:i(s,"tag-open")&&v==="<"?g++:i(s,"tag-close")&&v==="/>"&&g--),i(s,"tag-name")&&(m=v),T=N}}s=l}d=d.trim(),e.doc.setValue(d)},t.commands=[{name:"beautify",description:"Format selection (Beautify)",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]}); (function() {
|
||||
window.require(["ace/ext/beautify"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/code_lens",["require","exports","module","ace/line_widgets","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/editor","ace/config"],function(e,t,n){"use strict";function u(e){var t=e.$textLayer,n=t.$lenses;n&&n.forEach(function(e){e.remove()}),t.$lenses=null}function a(e,t){var n=e&t.CHANGE_LINES||e&t.CHANGE_FULL||e&t.CHANGE_SCROLL||e&t.CHANGE_TEXT;if(!n)return;var r=t.session,i=t.session.lineWidgets,s=t.$textLayer,a=s.$lenses;if(!i){a&&u(t);return}var f=t.$textLayer.$lines.cells,l=t.layerConfig,c=t.$padding;a||(a=s.$lenses=[]);var h=0;for(var p=0;p<f.length;p++){var d=f[p].row,v=i[d],m=v&&v.lenses;if(!m||!m.length)continue;var g=a[h];g||(g=a[h]=o.buildDom(["div",{"class":"ace_codeLens"}],t.container)),g.style.height=l.lineHeight+"px",h++;for(var y=0;y<m.length;y++){var b=g.childNodes[2*y];b||(y!=0&&g.appendChild(o.createTextNode("\u00a0|\u00a0")),b=o.buildDom(["a"],g)),b.textContent=m[y].title,b.lensCommand=m[y]}while(g.childNodes.length>2*y-1)g.lastChild.remove();var w=t.$cursorLayer.getPixelPosition({row:d,column:0},!0).top-l.lineHeight*v.rowsAbove-l.offset;g.style.top=w+"px";var E=t.gutterWidth,S=r.getLine(d).search(/\S|$/);S==-1&&(S=0),E+=S*l.characterWidth,g.style.paddingLeft=c+E+"px"}while(h<a.length)a.pop().remove()}function f(e){if(!e.lineWidgets)return;var t=e.widgetManager;e.lineWidgets.forEach(function(e){e&&e.lenses&&t.removeLineWidget(e)})}function l(e){e.codeLensProviders=[],e.renderer.on("afterRender",a),e.$codeLensClickHandler||(e.$codeLensClickHandler=function(t){var n=t.target.lensCommand;if(!n)return;e.execCommand(n.id,n.arguments),e._emit("codeLensClick",t)},i.addListener(e.container,"click",e.$codeLensClickHandler,e)),e.$updateLenses=function(){function o(){var r=n.selection.cursor,i=n.documentToScreenRow(r),o=n.getScrollTop(),u=t.setLenses(n,s),a=n.$undoManager&&n.$undoManager.$lastDelta;if(a&&a.action=="remove"&&a.lines.length>1)return;var f=n.documentToScreenRow(r),l=e.renderer.layerConfig.lineHeight,c=n.getScrollTop()+(f-i)*l;u==0&&o<l/4&&o>-l/4&&(c=-l),n.setScrollTop(c)}var n=e.session;if(!n)return;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var i=e.codeLensProviders.length,s=[];e.codeLensProviders.forEach(function(e){e.provideCodeLenses(n,function(e,t){if(e)return;t.forEach(function(e){s.push(e)}),i--,i==0&&o()})})};var n=s.delayedCall(e.$updateLenses);e.$updateLensesOnInput=function(){n.delay(250)},e.on("input",e.$updateLensesOnInput)}function c(e){e.off("input",e.$updateLensesOnInput),e.renderer.off("afterRender",a),e.$codeLensClickHandler&&e.container.removeEventListener("click",e.$codeLensClickHandler)}var r=e("../line_widgets").LineWidgets,i=e("../lib/event"),s=e("../lib/lang"),o=e("../lib/dom");t.setLenses=function(e,t){var n=Number.MAX_VALUE;return f(e),t&&t.forEach(function(t){var r=t.start.row,i=t.start.column,s=e.lineWidgets&&e.lineWidgets[r];if(!s||!s.lenses)s=e.widgetManager.$registerLineWidget({rowCount:1,rowsAbove:1,row:r,column:i,lenses:[]});s.lenses.push(t.command),r<n&&(n=r)}),e._emit("changeFold",{data:{start:{row:n}}}),n},t.registerCodeLensProvider=function(e,t){e.setOption("enableCodeLens",!0),e.codeLensProviders.push(t),e.$updateLensesOnInput()},t.clear=function(e){t.setLenses(e,null)};var h=e("../editor").Editor;e("../config").defineOptions(h.prototype,"editor",{enableCodeLens:{set:function(e){e?l(this):c(this)}}}),o.importCssString("\n.ace_codeLens {\n position: absolute;\n color: #aaa;\n font-size: 88%;\n background: inherit;\n width: 100%;\n display: flex;\n align-items: flex-end;\n pointer-events: none;\n}\n.ace_codeLens > a {\n cursor: pointer;\n pointer-events: auto;\n}\n.ace_codeLens > a:hover {\n color: #0000ff;\n text-decoration: underline;\n}\n.ace_dark > .ace_codeLens > a:hover {\n color: #4e94ce;\n}\n","codelense.css",!1)}); (function() {
|
||||
window.require(["ace/ext/code_lens"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})}); (function() {
|
||||
window.require(["ace/ext/elastic_tabstops_lite"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
; (function() {
|
||||
window.require(["ace/ext/error_marker"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/hardwrap",["require","exports","module","ace/range","ace/editor","ace/config"],function(e,t,n){"use strict";function i(e,t){function m(e,t,n){if(e.length<t)return;var r=e.slice(0,t),i=e.slice(t),s=/^(?:(\s+)|(\S+)(\s+))/.exec(i),o=/(?:(\s+)|(\s+)(\S+))$/.exec(r),u=0,a=0;o&&!o[2]&&(u=t-o[1].length,a=t),s&&!s[2]&&(u||(u=t),a=t+s[1].length);if(u)return{start:u,end:a};if(o&&o[2]&&o.index>n)return{start:o.index,end:o.index+o[2].length};if(s&&s[2])return u=t+s[2].length,{start:u,end:u+s[3].length}}var n=t.column||e.getOption("printMarginColumn"),i=t.allowMerge!=0,s=Math.min(t.startRow,t.endRow),o=Math.max(t.startRow,t.endRow),u=e.session;while(s<=o){var a=u.getLine(s);if(a.length>n){var f=m(a,n,5);if(f){var l=/^\s*/.exec(a)[0];u.replace(new r(s,f.start,s,f.end),"\n"+l)}o++}else if(i&&/\S/.test(a)&&s!=o){var c=u.getLine(s+1);if(c&&/\S/.test(c)){var h=a.replace(/\s+$/,""),p=c.replace(/^\s+/,""),d=h+" "+p,f=m(d,n,5);if(f&&f.start>h.length||d.length<n){var v=new r(s,h.length,s+1,c.length-p.length);u.replace(v," "),s--,o--}else h.length<a.length&&u.remove(new r(s,h.length,s,a.length))}}s++}}function s(e){if(e.command.name=="insertstring"&&/\S/.test(e.args)){var t=e.editor,n=t.selection.cursor;if(n.column<=t.renderer.$printMarginColumn)return;var r=t.session.$undoManager.$lastDelta;i(t,{startRow:n.row,endRow:n.row,allowMerge:!1}),r!=t.session.$undoManager.$lastDelta&&t.session.markUndoGroup()}}var r=e("../range").Range,o=e("../editor").Editor;e("../config").defineOptions(o.prototype,"editor",{hardWrap:{set:function(e){e?this.commands.on("afterExec",s):this.commands.off("afterExec",s)},value:!1}}),t.hardWrap=i}); (function() {
|
||||
window.require(["ace/ext/hardwrap"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/menu_tools/settings_menu.css",["require","exports","module"],function(e,t,n){n.exports="#ace_settingsmenu, #kbshortcutmenu {\n background-color: #F7F7F7;\n color: black;\n box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\n padding: 1em 0.5em 2em 1em;\n overflow: auto;\n position: absolute;\n margin: 0;\n bottom: 0;\n right: 0;\n top: 0;\n z-index: 9991;\n cursor: default;\n}\n\n.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\n box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\n background-color: rgba(255, 255, 255, 0.6);\n color: black;\n}\n\n.ace_optionsMenuEntry:hover {\n background-color: rgba(100, 100, 100, 0.1);\n transition: all 0.3s\n}\n\n.ace_closeButton {\n background: rgba(245, 146, 146, 0.5);\n border: 1px solid #F48A8A;\n border-radius: 50%;\n padding: 7px;\n position: absolute;\n right: -8px;\n top: -8px;\n z-index: 100000;\n}\n.ace_closeButton{\n background: rgba(245, 146, 146, 0.9);\n}\n.ace_optionsMenuKey {\n color: darkslateblue;\n font-weight: bold;\n}\n.ace_optionsMenuCommand {\n color: darkcyan;\n font-weight: normal;\n}\n.ace_optionsMenuEntry input, .ace_optionsMenuEntry button {\n vertical-align: middle;\n}\n\n.ace_optionsMenuEntry button[ace_selected_button=true] {\n background: #e7e7e7;\n box-shadow: 1px 0px 2px 0px #adadad inset;\n border-color: #adadad;\n}\n.ace_optionsMenuEntry button {\n background: white;\n border: 1px solid lightgray;\n margin: 0px;\n}\n.ace_optionsMenuEntry button:hover{\n background: #f0f0f0;\n}"}),define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom","ace/ext/menu_tools/settings_menu.css"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i=e("./settings_menu.css");r.importCssString(i,"settings_menu.css",!1),n.exports.overlayPage=function(t,n,r){function o(e){e.keyCode===27&&u()}function u(){if(!i)return;document.removeEventListener("keydown",o),i.parentNode.removeChild(i),t&&t.focus(),i=null,r&&r()}function a(e){s=e,e&&(i.style.pointerEvents="none",n.style.pointerEvents="auto")}var i=document.createElement("div"),s=!1;return i.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; "+(t?"background-color: rgba(0, 0, 0, 0.3);":""),i.addEventListener("click",function(e){s||u()}),document.addEventListener("keydown",o),n.addEventListener("click",function(e){e.stopPropagation()}),i.appendChild(n),document.body.appendChild(i),t&&t.blur(),{close:u,setIgnoreFocusOut:a}}}),define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var t=e.commandKeyBinding;for(var r in t){var s=r.replace(/(^|-)\w/g,function(e){return e.toUpperCase()}),o=t[r];Array.isArray(o)||(o=[o]),o.forEach(function(e){typeof e!="string"&&(e=e.name),i[e]?i[e].key+="|"+s:(i[e]={key:s,command:e},n.push(i[e]))})}}),n}}),define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){"use strict";function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'+t.command+"</span> : "+'<span class="ace_optionsMenuKey">'+t.key+"</span></div>"},"");s.id="kbshortcutmenu",s.innerHTML="<h1>Keyboard Shortcuts</h1>"+o+"</div>",n(t,s)}}var r=e("../editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}}); (function() {
|
||||
window.require(["ace/ext/keybinding_menu"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var n=e.editor,r=e.getAccelKey();if(r){var n=e.editor,i=e.getDocumentPosition(),s=n.session,o=s.getTokenAt(i.row,i.column);t.previousLinkingHover&&t.previousLinkingHover!=o&&n._emit("linkHoverOut"),n._emit("linkHover",{position:i,token:o}),t.previousLinkingHover=o}else t.previousLinkingHover&&(n._emit("linkHoverOut"),t.previousLinkingHover=!1)}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("../editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}}),t.previousLinkingHover=!1}); (function() {
|
||||
window.require(["ace/ext/linking"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Alda:["alda"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],Apex:["apex|cls|trigger|tgr"],AQL:["aql"],AsciiDoc:["asciidoc|adoc"],ASL:["dsl|asl|asl.json"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],BibTeX:["bib"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],Crystal:["cr"],CSharp:["cs"],Csound_Document:["csd"],Csound_Orchestra:["orc"],Csound_Score:["sco"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Drools:["drl"],Edifact:["edi"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr|fth|4th"],Fortran:["f|f90"],FSharp:["fsi|fs|ml|mli|fsx|fsscript"],FSL:["fsl"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],GraphQLSchema:["gql"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],Haskell_Cabal:["cabal"],haXe:["hx"],Hjson:["hjson"],HTML:["html|htm|xhtml|vue|we|wpy"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Ion:["ion"],Jack:["jack"],Jade:["jade|pug"],Java:["java"],JavaScript:["js|jsm|jsx|cjs|mjs"],JEXL:["jexl"],JSON:["json"],JSON5:["json5"],JSONiq:["jq"],JSP:["jsp"],JSSM:["jssm|jssm_state"],JSX:["jsx"],Julia:["jl"],Kotlin:["kt|kts"],LaTeX:["tex|latex|ltx|bib"],Latte:["latte"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],Log:["log"],LogiQL:["logic|lql"],Logtalk:["lgt"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MediaWiki:["wiki|mediawiki"],MEL:["mel"],MIPS:["s|asm"],MIXAL:["mixal"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nginx:["nginx|conf"],Nim:["nim"],Nix:["nix"],NSIS:["nsi|nsh"],Nunjucks:["nunjucks|nunjs|nj|njk"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],PartiQL:["partiql|pql"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],PHP_Laravel_blade:["blade.php"],Pig:["pig"],PLSQL:["plsql"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prisma:["prisma"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Puppet:["epp|pp"],Python:["py"],QML:["qml"],R:["r"],Raku:["raku|rakumod|rakutest|p6|pl6|pm6"],Razor:["cshtml|asp"],RDoc:["Rd"],Red:["red|reds"],RHTML:["Rhtml"],Robot:["robot|resource"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SaC:["sac"],SASS:["sass"],SCAD:["scad"],Scala:["scala|sbt"],Scheme:["scm|sm|rkt|oak|scheme"],Scrypt:["scrypt"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Slim:["slim|skim"],Smarty:["smarty|tpl"],Smithy:["smithy"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SPARQL:["rq"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Terraform:["tf","tfvars","terragrunt"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],TSX:["tsx"],Turtle:["ttl"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Visualforce:["vfp|component|page"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Zeek:["zeek|bro"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",Csound_Document:"Csound Document",Csound_Orchestra:"Csound",Csound_Score:"Csound Score",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker",PHP_Laravel_blade:"PHP (Blade Template)",Perl6:"Perl 6",AutoHotKey:"AutoHotkey / AutoIt"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}}); (function() {
|
||||
window.require(["ace/ext/modelist"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/rtl",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";function s(e,t){var n=t.getSelection().lead;t.session.$bidiHandler.isRtlLine(n.row)&&n.column===0&&(t.session.$bidiHandler.isMoveLeftOperation&&n.row>0?t.getSelection().moveCursorTo(n.row-1,t.session.getLine(n.row-1).length):t.getSelection().isEmpty()?n.column+=1:n.setPosition(n.row,n.column+1))}function o(e){e.editor.session.$bidiHandler.isMoveLeftOperation=/gotoleft|selectleft|backspace|removewordleft/.test(e.command.name)}function u(e,t){var n=t.session;n.$bidiHandler.currentRow=null;if(n.$bidiHandler.isRtlLine(e.start.row)&&e.action==="insert"&&e.lines.length>1)for(var r=e.start.row;r<e.end.row;r++)n.getLine(r+1).charAt(0)!==n.$bidiHandler.RLE&&(n.doc.$lines[r+1]=n.$bidiHandler.RLE+n.getLine(r+1))}function a(e,t){var n=t.session,r=n.$bidiHandler,i=t.$textLayer.$lines.cells,s=t.layerConfig.width-t.layerConfig.padding+"px";i.forEach(function(e){var t=e.element.style;r&&r.isRtlLine(e.row)?(t.direction="rtl",t.textAlign="right",t.width=s):(t.direction="",t.textAlign="",t.width="")})}function f(e){function n(e){var t=e.element.style;t.direction=t.textAlign=t.width=""}var t=e.$textLayer.$lines;t.cells.forEach(n),t.cellCache.forEach(n)}var r=[{name:"leftToRight",bindKey:{win:"Ctrl-Alt-Shift-L",mac:"Command-Alt-Shift-L"},exec:function(e){e.session.$bidiHandler.setRtlDirection(e,!1)},readOnly:!0},{name:"rightToLeft",bindKey:{win:"Ctrl-Alt-Shift-R",mac:"Command-Alt-Shift-R"},exec:function(e){e.session.$bidiHandler.setRtlDirection(e,!0)},readOnly:!0}],i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{rtlText:{set:function(e){e?(this.on("change",u),this.on("changeSelection",s),this.renderer.on("afterRender",a),this.commands.on("exec",o),this.commands.addCommands(r)):(this.off("change",u),this.off("changeSelection",s),this.renderer.off("afterRender",a),this.commands.off("exec",o),this.commands.removeCommands(r),f(this.renderer)),this.renderer.updateFull()}},rtl:{set:function(e){this.session.$bidiHandler.$isRtl=e,e?(this.setOption("rtlText",!1),this.renderer.on("afterRender",a),this.session.$bidiHandler.seenBidi=!0):(this.renderer.off("afterRender",a),f(this.renderer)),this.renderer.updateFull()}}})}); (function() {
|
||||
window.require(["ace/ext/rtl"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="\x01\x01",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})}); (function() {
|
||||
window.require(["ace/ext/spellcheck"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();return t.setUndoManager(n),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),t.Split=f}),define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){"use strict";n.exports=e("../split")}); (function() {
|
||||
window.require(["ace/ext/split"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/static.css",["require","exports","module"],function(e,t,n){n.exports=".ace_static_highlight {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;\n font-size: 12px;\n white-space: pre-wrap\n}\n\n.ace_static_highlight .ace_gutter {\n width: 2em;\n text-align: right;\n padding: 0 3px 0 0;\n margin-right: 3px;\n contain: none;\n}\n\n.ace_static_highlight.ace_show_gutter .ace_line {\n padding-left: 2.6em;\n}\n\n.ace_static_highlight .ace_line { position: relative; }\n\n.ace_static_highlight .ace_gutter-cell {\n -moz-user-select: -moz-none;\n -khtml-user-select: none;\n -webkit-user-select: none;\n user-select: none;\n top: 0;\n bottom: 0;\n left: 0;\n position: absolute;\n}\n\n\n.ace_static_highlight .ace_gutter-cell:before {\n content: counter(ace_line, decimal);\n counter-increment: ace_line;\n}\n.ace_static_highlight {\n counter-reset: ace_line;\n}\n"}),define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/ext/static.css","ace/config","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";function f(e){this.type=e,this.style={},this.textContent=""}var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=e("./static.css"),o=e("../config"),u=e("../lib/dom"),a=e("../lib/lang").escapeHTML;f.prototype.cloneNode=function(){return this},f.prototype.appendChild=function(e){this.textContent+=e.toString()},f.prototype.toString=function(){var e=[];if(this.type!="fragment"){e.push("<",this.type),this.className&&e.push(" class='",this.className,"'");var t=[];for(var n in this.style)t.push(n,":",this.style[n]);t.length&&e.push(" style='",t.join(""),"'"),e.push(">")}return this.textContent&&e.push(this.textContent),this.type!="fragment"&&e.push("</",this.type,">"),e.join("")};var l={createTextNode:function(e,t){return a(e)},createElement:function(e){return new f(e)},createFragment:function(){return new f("fragment")}},c=function(){this.config={},this.dom=l};c.prototype=i.prototype;var h=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",a=[];if(e.firstElementChild){var f=0;for(var l=0;l<e.childNodes.length;l++){var c=e.childNodes[l];c.nodeType==3?(f+=c.data.length,o+=c.data):a.push(f,c)}}else o=e.textContent,t.trim&&(o=o.trim());h.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<a.length;i+=2){var s=t.session.doc.indexToPosition(a[i]),o=a[i+1],f=r.children[s.row];f&&f.appendChild(o)}n&&n()})};h.render=function(e,t,n,i,s,u){function c(){var r=h.renderSync(e,t,n,i,s);return u?u(r):r}var a=1,f=r.prototype.$modes;typeof n=="string"&&(a++,o.loadModule(["theme",n],function(e){n=e,--a||c()}));var l;return t&&typeof t=="object"&&!t.getTokenizer&&(l=t,t=l.path),typeof t=="string"&&(a++,o.loadModule(["mode",t],function(e){if(!f[t]||l)f[t]=new e.Mode(l);t=f[t],--a||c()})),--a||c()},h.renderSync=function(e,t,n,i,o){i=parseInt(i||1,10);var u=new r("");u.setUseWorker(!1),u.setMode(t);var a=new c;a.setSession(u),Object.keys(a.$tabStrings).forEach(function(e){if(typeof a.$tabStrings[e]=="string"){var t=l.createFragment();t.textContent=a.$tabStrings[e],a.$tabStrings[e]=t}}),u.setValue(e);var f=u.getLength(),h=l.createElement("div");h.className=n.cssClass;var p=l.createElement("div");p.className="ace_static_highlight"+(o?"":" ace_show_gutter"),p.style["counter-reset"]="ace_line "+(i-1);for(var d=0;d<f;d++){var v=l.createElement("div");v.className="ace_line";if(!o){var m=l.createElement("span");m.className="ace_gutter ace_gutter-cell",m.textContent="",v.appendChild(m)}a.$renderLine(v,d,!1),v.textContent+="\n",p.appendChild(v)}return h.appendChild(p),{css:s+n.cssText,html:h.toString(),session:u}},n.exports=h,n.exports.highlight=h}); (function() {
|
||||
window.require(["ace/ext/static_highlight"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this)).schedule.bind(null,100);e.on("changeStatus",n),e.on("changeSelection",n),e.on("keyboardActivity",n)};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];n(e.keyBinding.getStatusText(e)),e.commands.recording&&n("REC");var r=e.selection,i=r.lead;if(!r.isEmpty()){var s=e.getSelectionRange();n("("+(s.end.row-s.start.row)+":"+(s.end.column-s.start.column)+")"," ")}n(i.row+":"+i.column," "),r.rangeCount&&n("["+r.rangeCount+"]"," "),t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s}); (function() {
|
||||
window.require(["ace/ext/statusbar"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/themelist",["require","exports","module"],function(e,t,n){"use strict";var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Dracula","","dark"],["Cobalt","cobalt","dark"],["Gruvbox","gruvbox","dark"],["Green on Black","gob","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Nord Dark","nord_dark","dark"],["One Dark","one_dark","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})}); (function() {
|
||||
window.require(["ace/ext/themelist"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang");t.$detectIndentation=function(e,t){function c(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;if(a[0]==" ")i++,s=-Number.MAX_VALUE;else{var f=a.match(/^ */)[0].length;if(f&&a[f]!=" "){var l=f-s;l>0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(u<o&&a[a.length-1]=="\\")a=e[u++]}var h=r.reduce(function(e,t){return e+t},0),p={score:0,length:0},d=0;for(var u=1;u<12;u++){var v=c(u);u==1?(d=v,v=n[1]?.9:.8,n.length||(v=0)):v/=d,r[u]&&(v+=r[u]/h),v>p.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||d<i/4||p.score<1.8)m=undefined;return{ch:" ",length:m}}if(d>i+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t&&t.trimEmpty?-1:0,s=[],o=-1;t&&t.keepCursorPosition&&(e.selection.rangeCount?e.selection.rangeList.ranges.forEach(function(e,t,n){var r=n[t+1];if(r&&r.cursor.row==e.cursor.row)return;s.push(e.cursor)}):s.push(e.selection.getCursor()),o=0);var u=s[o]&&s[o].row;for(var a=0,f=r.length;a<f;a++){var l=r[a],c=l.search(/\s+$/);a==u&&(c<s[o].column&&c>i&&(c=s[o].column),o++,u=s[o]?s[o].row:-1),c>i&&n.removeInLine(a,c,l.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch=" ":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",description:"Detect indentation from content",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",description:"Trim trailing whitespace",exec:function(e,n){t.trimTrailingSpace(e.session,n)}},{name:"convertIndentation",description:"Convert indentation to ...",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",description:"Set indentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]}); (function() {
|
||||
window.require(["ace/ext/whitespace"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/abc_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:["zupfnoter.information.comment.line.percentage","information.keyword","in formation.keyword.embedded"],regex:"(%%%%)(hn\\.[a-z]*)(.*)",comment:"Instruction Comment"},{token:["information.comment.line.percentage","information.keyword.embedded"],regex:"(%%)(.*)",comment:"Instruction Comment"},{token:"comment.line.percentage",regex:"%.*",comment:"Comments"},{token:"barline.keyword.operator",regex:"[\\[:]*[|:][|\\]:]*(?:\\[?[0-9]+)?|\\[[0-9]+",comment:"Bar lines"},{token:["information.keyword.embedded","information.argument.string.unquoted"],regex:"(\\[[A-Za-z]:)([^\\]]*\\])",comment:"embedded Header lines"},{token:["information.keyword","information.argument.string.unquoted"],regex:"^([A-Za-z]:)([^%\\\\]*)",comment:"Header lines"},{token:["text","entity.name.function","string.unquoted","text"],regex:"(\\[)([A-Z]:)(.*?)(\\])",comment:"Inline fields"},{token:["accent.constant.language","pitch.constant.numeric","duration.constant.numeric"],regex:"([\\^=_]*)([A-Ga-gz][,']*)([0-9]*/*[><0-9]*)",comment:"Notes"},{token:"zupfnoter.jumptarget.string.quoted",regex:'[\\"!]\\^\\:.*?[\\"!]',comment:"Zupfnoter jumptarget"},{token:"zupfnoter.goto.string.quoted",regex:'[\\"!]\\^\\@.*?[\\"!]',comment:"Zupfnoter goto"},{token:"zupfnoter.annotation.string.quoted",regex:'[\\"!]\\^\\!.*?[\\"!]',comment:"Zupfnoter annoation"},{token:"zupfnoter.annotationref.string.quoted",regex:'[\\"!]\\^\\#.*?[\\"!]',comment:"Zupfnoter annotation reference"},{token:"chordname.string.quoted",regex:'[\\"!]\\^.*?[\\"!]',comment:"abc chord"},{token:"string.quoted",regex:'[\\"!].*?[\\"!]',comment:"abc annotation"}]},this.normalizeRules()};s.metaData={fileTypes:["abc"],name:"ABC",scopeName:"text.abcnotation"},r.inherits(s,i),t.ABCHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/abc",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/abc_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./abc_highlight_rules").ABCHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="%",this.$id="ace/mode/abc",this.snippetFileId="ace/snippets/abc"}.call(u.prototype),t.Mode=u}); (function() {
|
||||
window.require(["ace/mode/abc"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/ada_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="abort|else|new|return|abs|elsif|not|reverse|abstract|end|null|accept|entry|select|access|exception|of|separate|aliased|exit|or|some|all|others|subtype|and|for|out|synchronized|array|function|overriding|at|tagged|generic|package|task|begin|goto|pragma|terminate|body|private|then|if|procedure|type|case|in|protected|constant|interface|until||is|raise|use|declare|range|delay|limited|record|when|delta|loop|rem|while|digits|renames|with|do|mod|requeue|xor",t="true|false|null",n="count|min|max|avg|sum|rank|now|coalesce|main",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]}};r.inherits(s,i),t.AdaHighlightRules=s}),define("ace/mode/ada",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/ada_highlight_rules","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./ada_highlight_rules").AdaHighlightRules,o=e("../range").Range,u=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="--",this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"){var o=t.match(/^.*(begin|loop|then|is|do)\s*$/);o&&(r+=n)}return r},this.checkOutdent=function(e,t,n){var r=t+n;return r.match(/^\s*(begin|end)$/)?!0:!1},this.autoOutdent=function(e,t,n){var r=t.getLine(n),i=t.getLine(n-1),s=this.$getIndent(i).length,u=this.$getIndent(r).length;if(u<=s)return;t.outdentRows(new o(n,0,n+2,0))},this.$id="ace/mode/ada"}.call(u.prototype),t.Mode=u}); (function() {
|
||||
window.require(["ace/mode/ada"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/aql_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="for|return|filter|search|sort|limit|let|collect|asc|desc|in|into|insert|update|remove|replace|upsert|options|with|and|or|not|distinct|graph|shortest_path|outbound|inbound|any|all|none|at least|aggregate|like|k_shortest_paths|k_paths|all_shortest_paths|prune|window",t="true|false",n="to_bool|to_number|to_string|to_array|to_list|is_null|is_bool|is_number|is_string|is_array|is_list|is_object|is_document|is_datestring|typename|json_stringify|json_parse|concat|concat_separator|char_length|lower|upper|substring|left|right|trim|reverse|contains|log|log2|log10|exp|exp2|sin|cos|tan|asin|acos|atan|atan2|radians|degrees|pi|regex_test|regex_replace|like|floor|ceil|round|abs|rand|sqrt|pow|length|count|min|max|average|avg|sum|product|median|variance_population|variance_sample|variance|percentile|bit_and|bit_or|bit_xor|bit_negate|bit_test|bit_popcount|bit_shift_left|bit_shift_right|bit_construct|bit_deconstruct|bit_to_string|bit_from_string|first|last|unique|outersection|interleave|in_range|jaccard|matches|merge|merge_recursive|has|attributes|keys|values|unset|unset_recursive|keep|keep_recursive|near|within|within_rectangle|is_in_polygon|distance|fulltext|stddev_sample|stddev_population|stddev|slice|nth|position|contains_array|translate|zip|call|apply|push|append|pop|shift|unshift|remove_value|remove_values|remove_nth|replace_nth|date_now|date_timestamp|date_iso8601|date_dayofweek|date_year|date_month|date_day|date_hour|date_minute|date_second|date_millisecond|date_dayofyear|date_isoweek|date_isoweekyear|date_leapyear|date_quarter|date_days_in_month|date_trunc|date_round|date_add|date_subtract|date_diff|date_compare|date_format|date_utctolocal|date_localtoutc|date_timezone|date_timezones|fail|passthru|v8|sleep|schema_get|schema_validate|shard_id|call_greenspun|version|noopt|noeval|not_null|first_list|first_document|parse_identifier|current_user|current_database|collection_count|pregel_result|collections|document|decode_rev|range|union|union_distinct|minus|intersection|flatten|is_same_collection|check_document|ltrim|rtrim|find_first|find_last|split|substitute|ipv4_to_number|ipv4_from_number|is_ipv4|md5|sha1|sha512|crc32|fnv64|hash|random_token|to_base64|to_hex|encode_uri_component|soundex|assert|warn|is_key|sorted|sorted_unique|count_distinct|count_unique|levenshtein_distance|levenshtein_match|regex_matches|regex_split|ngram_match|ngram_similarity|ngram_positional_similarity|uuid|tokens|exists|starts_with|phrase|min_match|bm25|tfidf|boost|analyzer|cosine_similarity|decay_exp|decay_gauss|decay_linear|l1_distance|l2_distance|minhash|minhash_count|minhash_error|minhash_match|geo_point|geo_multipoint|geo_polygon|geo_multipolygon|geo_linestring|geo_multilinestring|geo_contains|geo_intersects|geo_equals|geo_distance|geo_area|geo_in_range",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"//.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]},this.normalizeRules()};r.inherits(s,i),t.AqlHighlightRules=s}),define("ace/mode/aql",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/aql_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./aql_highlight_rules").AqlHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="//",this.$id="ace/mode/aql"}.call(o.prototype),t.Mode=o}); (function() {
|
||||
window.require(["ace/mode/aql"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/batchfile_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"keyword.command.dosbatch",regex:"\\b(?:append|assoc|at|attrib|break|cacls|cd|chcp|chdir|chkdsk|chkntfs|cls|cmd|color|comp|compact|convert|copy|date|del|dir|diskcomp|diskcopy|doskey|echo|endlocal|erase|fc|find|findstr|format|ftype|graftabl|help|keyb|label|md|mkdir|mode|more|move|path|pause|popd|print|prompt|pushd|rd|recover|ren|rename|replace|restore|rmdir|set|setlocal|shift|sort|start|subst|time|title|tree|type|ver|verify|vol|xcopy)\\b",caseInsensitive:!0},{token:"keyword.control.statement.dosbatch",regex:"\\b(?:goto|call|exit)\\b",caseInsensitive:!0},{token:"keyword.control.conditional.if.dosbatch",regex:"\\bif\\s+not\\s+(?:exist|defined|errorlevel|cmdextversion)\\b",caseInsensitive:!0},{token:"keyword.control.conditional.dosbatch",regex:"\\b(?:if|else)\\b",caseInsensitive:!0},{token:"keyword.control.repeat.dosbatch",regex:"\\bfor\\b",caseInsensitive:!0},{token:"keyword.operator.dosbatch",regex:"\\b(?:EQU|NEQ|LSS|LEQ|GTR|GEQ)\\b"},{token:["doc.comment","comment"],regex:"(?:^|\\b)(rem)($|\\s.*$)",caseInsensitive:!0},{token:"comment.line.colons.dosbatch",regex:"::.*$"},{include:"variable"},{token:"punctuation.definition.string.begin.shell",regex:'"',push:[{token:"punctuation.definition.string.end.shell",regex:'"',next:"pop"},{include:"variable"},{defaultToken:"string.quoted.double.dosbatch"}]},{token:"keyword.operator.pipe.dosbatch",regex:"[|]"},{token:"keyword.operator.redirect.shell",regex:"&>|\\d*>&\\d*|\\d*(?:>>|>|<)|\\d*<&|\\d*<>"}],variable:[{token:"constant.numeric",regex:"%%\\w+|%[*\\d]|%\\w+%"},{token:"constant.numeric",regex:"%~\\d+"},{token:["markup.list","constant.other","markup.list"],regex:"(%)(\\w+)(%?)"}]},this.normalizeRules()};s.metaData={name:"Batch File",scopeName:"source.dosbatch",fileTypes:["bat"]},r.inherits(s,i),t.BatchFileHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/batchfile",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/batchfile_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./batchfile_highlight_rules").BatchFileHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="::",this.blockComment="",this.$id="ace/mode/batchfile"}.call(u.prototype),t.Mode=u}); (function() {
|
||||
window.require(["ace/mode/batchfile"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/bibtex_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:/@Comment\{/,stateName:"bibtexComment",push:[{token:"comment",regex:/}/,next:"pop"},{token:"comment",regex:/\{/,push:"bibtexComment"},{defaultToken:"comment"}]},{token:["keyword","text","paren.lparen","text","variable","text","keyword.operator"],regex:/(@String)(\s*)(\{)(\s*)([a-zA-Z]*)(\s*)(=)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen","text","variable","text","keyword.operator"],regex:/(@String)(\s*)(\()(\s*)([a-zA-Z]*)(\s*)(=)/,push:[{token:"paren.rparen",regex:/\)/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen"],regex:/(@preamble)(\s*)(\()/,push:[{token:"paren.rparen",regex:/\)/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen"],regex:/(@preamble)(\s*)(\{)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{include:"#misc"},{defaultToken:"text"}]},{token:["keyword","text","paren.lparen","text","support.class"],regex:/(@[a-zA-Z]+)(\s*)(\{)(\s*)([\w-]+)/,push:[{token:"paren.rparen",regex:/\}/,next:"pop"},{token:["variable","text","keyword.operator"],regex:/([a-zA-Z0-9\!\$\&\*\+\-\.\/\:\;\<\>\?\[\]\^\_\`\|]+)(\s*)(=)/,push:[{token:"text",regex:/(?=[,}])/,next:"pop"},{include:"#misc"},{include:"#integer"},{defaultToken:"text"}]},{token:"punctuation",regex:/,/},{defaultToken:"text"}]},{defaultToken:"comment"}],"#integer":[{token:"constant.numeric.bibtex",regex:/\d+/}],"#misc":[{token:"string",regex:/"/,push:"#string_quotes"},{token:"paren.lparen",regex:/\{/,push:"#string_braces"},{token:"keyword.operator",regex:/#/}],"#string_braces":[{token:"paren.rparen",regex:/\}/,next:"pop"},{token:"invalid.illegal",regex:/@/},{include:"#misc"},{defaultToken:"string"}],"#string_quotes":[{token:"string",regex:/"/,next:"pop"},{include:"#misc"},{defaultToken:"string"}]},this.normalizeRules()};r.inherits(s,i),t.BibTeXHighlightRules=s}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/bibtex",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/bibtex_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./bibtex_highlight_rules").BibTeXHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.$id="ace/mode/bibtex"}.call(u.prototype),t.Mode=u}); (function() {
|
||||
window.require(["ace/mode/bibtex"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/c9search_highlight_rules",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";function o(e,t){try{return new RegExp(e,t)}catch(n){}}var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text_highlight_rules").TextHighlightRules,u=function(){this.$rules={start:[{tokenNames:["c9searchresults.constant.numeric","c9searchresults.text","c9searchresults.text","c9searchresults.keyword"],regex:/(^\s+[0-9]+)(:)(\d*\s?)([^\r\n]+)/,onMatch:function(e,t,n){var r=this.splitRegex.exec(e),i=this.tokenNames,s=[{type:i[0],value:r[1]},{type:i[1],value:r[2]}];r[3]&&(r[3]==" "?s[1]={type:i[1],value:r[2]+" "}:s.push({type:i[1],value:r[3]}));var o=n[1],u=r[4],a,f=0;if(o&&o.exec){o.lastIndex=0;while(a=o.exec(u)){var l=u.substring(f,a.index);f=o.lastIndex,l&&s.push({type:i[2],value:l});if(a[0])s.push({type:i[3],value:a[0]});else if(!l)break}}return f<u.length&&s.push({type:i[2],value:u.substr(f)}),s}},{regex:"^Searching for [^\\r\\n]*$",onMatch:function(e,t,n){var r=e.split("\x01");if(r.length<3)return"text";var s,u,a=0,f=[{value:r[a++]+"'",type:"text"},{value:u=r[a++],type:"text"},{value:"'"+r[a++],type:"text"}];r[2]!==" in"&&f.push({value:"'"+r[a++]+"'",type:"text"},{value:r[a++],type:"text"}),f.push({value:" "+r[a++]+" ",type:"text"}),r[a+1]?(s=r[a+1],f.push({value:"("+r[a+1]+")",type:"text"}),a+=1):a-=1;while(a++<r.length)r[a]&&f.push({value:r[a],type:"text"});u&&(/regex/.test(s)||(u=i.escapeRegExp(u)),/whole/.test(s)&&(u="\\b"+u+"\\b"));var l=u&&o("("+u+")",/ sensitive/.test(s)?"g":"ig");return l&&(n[0]=t,n[1]=l),f}},{regex:"^(?=Found \\d+ matches)",token:"text",next:"numbers"},{token:"string",regex:"^\\S:?[^:]+",next:"numbers"}],numbers:[{regex:"\\d+",token:"constant.numeric"},{regex:"$",token:"text",next:"start"}]},this.normalizeRules()};r.inherits(u,s),t.C9SearchHighlightRules=u}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/folding/c9search",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(){};r.inherits(o,s),function(){this.foldingStartMarker=/^(\S.*:|Searching for.*)$/,this.foldingStopMarker=/^(\s+|Found.*)$/,this.getFoldWidgetRange=function(e,t,n){var r=e.doc.getAllLines(n),s=r[n],o=/^(Found.*|Searching for.*)$/,u=/^(\S.*:|\s*)$/,a=o.test(s)?o:u,f=n,l=n;if(this.foldingStartMarker.test(s)){for(var c=n+1,h=e.getLength();c<h;c++)if(a.test(r[c]))break;l=c}else if(this.foldingStopMarker.test(s)){for(var c=n-1;c>=0;c--){s=r[c];if(a.test(s))break}f=c}if(f!=l){var p=s.length;return a===o&&(p=s.search(/\(Found[^)]+\)$|$/)),new i(f,p,l,0)}}}.call(o.prototype)}),define("ace/mode/c9search",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/c9search_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/c9search"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./c9search_highlight_rules").C9SearchHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/c9search").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u};r.inherits(a,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/c9search"}.call(a.prototype),t.Mode=a}); (function() {
|
||||
window.require(["ace/mode/c9search"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/cirru_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"constant.numeric",regex:/[\d\.]+/},{token:"comment.line.double-dash",regex:/--/,next:"comment"},{token:"storage.modifier",regex:/\(/},{token:"storage.modifier",regex:/,/,next:"line"},{token:"support.function",regex:/[^\(\)"\s{}\[\]]+/,next:"line"},{token:"string.quoted.double",regex:/"/,next:"string"},{token:"storage.modifier",regex:/\)/}],comment:[{token:"comment.line.double-dash",regex:/ +[^\n]+/,next:"start"}],string:[{token:"string.quoted.double",regex:/"/,next:"line"},{token:"constant.character.escape",regex:/\\/,next:"escape"},{token:"string.quoted.double",regex:/[^\\"]+/}],escape:[{token:"constant.character.escape",regex:/./,next:"string"}],line:[{token:"constant.numeric",regex:/[\d\.]+/},{token:"markup.raw",regex:/^\s*/,next:"start"},{token:"storage.modifier",regex:/\$/,next:"start"},{token:"variable.parameter",regex:/[^\(\)"\s{}\[\]]+/},{token:"storage.modifier",regex:/\(/,next:"start"},{token:"storage.modifier",regex:/\)/},{token:"markup.raw",regex:/^ */,next:"start"},{token:"string.quoted.double",regex:/"/,next:"string"}]}};r.inherits(s,i),t.CirruHighlightRules=s}),define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),define("ace/mode/cirru",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/cirru_highlight_rules","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./cirru_highlight_rules").CirruHighlightRules,o=e("./folding/coffee").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o,this.$behaviour=this.$defaultBehaviour};r.inherits(u,i),function(){this.lineCommentStart="--",this.$id="ace/mode/cirru"}.call(u.prototype),t.Mode=u}); (function() {
|
||||
window.require(["ace/mode/cirru"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/cobol_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="ACCEPT|MERGE|SUM|ADD||MESSAGE|TABLE|ADVANCING|MODE|TAPE|AFTER|MULTIPLY|TEST|ALL|NEGATIVE|TEXT|ALPHABET|NEXT|THAN|ALSO|NO|THEN|ALTERNATE|NOT|THROUGH|AND|NUMBER|THRU|ANY|OCCURS|TIME|ARE|OF|TO|AREA|OFF|TOP||ASCENDING|OMITTED|TRUE|ASSIGN|ON|TYPE|AT|OPEN|UNIT|AUTHOR|OR|UNTIL|BEFORE|OTHER|UP|BLANK|OUTPUT|USE|BLOCK|PAGE|USING|BOTTOM|PERFORM|VALUE|BY|PIC|VALUES|CALL|PICTURE|WHEN|CANCEL|PLUS|WITH|CD|POINTER|WRITE|CHARACTER|POSITION||ZERO|CLOSE|POSITIVE|ZEROS|COLUMN|PROCEDURE|ZEROES|COMMA|PROGRAM|COMMON|PROGRAM-ID|COMMUNICATION|QUOTE|COMP|RANDOM|COMPUTE|READ|CONTAINS|RECEIVE|CONFIGURATION|RECORD|CONTINUE|REDEFINES|CONTROL|REFERENCE|COPY|REMAINDER|COUNT|REPLACE|DATA|REPORT|DATE|RESERVE|DAY|RESET|DELETE|RETURN|DESTINATION|REWIND|DISABLE|REWRITE|DISPLAY|RIGHT|DIVIDE|RUN|DOWN|SAME|ELSE|SEARCH|ENABLE|SECTION|END|SELECT|ENVIRONMENT|SENTENCE|EQUAL|SET|ERROR|SIGN|EXIT|SEQUENTIAL|EXTERNAL|SIZE|FLASE|SORT|FILE|SOURCE|LENGTH|SPACE|LESS|STANDARD|LIMIT|START|LINE|STOP|LOCK|STRING|LOW-VALUE|SUBTRACT",t="true|false|null",n="count|min|max|avg|sum|rank|now|coalesce|main",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"\\*.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]}};r.inherits(s,i),t.CobolHighlightRules=s}),define("ace/mode/cobol",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/cobol_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./cobol_highlight_rules").CobolHighlightRules,o=function(){this.HighlightRules=s,this.$behaviour=this.$defaultBehaviour};r.inherits(o,i),function(){this.lineCommentStart="*",this.$id="ace/mode/cobol"}.call(o.prototype),t.Mode=o}); (function() {
|
||||
window.require(["ace/mode/cobol"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
define("ace/mode/csp_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e=this.createKeywordMapper({"constant.language":"child-src|connect-src|default-src|font-src|frame-src|img-src|manifest-src|media-src|object-src|script-src|style-src|worker-src|base-uri|plugin-types|sandbox|disown-opener|form-action|frame-ancestors|report-uri|report-to|upgrade-insecure-requests|block-all-mixed-content|require-sri-for|reflected-xss|referrer|policy-uri",variable:"'none'|'self'|'unsafe-inline'|'unsafe-eval'|'strict-dynamic'|'unsafe-hashed-attributes'"},"identifier",!0);this.$rules={start:[{token:"string.link",regex:/https?:[^;\s]*/},{token:"operator.punctuation",regex:/;/},{token:e,regex:/[^\s;]+/}]}};r.inherits(s,i),t.CspHighlightRules=s}),define("ace/mode/csp",["require","exports","module","ace/mode/text","ace/mode/csp_highlight_rules","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./text").Mode,i=e("./csp_highlight_rules").CspHighlightRules,s=e("../lib/oop"),o=function(){this.HighlightRules=i};s.inherits(o,r),function(){this.$id="ace/mode/csp"}.call(o.prototype),t.Mode=o}); (function() {
|
||||
window.require(["ace/mode/csp"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user