Merge pull request #1116 from bergware/master

Plugin system update
This commit is contained in:
tom mortensen
2022-06-27 16:07:24 -07:00
committed by GitHub
22 changed files with 1093 additions and 442 deletions

View File

@@ -15,14 +15,22 @@ Link='nav-user'
?>
<style>
/* Additional CSS for when user supplies element */
.ca_element_notice{padding-right:20px;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:900;display:none;}
.ca_PluginUpdateDismiss{float:right;margin-right:20px;cursor:pointer;}
.ca_pluginUpdateInfo{cursor:pointer;}
.ca_PluginUpdateInstall{cursor:pointer;}
a.bannerInfo {cursor:pointer;text-decoration:none;}
.bannerInfo::before {content:"\f05a";font-family:fontAwesome;color:#e68a00;}
.ca_element_notice{padding-right:20px;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:900;}
a.ca_PluginUpdateInstall{cursor:pointer;}
span.ca_PluginUpdateDismiss{float:right;margin-right:20px;cursor:pointer;}
span.bannerInfo {cursor:pointer;text-decoration:none;margin:0 12px 0 6px;}
span.bannerInfo::before {content:"\f05a";font-family:fontAwesome;color:#e68a00;}
</style>
<script>
const ca_args = {};
function ca_refresh() {
<?if ($task == 'Plugins'):?>
loadlist();
<?else:?>
refresh();
<?endif;?>
}
function ca_hidePluginUpdate(plugin,version,element) {
$.cookie(plugin,version);
@@ -30,14 +38,21 @@ function ca_hidePluginUpdate(plugin,version,element) {
}
function ca_pluginUpdateInstall(plugin) {
openBox("/plugins/dynamix.plugin.manager/scripts/plugin&arg1=update&arg2="+plugin,"_(Installing Update)_",600,900,true,"window.location.reload()");
}
function ca_pluginUpdateShowInfo(cmd,title,height,width,load,func,id) {
// open shadowbox window (run in foreground)
var run = cmd.split('?')[0].substr(-4)=='.php' ? cmd : '/logging.htm?cmd='+cmd+'&csrf_token=<?=$var['csrf_token']?>';
var options = load ? (func ? {modal:true,onClose:function(){setTimeout(func+'('+'"'+(id||'')+'")',0);}} : {modal:false,onClose:function(){location.reload();}}) : {modal:false};
Shadowbox.open({content:run, player:'iframe', title:title, height:Math.min(height,screen.availHeight), width:Math.min(width,screen.availWidth), options:options});
if (plugin == null) {
openPlugin(ca_args.cmd,ca_args.title,'','ca_refresh');
return;
}
ca_args.cmd = 'plugin update '+plugin;
ca_args.title = "_(Installing Update)_";
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
if (data==0) {
// no alert message - proceed with update
setTimeout(ca_pluginUpdateInstall);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","_(Alert Message)_","ca_pluginUpdateInstall");
}
});
}
function caPluginUpdateCheck(plugin,options=[],callback) {
@@ -54,21 +69,20 @@ function caPluginUpdateCheck(plugin,options=[],callback) {
if ( options.debug == true ) result.updateAvailable = true;
if ( ! options.element && ! options.dontShow ) {
if ( result.updateAvailable ) {
var HTML = result.updateMessage+" <a class='ca_PluginUpdateInstall' onclick='ca_pluginUpdateInstall(&quot;"+plugin+"&quot;);'>"+result.linkMessage+"</a> <a class='bannerInfo fa fa-info-circle' onclick='ca_pluginUpdateShowInfo(&quot;/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=/tmp/plugins/"+pluginFilename+".txt&quot;,&quot;_(Release Notes)_&quot;,600,900); return false;'></a>";
var HTML = result.updateMessage+"<span class='bannerInfo fa fa-info-circle big' title=\"_(View Release Notes)_\" onclick='openChanges(\"showchanges /tmp/plugins/"+pluginFilename+".txt\",\"_(Release Notes)_\")'></span><a class='ca_PluginUpdateInstall' onclick='ca_pluginUpdateInstall(\""+plugin+"\")'>"+result.linkMessage+"</a>";
addBannerWarning(HTML,false,options.noDismiss);
}
} else {
if ( $.cookie(plugin) != result.version ) {
if ( result.updateAvailable ) {
var HTML = result.updateMessage+" <a class='ca_PluginUpdateInstall' onclick='ca_pluginUpdateInstall(&quot;"+plugin+"&quot;);'>"+result.linkMessage+"</a> <a class='bannerInfo fa fa-info-circle' onclick='ca_pluginUpdateShowInfo(&quot;/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=/tmp/plugins/"+pluginFilename+".txt&quot;,&quot;_(Release Notes)_&quot;,600,900); return false;'></a>";
var HTML = result.updateMessage+"<span class='bannerInfo fa fa-info-circle big' title=\"_(View Release Notes)_\" onclick='openChanges(\"showchanges /tmp/plugins/"+pluginFilename+".txt\",\"_(Release Notes)_\")'></span><a class='ca_PluginUpdateInstall' onclick='ca_pluginUpdateInstall(\""+plugin+"\")'>"+result.linkMessage+"</a>";
if ( ! options.noDismiss ) {
HTML = HTML.concat("<span class='ca_PluginUpdateDismiss'><i class='fa fa-close' onclick='ca_hidePluginUpdate(&quot;"+plugin+"&quot;,&quot;"+result.version+"&quot;,&quot;"+options.element+"&quot;);'></i>");
HTML = HTML.concat("<span class='ca_PluginUpdateDismiss'><i class='fa fa-close' onclick='ca_hidePluginUpdate(\""+plugin+"\",\""+result.version+"\",\""+options.element+"\")'></i></span>");
}
result.HTML = HTML;
if ( ! options.dontShow ) {
$(options.element).html(HTML);
$(options.element).addClass("ca_element_notice").show();
$(options.element).addClass("ca_element_notice");
}
}
}
@@ -81,5 +95,4 @@ function caPluginUpdateCheck(plugin,options=[],callback) {
}
});
}
</script>

View File

@@ -15,17 +15,31 @@ Tag="download"
*/
?>
<script>
function installPlugin(name) {
var file = name.trim();
var plugin = file.replace(/^.*(\\|\/|\:)/,'').replace('.plg','')+':install';
var func = plugin.includes('dynamix.unraid.net') ? 'reloadToList' : 'loadlist'; // conditionally reload on closure of shadboxbox for My Servers plugin
if (file) openBox("/plugins/dynamix.plugin.manager/scripts/plugin&arg1=install&arg2="+file,"_(Install Plugin)_",600,900,true,func,plugin);
const my = {};
function installPlugin(file) {
if (file == null) {
$('#plugin_file').val('');
openPlugin(my.cmd,my.title,my.plg);
return;
}
file = file.trim();
if (!file) return;
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
my.cmd = 'plugin install '+file;
my.title = "_(Install Plugin)_";
my.plg = file.replace(/^.*(\\|\/|\:)/,'').replace('.plg','')+':install';
if (data==0) {
// no alert message - proceed with install
setTimeout(installPlugin);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","<?=_('Alert Message')?>",'installPlugin');
}
});
}
function reloadToList() {
$.removeCookie('tab');
window.location.href = '/Plugins';
};
</script>
**_(Enter URL of remote plugin file or local plugin file)_**
<form name="plugin_install" method="POST" target="progressFrame">

View File

@@ -18,8 +18,10 @@ Code="e944"
*/
?>
<?
// Remove stale /tmp/plugin/*.plg entries
foreach (glob("/tmp/plugins/*.{plg,txt}", GLOB_NOSORT+GLOB_BRACE) as $entry) if (!file_exists("/var/log/plugins/".basename($entry))) @unlink($entry);
// Remove stale /tmp/plugin/*.plg entries (check that script 'plugin' is not running to avoid clashes)
if (!exec("pgrep -f $docroot/plugins/dynamix.plugin.manager/scripts/plugin")) {
foreach (glob("/tmp/plugins/*.{plg,txt}", GLOB_NOSORT+GLOB_BRACE) as $entry) if (!file_exists("/var/log/plugins/".basename($entry))) @unlink($entry);
}
$check = $notify['version'] ? 0 : 1;
?>
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.filetree.css')?>">
@@ -27,8 +29,29 @@ $check = $notify['version'] ? 0 : 1;
#plugin_tree{width:33%;height:200px;overflow-y:scroll}
table tbody td{line-height:normal}
</style>
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
<script>
const args = {};
function openInstall(cmd,title,plg) {
if (cmd == null) {
openPlugin(args.cmd,args.title,args.plg);
return;
}
args.cmd = cmd;
args.title = title;
args.plg = plg;
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
if (data==0) {
// no alert message - proceed with update
setTimeout(openInstall);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","_(Alert Message)_",'openInstall');
}
});
}
<?if ($display['resize']):?>
function resize(bind) {
var width = [];
@@ -42,6 +65,19 @@ function resize(bind) {
}
}
<?endif;?>
function multiRemove() {
if ($('input.remove:checked').length > 1) $('#removeall').show(); else $('#removeall').hide();
}
function updateList() {
let list = [];
$('input.update').each(function(){list.push($(this).attr('data'));});
openPlugin("multiplugin update "+list.join('*'),"_(Update All Plugins)_",":return");
}
function removeList() {
let list = [];
$('input.remove:checked').each(function(){list.push($(this).attr('data'));});
openPlugin("multiplugin remove "+list.join('*'),"_(Remove Selected Plugins)_","","refresh");
}
function updateInfo(data) {
var updates = data.split('\n');
for (var n=0,update; update=updates[n]; n++) {
@@ -52,9 +88,6 @@ function updateInfo(data) {
}
}
}
function disableButton() {
$('#plugin_list').find('input[type=button]').prop('disabled',true);
}
function initlist() {
timers.plugins = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{init:true,check:<?=$check?>},function(data) {
@@ -94,14 +127,14 @@ function loadlist(id,check) {
$('#plugin_table').trigger('update');
$('#checkall').find('input').prop('disabled',false);
if (data[1] > 1) $('#updateall').show(); else $('#updateall').hide();
if (data[2] != null) openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file='+data[2],"_(Alert Message)_",600,900);
});
}
$(function() {
initlist();
$('#plugin_tree').fileTree({root:'/boot/',top:'/boot/',filter:'plg'}, function(file) {$('#plugin_file').val(file);});
$('.tabs').append("<span id='updateall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value='<?=_('Update All Plugins')?>' onclick='disableButton();openBox(\"/plugins/dynamix.plugin.manager/scripts/plugin&arg1=updateall\",\"<?=_('Update All Plugins')?>\",600,600,true,\"loadlist\",\":return\")'></span>");
$('.tabs').append("<span id='checkall' class='status vhshift'><input type='button' value='<?=_('Check For Updates')?>' onclick='openBox(\"/plugins/dynamix.plugin.manager/scripts/checkall\",\"<?=_('Plugin Update Check')?>\",600,600,true,\"loadlist\",\":return\")' disabled></span>");
$('.tabs').append("<span id='removeall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value=\"_(Remove Selected Plugins)_\" onclick='removeList()'></span>");
$('.tabs').append("<span id='updateall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value=\"_(Update All Plugins)_\" onclick='updateList()'></span>");
$('.tabs').append("<span id='checkall' class='status vhshift'><input type='button' value=\"_(Check For Updates)_\" onclick='openPlugin(\"checkall\",\"_(Plugin Update Check)_\",\":return\")' disabled></span>");
});
</script>
<table class='tablesorter plugins shift' id='plugin_table'>

View File

@@ -19,9 +19,10 @@ Tag="upload"
$version = $branch = $date = _('unknown');
$bzroot = file_exists('/boot/previous/bzroot');
$check = $notify['unraidos'] ? 0 : 1;
$changes = '/boot/previous/changes.txt';
if (file_exists('/boot/previous/changes.txt')) {
exec("head -n4 /boot/previous/changes.txt",$rows);
if (file_exists($changes)) {
exec("head -n4 $changes",$rows);
foreach ($rows as $row) {
$i = stripos($row,'version');
if ($i !== false) {
@@ -39,9 +40,29 @@ input[value="_(Install)_"],input[value="_(Update)_"],input[value="_(Restore)_"]{
span.vhshift{margin-top:13px!important}
<?endif;?>
</style>
<script>
var original = null;
const args = {};
function openInstall(cmd,title,plg) {
if (cmd == null) {
openPlugin(args.cmd,args.title,args.plg);
return;
}
args.cmd = cmd;
args.title = title;
args.plg = plg;
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
if (data==0) {
// no alert message - proceed with update
setTimeout(openInstall);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","_(Alert Message)_",'openInstall');
}
});
}
function update_table(branch) {
if (original) {
if (branch != original) branch = '';
@@ -82,21 +103,20 @@ function warning (data) {
}
function loadlist(id,check) {
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,audit:id,check:check||<?=$check?>},function(data) {
data = data.split('\0');
var list = $('#os_list');
if (id) {
var cmd = id.split(':');
var tr = 'tr#'+cmd[0].replace(/[\. _]/g,'');
switch (cmd[1]) {
case 'update' : data[0] = warning(data[0]);
case 'return' : updateInfo(data[0]); break;
case 'install': list.find(tr).remove(); list.append(warning(data[0])); break;
case 'update' : data = warning(data);
case 'return' : updateInfo(data); break;
case 'install': list.find(tr).remove(); list.append(warning(data)); break;
}
} else {
<?if (!$reboot):?>
updateInfo(data[0]);
updateInfo(data);
<?else:?>
updateInfo(warning(data[0]));
updateInfo(warning(data));
<?endif;?>
}
$('#os_table').trigger('update');
@@ -104,12 +124,11 @@ function loadlist(id,check) {
<?if ($reboot):?>
$('#change_branch').prop('disabled',true);
<?endif;?>
if (data[1] != null) openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file='+data[1],"_(Alert Message)_",600,900);
});
}
$(function() {
initlist();
$('.tabs').append("<span class='status vhshift'><input type='button' id='checkos' value='<?=_('Check for Updates')?>' onclick='openBox(\"/plugins/dynamix.plugin.manager/scripts/plugin&arg1=checkos\",\"<?=_('System Update Check')?>\",600,600,true,\"loadlist\",\":return\")' disabled></span>");
$('.tabs').append("<span class='status vhshift'><input type='button' id='checkos' value=\"_(Check for Updates)_\" onclick='openPlugin(\"plugin checkos\",\"_(System Update Check)_\",\":return\")' disabled></span>");
});
</script>
<table class='tablesorter plugins shift' id='os_table'>

View File

@@ -34,16 +34,14 @@ function check_plugin($arg, &$ncsi) {
function make_link($method, $arg, $extra='') {
$plg = basename($arg,'.plg').':'.$method;
$id = str_replace(['.',' ','_'],'',$plg);
$check = $method=='remove' ? "<input type='checkbox' onClick='document.getElementById(\"$id\").disabled=!this.checked'>" : "";
$check = $method=='remove' ? "<input type='checkbox' data='$arg' class='remove' onClick='document.getElementById(\"$id\").disabled=!this.checked;multiRemove()'>" : "";
$disabled = $check ? ' disabled' : '';
if ($method == 'delete') {
$cmd = "/plugins/dynamix.plugin.manager/scripts/plugin_rm&arg1=$arg";
$exec = $plg = "";
$cmd = "plugin_rm $arg"; $plg = "";
} else {
$cmd = "/plugins/dynamix.plugin.manager/scripts/plugin&arg1=$method&arg2=$arg".($extra?"&arg3=$extra":"");
$exec = "loadlist";
$cmd = "plugin $method $arg".($extra?" $extra":"");
}
return "$check<input type='button' id='$id' value='"._(ucfirst($method))."' onclick='openBox(\"$cmd\",\""._(ucwords($method)." Plugin")."\",600,900,true,\"$exec\",\"$plg\");'$disabled>";
return "$check<input type='button' id='$id' data='$arg' class='$method' value=\""._(ucfirst($method))."\" onclick='openInstall(\"$cmd\",\""._(ucwords($method)." Plugin")."\",\"$plg\");'$disabled>";
}
// trying our best to find an icon

View File

@@ -23,6 +23,7 @@ $system = unscript($_GET['system']??'');
$branch = unscript($_GET['branch']??'');
$audit = unscript($_GET['audit']??'');
$check = unscript($_GET['check']??'');
$cmd = unscript($_GET['cmd']??'');
$init = unscript($_GET['init']??'');
$empty = true;
$install = false;
@@ -32,6 +33,12 @@ $builtin = ['unRAIDServer'];
$plugins = "/var/log/plugins/*.plg";
$ncsi = null; // network connection status indicator
if ($cmd=='alert') {
// signal alert message yer or no
echo is_file($alerts) ? 1 : 0;
die();
}
if ($audit) {
[$plg,$action] = my_explode(':',$audit);
switch ($action) {
@@ -166,7 +173,7 @@ foreach (glob($plugins,GLOB_NOSORT) as $plugin_link) {
if (($changes = plugin('changes',$changes_file)) !== false) {
$txtfile = "/tmp/plugins/".basename($plugin_file,'.plg').".txt";
file_put_contents($txtfile,$changes);
$version .= "&nbsp;<span class='fa fa-info-circle fa-fw big blue-text' title='"._('View Release Notes')."' onclick=\"openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=$txtfile','"._('Release Notes')."',600,900)\"></span>";
$version .= "&nbsp;<span class='fa fa-info-circle fa-fw big blue-text' title='"._('View Release Notes')."' onclick=\"openChanges('showchanges $txtfile','"._('Release Notes')."')\"></span>";
}
if ($rank < 2 && ($alert = plugin('alert',$changes_file)) !== false) {
// generate alert message (if existing) when newer version is available
@@ -182,5 +189,4 @@ foreach (glob($plugins,GLOB_NOSORT) as $plugin_link) {
}
if ($empty) echo "<tr><td colspan='6' style='text-align:center;padding-top:12px'><i class='fa fa-check-square-o icon'></i> "._('No plugins installed')."</td><tr>";
if (!$init && !$os) echo "\0".$updates;
if (!$init && file_exists($alerts)) echo "\0".$alerts;
?>

View File

@@ -0,0 +1,54 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
function readJson($file) {
return is_file($file) ? json_decode(file_get_contents($file),true) : [];
}
function newurl($url) {
$oldURL = 'https://raw.github.com/';
$newURL = 'https://raw.githubusercontent.com/';
return str_replace($oldURL,$newURL,$url);
}
function searchLink(&$db,$url) {
if ($url) for ($i = 0; $i < count($db); $i++) if ($db[$i]['PluginURL']==$url) return $db[$i]['Support'];
}
$method = $argv[1];
$plugin = "/boot/config/plugins/{$argv[2]}";
if ($method == 'install' or $method == 'update') {
// update support link in plugin file
$info = readJson('/tmp/community.applications/tempFiles/templates.json');
// find matching support link
$url = plugin('pluginURL', $plugin);
if ($support = searchLink($info, $url) ?: searchLink($info, newurl($url))) {
// update incorrect or missing support links
if (plugin('support', $plugin) != $support) {
$xml = @simplexml_load_file($plugin);
if ($xml->xpath('//PLUGIN/@support')[0]) {
// support link exists, update it
$xml->xpath('//PLUGIN/@support')[0] = $support;
} else {
// support link is missing, add it
$xml->addAttribute('support', $support);
}
echo "Updating support link\n";
file_put_contents($plugin, $xml->saveXML());
}
}
}
?>

View File

@@ -0,0 +1,34 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
$method = $argv[1];
$plugin = $argv[2];
// validate plugin update (not applicable to OS updates)
if ($method == 'check' and $plugin != 'unRAIDServer.plg') {
$old_plugin = "/boot/config/plugins/$plugin";
$new_plugin = "/tmp/plugins/$plugin";
if (plugin('version', $new_plugin) > plugin('version', $old_plugin)) {
echo "Validating $plugin update\n";
if (($status = plugin('validate', $new_plugin)) != 'valid') {
echo "$status\n";
// restore original plugin and undo update
copy($old_plugin, $new_plugin);
}
}
}
?>

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2019-2020, Lime Technology
* Copyright 2019-2020, Andrew Zawadzki.
/* Copyright 2005-2022, Lime Technology
* Copyright 2019-2022, Andrew Zawadzki.
*
* 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,81 +14,85 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
//add translations
$_SERVER['REQUEST_URI'] = "plugins";
require_once "$docroot/plugins/dynamix/include/Translations.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
function download_url($url, $path = "") {
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_FRESH_CONNECT,true);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,15);
curl_setopt($ch,CURLOPT_TIMEOUT,45);
curl_setopt($ch,CURLOPT_ENCODING,"");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt_array($ch,[
CURLOPT_URL => $url,
CURLOPT_FRESH_CONNECT => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_TIMEOUT => 45,
CURLOPT_ENCODING => "",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true
]);
$out = curl_exec($ch);
curl_close($ch);
if ( $path )
file_put_contents($path,$out);
if ( $path ) file_put_contents($path,$out);
return $out ?: false;
}
switch ($_POST['action']) {
case 'checkPlugin':
$options = $_POST['options'];
$plugin = $options['plugin'];
$name = $options['name'] ?? $plugin;
if ( ! $plugin || ! file_exists("/var/log/plugins/$plugin") ) {
echo json_encode(array("updateAvailable"=>false));
echo json_encode(["updateAvailable"=>false]);
break;
}
exec("mkdir -p /tmp/plugins");
@unlink("/tmp/plugins/$plugin");
$url = @plugin("pluginURL","/boot/config/plugins/$plugin");
$url = plugin("pluginURL","/boot/config/plugins/$plugin");
download_url($url,"/tmp/plugins/$plugin");
$changes = @plugin("changes","/tmp/plugins/$plugin");
$version = @plugin("version","/tmp/plugins/$plugin");
$installedVersion = @plugin("version","/boot/config/plugins/$plugin");
$min = @plugin("min","/tmp/plugins/$plugin") ?: "6.4.0";
$changes = plugin("changes","/tmp/plugins/$plugin");
$alerts = plugin("alert","/tmp/plugins/$plugin");
$version = plugin("version","/tmp/plugins/$plugin");
$installedVersion = plugin("version","/boot/config/plugins/$plugin");
$min = plugin("min","/tmp/plugins/$plugin") ?: "6.4.0";
if ( $changes ) {
file_put_contents("/tmp/plugins/".pathinfo($plugin, PATHINFO_FILENAME).".txt",$changes);
} else {
@unlink("/tmp/plugins/".pathinfo($plugin, PATHINFO_FILENAME).".txt");
}
if ( $alerts ) {
file_put_contents('/tmp/plugins/my_alerts.txt',$alerts);
} else {
@unlink('/tmp/plugins/my_alerts.txt');
}
$update = false;
if ( strcmp($version,$installedVersion) > 0 ) {
$unraid = parse_ini_file("/etc/unraid-version");
$update = (version_compare($min,$unraid['version'],">")) ? false : true;
$update = version_compare($min,$unraid['version'],'<=');
}
$updateMessage = sprintf(_("%s: An update is available."),$name);
$linkMessage = sprintf(_("Click here to install version %s"),$version);
echo json_encode(array("updateAvailable" => $update,"version" => $version,"min"=>$min,"changes"=>$changes,"installedVersion"=>$installedVersion,"updateMessage"=>$updateMessage,"linkMessage"=>$linkMessage));
echo json_encode(["updateAvailable"=>$update, "version"=>$version, "min"=>$min, "alert"=>$alerts, "changes"=>$changes, "installedVersion"=>$installedVersion, "updateMessage"=>$updateMessage, "linkMessage"=>$linkMessage]);
break;
case 'addRebootNotice':
$message = htmlspecialchars(trim($_POST['message']));
if (!$message) break;
$existing = @file("/tmp/reboot_notifications",FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: array();
if ( ! $message ) break;
$existing = @file("/tmp/reboot_notifications",FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
$existing[] = $message;
file_put_contents("/tmp/reboot_notifications",implode("\n",array_unique($existing)));
break;
case 'removeRebootNotice':
$message = htmlspecialchars(trim($_POST['message']));
$existing = file_get_contents("/tmp/reboot_notifications");
$newReboots = str_replace($message,"",$existing);
file_put_contents("/tmp/reboot_notifications",$newReboots);
break;
}
}
?>

View File

@@ -24,13 +24,33 @@ $_SERVER['REQUEST_URI'] = 'plugins';
$_SESSION['locale'] = $display['locale'];
require_once "$docroot/webGui/include/Translations.php";
$console = !(isset($argv[1]) && $argv[1]=='nchan');
function write($message){
global $console;
if ($console) {
echo $message;
} else {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => 'http://localhost/pub/plugins?buffer_length=0',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
}
// check connectivity first
echo _("Checking connectivity")."...\n";
write(_("Checking connectivity")."...\n");
if (exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'")) {
$check = popen('plugin checkall','r');
while (!feof($check)) echo fgets($check);
while (!feof($check)) write(fgets($check));
pclose($check);
} else {
echo _("No response, aborting")."!\n";
write(_("No response, aborting")."!\n");
}
?>

View File

@@ -1,9 +1,11 @@
#!/usr/bin/php -q
<?PHP
// Copyright 2005-2020, Lime Technology
// Copyright 2005-2022, Lime Technology
// License: GPLv2 only
//
// Program updates made by Bergware International (April 2020)
// Program updates made by Bergware International (June 2022)
$usage = <<<EOF
Process language files.
@@ -30,6 +32,9 @@ Usage: language updateall
EOF;
// Error code to description (wget)
// ref: https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html
//
function error_desc($code) {
switch($code) {
case 0: return 'No errors';
@@ -46,38 +51,79 @@ function error_desc($code) {
}
}
// Set output control
// Check for optional parameter 'nchan'
//
function console($i) {
global $console, $argv;
$console = !(isset($argv[$i]) && $argv[$i]=='nchan');
}
// Function to write either to console (echo) or nchan (curl)
// Default output is console, use optional parameter "nchan" to write to nchan instead
//
function write($message) {
global $console;
if ($console) {
echo $message;
} else {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => 'http://localhost/pub/plugins?buffer_length=0',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
}
// Download a file from a URL.
// Returns TRUE if success else FALSE and fills in error.
//
function download($url, $name, &$error) {
$plg = basename($url);
if ($file = popen("wget --compression=auto --no-cache --progress=dot -O $name $url 2>&1", 'r')) {
echo "language: downloading: $url ...\r";
write("language: downloading: $plg ...\r");
$level = -1;
while (!feof($file)) {
if (preg_match('/\d+%/', fgets($file), $matches)) {
$percentage = substr($matches[0],0,-1);
if ($percentage > $level) {
echo "language: downloading: $url ... $percentage%\r";
write("language: downloading: $plg ... $percentage%\r");
$level = $percentage;
}
}
}
if (($perror = pclose($file)) == 0) {
echo "language: downloading: $url ... done\n";
write("language: downloading: $plg ... done\n");
return true;
} else {
echo "language: downloading: $url ... failed (".error_desc($perror).")\n";
$error = "$url download failure (".error_desc($perror).")";
$error = "$plg download failure (".error_desc($perror).")";
return false;
}
} else {
$error = "$url failed to open";
$error = "$plg failed to open";
return false;
}
}
// Deal with logging message.
//
function logger($message) {
shell_exec("logger $message");
}
// Interpret a language file
// Returns TRUE if success, else FALSE and fills in error string.
//
function language($method, $xml_file, &$error) {
global $docroot, $boot, $plugins, $tmp;
// parse language XML file
$xml = file_exists($xml_file) ? simplexml_load_file($xml_file,NULL,LIBXML_NOCDATA) : false;
$xml = file_exists($xml_file) ? @simplexml_load_file($xml_file,NULL,LIBXML_NOCDATA) : false;
if ($xml === false) {
$error = "XML file doesn't exist or xml parse error";
return false;
@@ -127,7 +173,7 @@ function language($method, $xml_file, &$error) {
}
case 'dump':
// dump file: debugging
echo print_r($xml);
write(print_r($xml,true));
return true;
default:
// return single attribute
@@ -138,7 +184,7 @@ function language($method, $xml_file, &$error) {
// MAIN - single argument
if ($argc < 2) {
echo $usage;
write($usage);
exit(1);
}
@@ -147,23 +193,32 @@ $boot = '/boot/config/plugins';
$plugins = '/var/log/plugins';
$tmp = '/tmp/plugins';
$method = $argv[1];
$console = true; // default output is console, nchan otherwise
// language checkall
// check all installed languages
//
if ($method == 'checkall') {
echo "language: checking all language packs\n";
console(2);
write("language: checking all language packs\n");
foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) {
$lang_file = @readlink($link);
if ($lang_file === false) continue;
if (language('LanguageURL', $lang_file, $error) === false) continue;
$name = str_replace('lang-', '', basename($lang_file, '.xml'));
$lang = language('Language', $lang_file, $error) ?: $name;
echo "language: checking $lang language pack ...\n";
write("language: checking $lang language pack ...\n");
exec(realpath($argv[0])." check $name >/dev/null");
}
exit(0);
}
// language updateall
// update all installed languages
//
if ($method == 'updateall') {
echo "language: updating all language packs\n";
console(2);
write("language: updating all language packs\n");
foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) {
$lang_file = @readlink($link);
if ($lang_file === false) continue;
@@ -174,7 +229,7 @@ if ($method == 'updateall') {
$latest = language('Version', "$tmp/lang-$name.xml", $error);
// update only when newer
if (strcmp($latest, $version) > 0) {
echo "language: updating $lang language pack ...\n";
write("language: updating $lang language pack ...\n");
exec(realpath($argv[0])." update $name >/dev/null");
}
}
@@ -182,83 +237,94 @@ if ($method == 'updateall') {
}
// MAIN - two arguments
if ($argc != 3) {
echo $usage;
if ($argc < 3) {
write($usage);
exit(1);
}
// language install [language_file]
//
if ($method == 'install') {
echo "language: installing language pack\n";
if (substr($argv[2],0,7)=='http://' || substr($argv[2],0,8)=='https://') {
console(3);
$argv[2] = preg_replace('#[\x00-\x1F\x80-\xFF]#', '', $argv[2]);
$name = basename($argv[2]);
write("language: installing language pack\n");
// check for URL
if (preg_match('#^https?://#',$argv[2])) {
$langURL = $argv[2];
echo "language: downloading $langURL\n";
$name = basename($langURL);
$xml_file = "$tmp/$name";
write("language: downloading: $name\n");
if (!download($langURL, $xml_file, $error)) {
echo "language: $error\n";
write("language: $error\n");
@unlink($xml_file);
exit(1);
}
} else {
$xml_file = realpath($argv[2]);
$name = basename($xml_file);
}
$link_file = "$plugins/$name";
$lang_file = "$boot/$name";
@unlink($link_file);
if (language('install', $xml_file, $error) === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
$lang = language('Language', $xml_file, $error) ?: substr($name,0,-4);
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
echo "language: $lang language pack installed\n";
write("language: $lang language pack installed\n");
logger("language: $lang language pack installed");
exit(0);
}
// language check [language]
//
if ($method == 'check') {
console(3);
$name = $argv[2];
echo "language: checking language pack\n";
write("language: checking language pack\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
echo "language: $name language pack not installed\n";
write("language: $name language pack not installed\n");
exit(1);
}
$templateURL = language('TemplateURL', $lang_file, $error);
if ($templateURL === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
$xml_file = "$tmp/lang-$name.xml";
if (!download($templateURL, $xml_file, $error)) {
echo "language: $error\n";
write("language: $error\n");
@unlink($xml_file);
exit(1);
}
$version = language('Version', $xml_file, $error);
if ($version === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
echo "$version\n";
write("$version\n");
exit(0);
}
// language update [language]
//
if ($method == 'update') {
console(3);
$name = $argv[2];
echo "language: updating language pack\n";
write("language: updating language pack\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
echo "language: $name language pack not installed\n";
write("language: $name language pack not installed\n");
exit(1);
}
// verify previous check has been done
$xml_file = "$tmp/lang-$name.xml";
if (!file_exists($xml_file)) {
echo "language: update does not exist, perform a check first\n";
write("language: update does not exist, perform a check first\n");
exit (1);
}
$lang = language('Language', $xml_file, $error) ?: $name;
@@ -266,47 +332,54 @@ if ($method == 'update') {
$old_version = language('Version', $lang_file, $error);
$new_version = language('Version', $xml_file, $error);
if ($new_version == $old_version) {
echo "language: $lang language pack not reinstalling same version\n";
write("language: $lang language pack not reinstalling same version\n");
exit(1);
}
// install the updated plugin
@unlink("$boot/dynamix/lang-$name.zip");
@unlink($link_file);
if (language('install', $xml_file, $error) === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
copy($xml_file, $lang_file);
symlink($lang_file, $link_file);
echo "language: $lang language pack updated\n";
write("language: $lang language pack updated\n");
logger("language: $lang language pack updated");
exit(0);
}
// language remove [language]
//
if ($method == 'remove') {
console(3);
$name = $argv[2];
echo "language: removing language pack\n";
write("language: removing language pack: $name\n");
$link_file = "$plugins/lang-$name.xml";
$lang_file = @readlink($link_file);
if ($lang_file === false) {
echo "language: $name language pack not installed\n";
write("language: $name language pack not installed\n");
exit(1);
}
$lang = language('Language', $lang_file, $error) ?: $name;
if (language('remove', $lang_file, $error) === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
echo "language: $lang language pack removed\n";
write("language: $lang language pack removed\n");
logger("language: $lang language pack removed");
exit(0);
}
// return attribute
//
console(3);
$xml_file = $argv[2];
$value = language($method, $xml_file, $error);
if ($value === false) {
echo "language: $error\n";
write("language: $error\n");
exit(1);
}
echo "$value\n";
write("$value\n");
exit(0);
?>

View File

@@ -0,0 +1,48 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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.
*/
?>
<?
$method = $argv[1];
$plugins = explode('*',$argv[2]);
$console = !(isset($argv[3]) && $argv[3]=='nchan');
function write($message){
global $console;
if ($console) {
echo $message;
} else {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => 'http://localhost/pub/plugins?buffer_length=0',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
}
foreach ($plugins as $plugin) {
if (!$plugin) continue;
$line = '';
$run = popen("plugin $method $plugin",'r');
while (!feof($run)) {
$line .= fgetc($run);
if (in_array($line[-1],["\r","\n"])) {write($line); $line = '';}
}
pclose($run);
write("\n");
}
?>

View File

@@ -4,6 +4,8 @@
// License: GPLv2 only
//
// Program updates made by Bergware International (April 2020)
// Program updates made by Bergware International (June 2022)
$usage = <<<EOF
Process plugin files.
@@ -160,32 +162,95 @@ function error_desc($code) {
}
}
// Set output control
// Check for optional parameter 'nchan'
//
function console($i) {
global $console, $argv;
$console = !(isset($argv[$i]) && $argv[$i]=='nchan');
}
// Function to write either to console (echo) or nchan (curl)
// Default output is console, use optional parameter "nchan" to write to nchan instead
//
function write($message) {
global $console;
if ($console) {
echo $message;
} else {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => 'http://localhost/pub/plugins?buffer_length=0',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
}
// Run command and obtain output
//
function run($command) {
$run = popen($command,'r');
while (!feof($run)) write(fgets($run));
return pclose($run);
}
// Run hooked scripts before correct execution of "method"
// method = install, update, remove, check
// hook programs receives two parameters: method and plugin-name
//
function pre_hooks() {
global $method, $plugin;
$hooks = "/usr/local/emhttp/plugins/dynamix.plugin.manager/pre-hooks";
foreach (glob("$hooks/*") as $hook) if (is_executable($hook)) {
write("Executing hook script: ".basename($hook)."\n");
run("$hook $method $plugin");
}
}
// Run hooked scripts after successful completion of "method"
// method = install, update, remove, check
// hook programs receives two parameters: method and plugin-name
//
function post_hooks() {
global $method, $plugin;
$hooks = "/usr/local/emhttp/plugins/dynamix.plugin.manager/post-hooks";
foreach (glob("$hooks/*") as $hook) if (is_executable($hook)) {
write("Executing hook script: ".basename($hook)."\n");
run("$hook $method $plugin");
}
}
// Download a file from a URL.
// Returns TRUE if success else FALSE and fills in error.
//
function download($url, $name, &$error) {
if ($file = popen("wget --compression=auto --no-cache --progress=dot -O $name $url 2>&1", 'r')) {
echo "plugin: downloading: $url ...\r";
function download($url, $name, &$error, $write=true) {
$plg = basename($url);
if ($file = popen("wget --compression=auto --no-cache --progress=dot --retry-connrefused --timeout=30 --tries=5 --waitretry=5 -O $name $url 2>&1", 'r')) {
if ($write) write("plugin: downloading: $plg ...\r");
$level = -1;
while (!feof($file)) {
if (preg_match('/\d+%/', fgets($file), $matches)) {
$percentage = substr($matches[0],0,-1);
if ($percentage > $level) {
echo "plugin: downloading: $url ... $percentage%\r";
if ($write) write("plugin: downloading: $plg ... $percentage%\r");
$level = $percentage;
}
}
}
if (($perror = pclose($file)) == 0) {
echo "plugin: downloading: $url ... done\n";
if ($write) write("plugin: downloading: $plg ... done\n");
return true;
} else {
echo "plugin: downloading: $url ... failed (".error_desc($perror).")\n";
$error = "$url download failure (".error_desc($perror).")";
$error = "$plg download failure (".error_desc($perror).")";
return false;
}
} else {
$error = "$url failed to open";
$error = "$plg failed to open";
return false;
}
}
@@ -193,7 +258,6 @@ function download($url, $name, &$error) {
// Deal with logging message.
//
function logger($message) {
// echo "$message\n";
shell_exec("logger $message");
}
@@ -209,7 +273,7 @@ function plugin($method, $plugin_file, &$error) {
$methods = ['install', 'remove'];
// parse plugin definition XML file
$xml = file_exists($plugin_file) ? simplexml_load_file($plugin_file, NULL, LIBXML_NOCDATA) : false;
$xml = file_exists($plugin_file) ? @simplexml_load_file($plugin_file, NULL, LIBXML_NOCDATA) : false;
if ($xml === false) {
$error = "XML file doesn't exist or xml parse error";
return false;
@@ -217,21 +281,52 @@ function plugin($method, $plugin_file, &$error) {
// dump
if ($method == 'dump') {
// echo $xml->asXML();
echo print_r($xml);
// dump file: debugging
write(print_r($xml,true));
return true;
}
// release notes
if ($method == 'changes') {
if (!$xml->CHANGES) return false;
return trim($xml->CHANGES);
return $xml->CHANGES ? trim($xml->CHANGES) : false;
}
// alert message
if ($method == 'alert') {
if (!$xml->ALERT) return false;
return trim($xml->ALERT);
return $xml->ALERT ? trim($xml->ALERT) : false;
}
// validate plugin download without installation
if ($method == 'validate') {
$name = '/tmp/validate-plugin.tmp';
foreach ($xml->FILE as $file) {
if ($file->URL) {
$url = $file->URL;
@unlink($name);
} elseif ($file->SHA256) {
if (!is_file($name) && download($url, $name, $error, false) === false) {
@unlink($name);
return false;
}
if (hash_file('sha256', $name) != $file->SHA256) {
$error = "bad file SHA256";
@unlink($name);
return false;
}
} elseif ($file->MD5) {
if (!is_file($name) && download($url, $name, $error, false) === false) {
@unlink($name);
return false;
}
if (md5_file($name) != $file->MD5) {
$error = "bad file MD5";
@unlink($name);
return false;
}
}
}
@unlink($name);
return "valid";
}
// check if $method is an attribute
@@ -254,12 +349,12 @@ function plugin($method, $plugin_file, &$error) {
// bergware - check Unraid version dependency (if present)
$min = $file->attributes()->Min;
if ($min && version_compare($unraid['version'],$min,'<')) {
echo "plugin: skipping: ".basename($name)." - Unraid version too low, requires at least version $min\n";
write("plugin: skipping: ".basename($name)." - Unraid version too low, requires at least version $min\n");
continue;
}
$max = $file->attributes()->Max;
if ($max && version_compare($unraid['version'],$max,'>')) {
echo "plugin: skipping: ".basename($name)." - Unraid version too high, requires at most version $max\n";
write("plugin: skipping: ".basename($name)." - Unraid version too high, requires at most version $max\n");
continue;
}
// Name can be missing but only makes sense if Run attribute is present
@@ -344,17 +439,19 @@ function plugin($method, $plugin_file, &$error) {
$command = $file->attributes()->Run;
if ($name) {
logger("plugin: running: $name");
system("$command $name", $retval);
$retval = run("$command $name");
} elseif ($file->LOCAL) {
logger("plugin: running: $file->LOCAL");
system("$command $file->LOCAL", $retval);
$retval = run("$command $file->LOCAL");
} elseif ($file->INLINE) {
logger("plugin: running: 'anonymous'");
$inline = escapeshellarg($file->INLINE);
passthru("echo $inline | $command", $retval);
$name = '/tmp/inline.sh';
file_put_contents($name, $file->INLINE);
$retval = run("$command $name");
unlink($name);
}
if ($retval) {
$error = "run failed: $command retval: $retval";
if ($retval != 0) {
$error = "run failed: $command";
return false;
}
}
@@ -373,7 +470,7 @@ function move($src_file, $tar_dir) {
//
// MAIN - single argument
if ($argc < 2) {
echo $usage;
write($usage);
exit(1);
}
$notify = '/usr/local/emhttp/webGui/scripts/notify';
@@ -382,11 +479,17 @@ $plugins = '/var/log/plugins';
$tmp = '/tmp/plugins';
$method = $argv[1];
$builtin = ['unRAIDServer','unRAIDServer-'];
$console = true; // default output is console, nchan otherwise
// plugin checkall
// check all installed plugins, except built-in
//
if ($method == 'checkall') {
console(2);
if (!$cmd = realpath($argv[0])) {
write("Unknown command: {$argv[0]}\n");
exit(1);
}
foreach (glob("$plugins/*.plg", GLOB_NOSORT) as $link) {
// skip OS related plugins
if (in_array(basename($link,'.plg'),$builtin)) continue;
@@ -395,8 +498,8 @@ if ($method == 'checkall') {
if ($installed_plugin_file === false) continue;
if (plugin('pluginURL', $installed_plugin_file, $error) === false) continue;
$plugin = basename($installed_plugin_file);
echo "plugin: checking $plugin ...\n";
exec(realpath($argv[0])." check $plugin >/dev/null");
write("plugin: checking $plugin ...\n");
exec("$cmd check $plugin >/dev/null");
}
exit(0);
}
@@ -405,6 +508,11 @@ if ($method == 'checkall') {
// update all installed plugins, which have a update available
//
if ($method == 'updateall') {
console(2);
if (!$cmd = realpath($argv[0])) {
write("Unknown command: {$argv[0]}\n");
exit(1);
}
foreach (glob("$plugins/*.plg", GLOB_NOSORT) as $link) {
// skip OS related plugins
if (in_array(basename($link,'.plg'),$builtin)) continue;
@@ -417,8 +525,8 @@ if ($method == 'updateall') {
$latest = plugin('version', "$tmp/$plugin", $error);
// update only when newer
if (strcmp($latest,$version) > 0) {
echo "plugin: updating $plugin ...\n";
exec(realpath($argv[0])." update $plugin >/dev/null");
write("plugin: updating $plugin ...\n");
exec("$cmd update $plugin >/dev/null");
}
}
exit(0);
@@ -428,21 +536,26 @@ if ($method == 'updateall') {
// check built-in only
//
if ($method == 'checkos') {
console(2);
if (!$cmd = realpath($argv[0])) {
write("Unknown command: {$argv[0]}\n");
exit(1);
}
foreach ($builtin as $link) {
// only consider symlinks
$installed_plugin_file = @readlink("$plugins/$link.plg");
if ($installed_plugin_file === false) continue;
if (plugin("pluginURL", $installed_plugin_file, $error) === false) continue;
$plugin = basename($installed_plugin_file);
echo "plugin: checking $plugin ...\n";
exec(realpath($argv[0])." check $plugin >/dev/null");
write("plugin: checking $plugin ...\n");
exec("$cmd check $plugin >/dev/null");
}
exit(0);
}
// MAIN - two or three arguments
if ($argc < 3) {
echo $usage;
write($usage);
exit(1);
}
@@ -454,72 +567,76 @@ if ($argc < 3) {
//
$unraid = parse_ini_file('/etc/unraid-version');
if ($method == 'install') {
$argv[2] = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $argv[2]);
echo "plugin: installing: {$argv[2]}\n";
console(3);
$argv[2] = preg_replace('#[\x00-\x1F\x80-\xFF]#', '', $argv[2]);
$plugin = basename($argv[2]);
write("plugin: installing: $plugin\n");
// check for URL
if ((strpos($argv[2], "http://") === 0) || (strpos($argv[2], "https://") === 0)) {
if (preg_match('#^https?://#',$argv[2])) {
$pluginURL = $argv[2];
echo "plugin: downloading $pluginURL\n";
$plugin_file = "$tmp/".basename($pluginURL);
$plugin_file = "$tmp/$plugin";
write("plugin: downloading: $plugin\n");
if (!download($pluginURL, $plugin_file, $error)) {
echo "plugin: $error\n";
write("plugin: $error\n");
@unlink($plugin_file);
exit(1);
}
} else
} else {
$plugin_file = realpath($argv[2]);
}
// bergware - check Unraid version dependency (if present)
$min = plugin('min', $plugin_file, $error);
if ($min && version_compare($unraid['version'], $min, '<')) {
echo "plugin: installed Unraid version is too low, require at least version $min\n";
write("plugin: installed Unraid version is too low, require at least version $min\n");
if (dirname($plugin_file) == "$boot") {
move($plugin_file, "$boot-error");
}
exit(1);
}
$max = plugin('max', $plugin_file, $error);
if (empty($max)) $max = plugin('Unraid', $plugin_file, $error);
$max = plugin('max', $plugin_file, $error) ?: plugin('Unraid', $plugin_file, $error);
if ($max && version_compare($unraid['version'], $max, '>')) {
echo "plugin: installed Unraid version is too high, require at most version $max\n";
write("plugin: installed Unraid version is too high, require at most version $max\n");
if (dirname($plugin_file) == "$boot") {
move($plugin_file, "$boot-error");
}
exit(1);
}
$plugin = basename($plugin_file);
$symlink = "$plugins/$plugin";
// check for re-install
$installed_plugin_file = @readlink("$plugins/$plugin");
$installed_plugin_file = @readlink($symlink);
if ($installed_plugin_file !== false) {
if ($plugin_file == $installed_plugin_file) {
echo "plugin: not re-installing same plugin\n";
write("plugin: not re-installing same plugin\n");
exit(1);
}
// must have version attributes for re-install
$version = plugin('version', $plugin_file, $error);
if ($version === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
$installed_version = plugin('version', $installed_plugin_file, $error);
if ($installed_version === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
// check version installation?
$forced = $argc==4 ? $argv[3] : false;
$forced = $console ? ($argc==4 ? $argv[3] : false) : ($argc==5 ? $argv[4] : false);
if (!$forced) {
// do not re-install if same plugin already installed or has higher version
if (strcmp($version, $installed_version) < 0) {
echo "plugin: not installing older version\n";
write("plugin: not installing older version\n");
exit(1);
}
if (strcmp($version, $installed_version) == 0) {
echo "plugin: not reinstalling same version\n";
if (strcmp($version, $installed_version) === 0) {
write("plugin: not reinstalling same version\n");
exit(1);
}
}
// run hook scripts for pre processing
pre_hooks();
if (plugin('install', $plugin_file, $error) === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
if (dirname($plugin_file) == "$boot") {
move($plugin_file, "$boot-error");
}
@@ -529,11 +646,14 @@ if ($method == 'install') {
exec("$notify -e $event -s $subject -d $description) -i 2");
exit(1);
}
unlink("$plugins/$plugin");
// remove symlink for re-install
unlink($symlink);
} else {
// run hook scripts for pre processing
pre_hooks();
// fresh install
if (plugin('install', $plugin_file, $error) === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
if (dirname($plugin_file) == "$boot") {
move($plugin_file, "$boot-error");
}
@@ -544,11 +664,15 @@ if ($method == 'install') {
$target = "$boot/$plugin";
if (!plugin('noInstall', $plugin_file, $error)) {
if ($target != $plugin_file) copy($plugin_file, $target);
symlink($target, "$plugins/$plugin");
echo "plugin: $plugin installed\n";
symlink($target, $symlink);
write("plugin: $plugin installed\n");
logger("plugin: $plugin installed");
} else {
echo "script: $plugin executed\n";
write("script: $plugin executed\n");
logger("script: $plugin executed");
}
// run hook scripts for post processing
post_hooks();
exit(0);
}
@@ -557,30 +681,36 @@ if ($method == 'install') {
// directory.
//
if ($method == 'check') {
console(3);
$plugin = $argv[2];
echo "plugin: checking: $plugin\n";
$installed_plugin_file = @readlink("$plugins/$plugin");
$symlink = "$plugins/$plugin";
write("plugin: checking: $plugin ...\n");
$installed_plugin_file = @readlink($symlink);
if ($installed_plugin_file === false) {
echo "plugin: not installed\n";
write("plugin: not installed\n");
exit(1);
}
$installed_pluginURL = plugin('pluginURL', $installed_plugin_file, $error);
if ($installed_pluginURL === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
$plugin_file = "$tmp/$plugin";
if (!download($installed_pluginURL, $plugin_file, $error)) {
echo "plugin: $error\n";
write("plugin: $error\n");
@unlink($plugin_file);
exit(1);
}
// run hook scripts for pre processing
pre_hooks();
$version = plugin('version', $plugin_file, $error);
if ($version === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
echo "$version\n";
write("$version\n");
// run hook scripts for post processing
post_hooks();
exit(0);
}
@@ -593,60 +723,53 @@ if ($method == 'check') {
// Finally we mark the new.plg "installed".
//
if ($method == 'update') {
console(3);
$plugin = $argv[2];
echo "plugin: updating: $plugin\n";
$installed_plugin_file = @readlink("$plugins/$plugin");
$symlink = "$plugins/$plugin";
write("plugin: updating: $plugin\n");
$installed_plugin_file = @readlink($symlink);
if ($installed_plugin_file === false) {
echo "plugin: $plugin not installed\n";
write("plugin: $plugin not installed\n");
exit(1);
}
// get old support link
$previousSupportLink = plugin('support', "$plugins/$plugin", $error);
// verify previous check has been done
$plugin_file = "$tmp/$plugin";
if (!file_exists($plugin_file)) {
echo "plugin: $plugin_file does not exist, check for updates first\n";
write("plugin: $plugin_file does not exist, check for updates first\n");
exit (1);
}
// bergware - check Unraid version dependency (if present)
$min = plugin('min', $plugin_file, $error);
if ($min && version_compare($unraid['version'], $min, '<')) {
echo "plugin: installed Unraid version is too low, require at least version $min\n";
write("plugin: installed Unraid version is too low, require at least version $min\n");
exit(1);
}
$max = plugin('max', $plugin_file, $error);
if (empty($max))
$max = plugin('Unraid', $plugin_file, $error);
$max = plugin('max', $plugin_file, $error) ?: plugin('Unraid', $plugin_file, $error);
if ($max && version_compare($unraid['version'], $max, '>')) {
echo "plugin: installed Unraid version is too high, require at most version $max\n";
write("plugin: installed Unraid version is too high, require at most version $max\n");
exit(1);
}
// check for a reinstall of same version
if (strcmp(plugin('version', $installed_plugin_file,$error), plugin('version', $plugin_file,$error1)) == 0) {
echo "Not reinstalling same version\n";
if (strcmp(plugin('version', $installed_plugin_file, $error), plugin('version', $plugin_file, $error)) === 0) {
write("Not reinstalling same version\n");
exit(1);
}
// run hook scripts for pre processing
pre_hooks();
// install the updated plugin
if (plugin('install', $plugin_file, $error) === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
// install was successful, save the updated plugin so it installs again next boot
unlink("$plugins/$plugin");
// re-inject the old support link if the updated plugin doesn't have one
if (!plugin('support', $plugin_file,$error) && $previousSupportLink) {
echo "\n\nUpdating Support Link\n";
$pluginXML = simplexml_load_file($plugin_file);
$pluginXML->addAttribute('support', $previousSupportLink);
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($pluginXML->asXML());
file_put_contents($plugin_file,$dom->saveXML());
}
copy($plugin_file,"$boot/$plugin");
symlink("$boot/$plugin", "$plugins/$plugin");
echo "plugin: $plugin updated\n";
unlink($symlink);
$target = "$boot/$plugin";
copy($plugin_file, $target);
symlink($target, $symlink);
write("plugin: $plugin updated\n");
logger("plugin: $plugin updated");
// run hook scripts for post processing
post_hooks();
exit(0);
}
@@ -654,35 +777,43 @@ if ($method == 'update') {
// only .plg files should have a remove method
//
if ($method == 'remove') {
console(3);
$plugin = $argv[2];
echo "plugin: removing: $plugin\n";
$installed_plugin_file = @readlink("$plugins/$plugin");
$symlink = "$plugins/$plugin";
write("plugin: removing: $plugin\n");
$installed_plugin_file = @readlink($symlink);
if ($installed_plugin_file !== false) {
// remove the symlink
unlink("$plugins/$plugin");
unlink($symlink);
@unlink("$tmp/$plugin");
// run hook scripts for pre processing
pre_hooks();
if (plugin('remove', $installed_plugin_file, $error) === false) {
// but if can't remove, restore the symlink
symlink($installed_plugin_file, "$plugins/$plugin");
echo "plugin: $error\n";
if (is_file($installed_plugin_file)) symlink($installed_plugin_file, $symlink);
write("plugin: $error\n");
exit(1);
}
}
// remove the plugin file
move($installed_plugin_file, "$boot-removed");
echo "plugin: $plugin removed\n";
write("plugin: $plugin removed\n");
logger("plugin: $plugin removed");
exec("/usr/local/sbin/update_cron");
// run hook scripts for post processing
post_hooks();
exit(0);
}
// <attribute>
// return attribute
//
console(3);
$plugin_file = $argv[2];
$value = plugin($method, $plugin_file, $error);
if ($value === false) {
echo "plugin: $error\n";
write("plugin: $error\n");
exit(1);
}
echo "$value\n";
write("$value\n");
exit(0);
?>

View File

@@ -1,6 +1,12 @@
#!/bin/bash
text="Deleting $1 ..."
if [[ -z $2 ]]; then
echo $text
else
curl -sfd $text --unix-socket /var/run/nginx.socket http://localhost/pub/plugins?buffer_length=0 >/dev/null 2>&1
fi
# put some restrictions on 'rm'
echo "Deleting $1 ..."
[[ $1 == /boot/config/plugins-error/* ]] && rm $1
[[ $1 == /boot/config/plugins-stale/* ]] && rm $1

View File

@@ -0,0 +1,50 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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.
*/
?>
<?
session_start();
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'plugins';
$_SESSION['locale'] = $display['locale'];
require_once "$docroot/webGui/include/Translations.php";
$file = realpath($argv[1] ?? '');
$console = !(isset($argv[2]) && $argv[2]=='nchan');
$valid = ['/var/tmp/','/tmp/plugins/'];
$good = false;
function write($message){
global $console;
if ($console) {
echo $message;
} else {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => 'http://localhost/pub/changes?buffer_length=0',
CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
}
if ($file) {
foreach ($valid as $check) if (strncmp($file,$check,strlen($check))===0) $good = true;
if ($good && pathinfo($file)['extension']=='txt') write(Markdown(file_get_contents($file)));
} else {
write(Markdown("*"._('No release notes available')."!*"));
}
?>

View File

@@ -3,8 +3,8 @@ Name="Apps"
Code="e942"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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,
@@ -20,7 +20,7 @@ div.notice{margin:150px 0 20px 0}
<script>
function installPlugin(file) {
openBox("/plugins/dynamix.plugin.manager/scripts/plugin&arg1=install&arg2="+file,"_(Install Plugin)_",600,900,true);
openPlugin("plugin install "+file,"_(Install Plugin)_","","refresh");
}
</script>

View File

@@ -22,26 +22,22 @@ $zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
ul,li{margin:0;padding-top:0;padding-bottom:0}
pre.pre{margin:30px 0}
pre>p{margin:0;padding:0}
tt{display:inline-block;text-align:left;position:absolute;left:30px;margin-bottom:30px}
#command{white-space:normal;border:none}
.sweet-alert{width:900px;height:600px}
button.confirm{margin-top:70px}
pre#text{height:250px!important}
</style>
<script>
var diagnosticsFile = "";
var diagnostic = new NchanSubscriber('/sub/diagnostic',{subscriber:'websocket'});
var diagnostic = new NchanSubscriber('/sub/diagnostics',{subscriber:'websocket'});
diagnostic.on('message', function(data) {
if (data) {
if (data == diagnosticsFile.replace("/","")+"FINISHED") {
diagnostic.stop();
swal.close();
location = diagnosticsFile;
setTimeout(cleanUp,4000);
} else {
$("#command").html(data);
}
if (data == '_DONE_') {
diagnostic.stop();
swal.close();
location = diagnosticsFile;
setTimeout(cleanUp,4000);
} else {
let box = $('pre#text');
box.html(box.html()+'<br>'+data).scrollTop(box[0].scrollHeight);
}
});
@@ -56,7 +52,7 @@ function cleanUp() {
function zipfile(){
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1);
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1);
return '<?=$zip?>-diagnostics-'+localISOTime.substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
}
@@ -65,10 +61,12 @@ function diagnostics(file) {
$.post('/webGui/include/Download.php',{cmd:'diag',file:file,anonymize:anonymize},function(zip) {
diagnosticsFile = zip;
diagnostic.start();
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<br><br><tt><pre id='command'></pre></tt>",html:true,type:"info",confirmButtonText:"_(Close)_"});
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<hr><br><pre id='text'></pre><hr>",html:true,type:"info",confirmButtonText:"_(Close)_"});
$('.sweet-alert').css({'height':'600','width':'900'});
});
}
</script>
:diagnostics_1_plug:
This utility is used for troubleshooting purposes. It will collect all of the system information and configuration files, and package these files in a single ZIP file which can be saved locally.
Subsequently, this file can be included in your correspondence with Limetech or the Unraid forum.

View File

@@ -21,7 +21,7 @@ $config = "/boot/config";
$entity = $notify['entity'] & 1 == 1;
$alerts = '/tmp/plugins/my_alerts.txt';
function annotate($text) {echo "\n<!--\n".str_repeat("#",strlen($text))."\n$text\n".str_repeat("#",strlen($text))."\n-->\n";}
function annotate($text) {echo "\n<!--\n",str_repeat("#",strlen($text)),"\n$text\n",str_repeat("#",strlen($text)),"\n-->\n";}
?>
<!DOCTYPE html>
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
@@ -59,10 +59,13 @@ html{font-size:<?=$display['font']?>%}
<?endif;?>
<?endif;?>
.inline_help{display:none}
.upgrade_notice{position:fixed;top:1px;left:0;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:999}
.upgrade_notice i{margin:14px;float:right;cursor:pointer}
.upgrade_notice{position:fixed;top:24px;left:50%;margin-left:-480px;width:900px;height:40px;line-height:40px;color:#e68a00;background-color:#feefb3;border:#e68a00 1px solid;border-radius:40px;text-align:center;font-size:1.4rem;z-index:999}
.upgrade_notice.done{color:#4f8a10;background-color:#dff2bf;border-color:#4f8a10}
.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}
pre#body{font-family:clear-sans;text-align:left;margin:-10px 0 0 30px;padding:0;height:400px;white-space:normal;border:none}
pre#text{text-align:left;margin:-10px 0 0 30px;padding:0;height:400px;white-space:normal;border:none}
<?
$nchan = ['webGui/nchan/notify_poller','webGui/nchan/session_check'];
$safemode = $var['safeMode']=='yes';
@@ -78,7 +81,7 @@ if ($themes2) {
}
$notes = '/var/tmp/unRAIDServer.txt';
if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg"));
$notes = "&nbsp;<span class='fa fa-info-circle fa-fw big blue-text' title='"._('View Release Notes')."' onclick=\"openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=$notes','"._('Release Notes')."',600,900)\"></span>";
$notes = "&nbsp;<span class='fa fa-info-circle fa-fw big blue-text' title='"._('View Release Notes')."' onclick=\"openChanges('showchanges $notes','"._('Release Notes')."')\"></span>";
?>
</style>
@@ -100,9 +103,15 @@ var expiretime = <?=$var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var
var before = new Date();
// page timer events
var timers = {};
const timers = {};
timers.bannerWarning = null;
const addAlert = {};
addAlert.text = $.cookie('addAlert-text');
addAlert.cmd = $.cookie('addAlert-cmd');
addAlert.plg = $.cookie('addAlert-plg');
addAlert.func = $.cookie('addAlert-func');
// current csrf_token
var csrf_token = "<?=$var['csrf_token']?>";
@@ -155,7 +164,7 @@ function updateTime() {
}
function refresh(top) {
if (typeof top === 'undefined') {
for (var i=0,element; element=document.querySelectorAll('input,button,select')[i]; i++) { element.disabled = true; }
for (var i=0,element; element=document.querySelectorAll('input,button,select')[i]; i++) {element.disabled = true;}
for (var i=0,link; link=document.getElementsByTagName('a')[i]; i++) { link.style.color = "gray"; } //fake disable
location.reload();
} else {
@@ -205,7 +214,7 @@ function openBox(cmd,title,height,width,load,func,id) {
// open shadowbox window (run in foreground)
var uri = cmd.split('?');
var run = uri[0].substr(-4)=='.php' ? cmd+(uri[1]?'&':'?')+'done=<?=urlencode(_("Done"))?>' : '/logging.htm?cmd='+cmd+'&csrf_token='+csrf_token+'&done=<?=urlencode(_("Done"))?>';
var options = load ? (func ? {modal:true,onClose:function(){setTimeout(func+'('+'"'+(id||'')+'")',0);}} : {modal:true,onClose:function(){location.reload();}}) : {modal:false};
var options = load ? (func ? {modal:true,onClose:function(){setTimeout(func+'('+'"'+(id||'')+'")');}} : {modal:true,onClose:function(){location.reload();}}) : {modal:false};
Shadowbox.open({content:run, player:'iframe', title:title, height:Math.min(height,screen.availHeight), width:Math.min(width,screen.availWidth), options:options});
}
function openWindow(cmd,title,height,width) {
@@ -235,6 +244,67 @@ function openTerminal(tag,name,more) {
var socket = ['ttyd','syslog'].includes(tag) ? '/webterminal/'+tag+'/' : '/logterminal/'+name+(more=='.log'?more:'')+'/';
$.get('/webGui/include/OpenTerminal.php',{tag:tag,name:name,more:more},function(){tty_window.location=socket; tty_window.focus();});
}
function bannerAlert(text,cmd,plg,func) {
$.post('/webGui/include/StartCommand.php',{cmd:cmd,pid:1},function(pid) {
if (pid == 0) {
if ($(".upgrade_notice").hasClass('done') || timers.bannerAlert==null) {
forcedBanner = false;
if ($.cookie('addAlert') != null) {
removeBannerWarning($.cookie('addAlert'));
$.removeCookie('addAlert');
}
if (plg != null) setTimeout((func||'loadlist')+'("'+plg+'")',250);
} else {
$(".upgrade_notice").addClass('done');
timers.bannerAlert = null;
setTimeout(function(){bannerAlert(text,cmd,plg,func);},1000);
}
} else {
$(".upgrade_notice").removeClass('done');
$.cookie('addAlert',addBannerWarning(text,true,true,true));
$.cookie('addAlert-text',text);
$.cookie('addAlert-cmd',cmd);
$.cookie('addAlert-plg',plg);
$.cookie('addAlert-func',func);
timers.bannerAlert = setTimeout(function(){bannerAlert(text,cmd,plg,func);},250);
}
});
}
function openPlugin(cmd,title,plg,func) {
$.post('/webGui/include/StartCommand.php',{cmd:cmd+' nchan'},function(pid) {
if (pid==0) return;
plugins.start();
swal({title:title+'<hr>',text:"<pre id='text'></pre><hr>",html:true,animation:'none',confirmButtonText:"<?=_('Close')?>"},function(){
plugins.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
setTimeout(function(){bannerAlert("<?=_('Attention - operation continues in background')?>",cmd,plg,func);});
});
$('.sweet-alert').addClass('nchan');
});
}
function openChanges(cmd,title) {
$.post('/webGui/include/StartCommand.php',{cmd:cmd+' nchan'},function(pid) {
if (pid==0) return;
changes.start();
swal({title:title+'<hr>',text:"<pre id='body'></pre><hr>",html:true,animation:'none',confirmButtonText:"<?=_('Close')?>"},function(){
changes.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
});
$('.sweet-alert').addClass('nchan');
});
}
function openAlert(cmd,title,func) {
$.post('/webGui/include/StartCommand.php',{cmd:cmd+' nchan'},function(pid) {
if (pid==0) return;
changes.start();
swal({title:title+'<hr>',text:"<pre id='body'></pre><hr>",html:true,animation:'none',showCancelButton:true,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(proceed){
changes.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
if (proceed) setTimeout(func+'()',750);
});
$('.sweet-alert').addClass('nchan');
});
}
function showStatus(name,plugin,job) {
$.post('/webGui/include/ProcessStatus.php',{name:name,plugin:plugin,job:job},function(status){$(".tabs").append(status);});
}
@@ -254,29 +324,38 @@ function escapeQuotes(form) {
var bannerWarnings = [];
var currentBannerWarning = 0;
var osUpgradeWarning = false;
var forcedBanner = false;
function addBannerWarning(text,warning=true,noDismiss=false) {
function addBannerWarning(text,warning=true, noDismiss=false, forced=false) {
var cookieText = text.replace(/[^a-z0-9]/gi,'');
if ($.cookie(cookieText) == "true") return false;
if (warning) text = "<i class='fa fa-warning' style='float:initial;'></i> "+text;
if (warning) text = "<i class='fa fa-warning fa-fw' style='float:initial'></i> "+text;
if (bannerWarnings.indexOf(text) < 0) {
var arrayEntry = bannerWarnings.push("placeholder") - 1;
if (forced) {
var arrayEntry = 0; bannerWarnings = []; clearTimeout(timers.bannerWarning); timers.bannerWarning = null; forcedBanner = true;
} else {
var arrayEntry = bannerWarnings.push("placeholder") - 1;
}
if (!noDismiss) text += "<a class='bannerDismiss' onclick='dismissBannerWarning("+arrayEntry+",&quot;"+cookieText+"&quot;)'></a>";
bannerWarnings[arrayEntry] = text;
} else return bannerWarnings.indexOf(text);
} else {
return bannerWarnings.indexOf(text);
}
if (timers.bannerWarning==null) showBannerWarnings();
return arrayEntry;
}
function dismissBannerWarning(entry,cookieText) {
$.cookie(cookieText,"true",{expires:365});
$.cookie(cookieText,"true");
removeBannerWarning(entry);
}
function removeBannerWarning(entry) {
bannerWarnings[entry] = false;
clearTimeout(timers.bannerWarning);
showBannerWarnings();
if (!forcedBanner) {
bannerWarnings[entry] = false;
clearTimeout(timers.bannerWarning);
showBannerWarnings();
}
}
function bannerFilterArray(array) {
@@ -313,7 +392,7 @@ function removeRebootNotice(message="<?=_('You must reboot for changes to take e
}
function showUpgradeChanges() {
openBox("/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=/tmp/plugins/unRAIDServer.txt","<?=_('Release Notes')?>",600,900);
openChanges("showchanges /tmp/plugins/unRAIDServer.txt","<?=_('Release Notes')?>");
}
function showUpgrade(text,noDismiss=false) {
if ($.cookie('os_upgrade')==null) {
@@ -321,11 +400,6 @@ function showUpgrade(text,noDismiss=false) {
osUpgradeWarning = addBannerWarning(text.replace(/<a>(.+?)<\/a>/,"<a href='#' onclick='openUpgrade()'>$1</a>").replace(/<b>(.*)<\/b>/,"<a href='#' onclick='document.rebootNow.submit()'>$1</a>"),false,noDismiss);
}
}
function confirmUpgrade() {
swal({title:"<?=_('Update')?> Unraid OS",text:"<?=_('Do you want to update to the new version')?>?",type:'warning',html:true,showCancelButton:true,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(){
openBox("/plugins/dynamix.plugin.manager/scripts/plugin&arg1=update&arg2=unRAIDServer.plg","<?=_('Update')?> Unraid OS",600,900,true);
});
}
function hideUpgrade(set) {
removeBannerWarning(osUpgradeWarning);
if (set)
@@ -333,13 +407,26 @@ function hideUpgrade(set) {
else
$.removeCookie('os_upgrade');
}
function confirmUpgrade(confirm) {
if (confirm) {
swal({title:"<?=_('Update')?> Unraid OS",text:"<?=_('Do you want to update to the new version')?>?",type:'warning',html:true,showCancelButton:true,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(){
setTimeout(function(){openPlugin("plugin update unRAIDServer.plg","<?=_('Update')?> Unraid OS");},250);
});
} else {
setTimeout(function(){openPlugin("plugin update unRAIDServer.plg","<?=_('Update')?> Unraid OS");},250);
}
}
function openUpgrade() {
hideUpgrade();
<?if (file_exists($alerts)):?>
openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=<?=$alerts?>',"<?=_('Alert Message')?>",600,900,true,'confirmUpgrade');
<?else:?>
confirmUpgrade();
<?endif;?>
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
if (data==0) {
// no alert message - proceed with upgrade
confirmUpgrade(true);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","<?=_('Alert Message')?>",'confirmUpgrade');
}
});
}
function digits(number) {
if (number < 10) return 'one';
@@ -626,7 +713,7 @@ defaultPage.on('message', function(msg,meta) {
case 'Formatting': var status = "<span class='green strong'><i class='fa fa-play-circle'></i> <?=_('Array Started')?></span>&bullet;<span class='orange strong'><?=_('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) {
if (ini['mdResyncPos'] > 0) {
var resync = ini['mdResyncAction'].split(/\s+/);
switch (resync[0]) {
case 'recon': var action = resync[1]=='P' ? "<?=_('Parity-Sync')?>" : "<?=_('Data-Rebuild')?>"; break;
@@ -677,6 +764,23 @@ defaultPage.on('message', function(msg,meta) {
}
});
var plugins = new NchanSubscriber('/sub/plugins',{subscriber:'websocket'});
plugins.on('message', function(data) {
let box = $('pre#text');
const text = box.html().split('<br>');
if (data.slice(-1) == '\r') {
text[text.length-1] = data.slice(0,-1);
} else {
text.push(data.slice(0,-1));
}
box.html(text.join('<br>')).scrollTop(box[0].scrollHeight);
});
var changes = new NchanSubscriber('/sub/changes',{subscriber:'websocket'});
changes.on('message', function(data) {
$('pre#body').html(data);
});
var backtotopoffset = 250;
var backtotopduration = 500;
$(window).scroll(function() {
@@ -729,6 +833,7 @@ $(function() {
var top = ($.cookie('top')||0) - $('.tabs').offset().top - 75;
if (top>0) {$('html,body').scrollTop(top);}
$.removeCookie('top');
if ($.cookie('addAlert')!=null) bannerAlert(addAlert.text,addAlert.cmd,addAlert.plg,addAlert.func);
<?if ($safemode):?>
showNotice("<?=_('System running in')?> <b><?=('safe mode')?></b>");
<?else:?>

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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,
@@ -40,7 +40,7 @@ case 'delete':
case 'diag':
if (is_file("$docroot/$file") && !rootpath($file)) exit;
$anon = empty($_POST['anonymize']) ? '' : escapeshellarg($_POST['anonymize']);
exec("echo $docroot/webGui/scripts/diagnostics $anon ".escapeshellarg("$docroot/$file")." | at NOW > /dev/null 2>&1");
exec("echo $docroot/webGui/scripts/diagnostics $anon ".escapeshellarg("$docroot/$file")." | at -M now > /dev/null 2>&1");
echo "/$file";
break;
case 'unlink':

View File

@@ -0,0 +1,40 @@
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, 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';
require_once "$docroot/webGui/include/Secure.php";
function pgrep($proc) {
return exec("pgrep -f $proc");
}
[$command,$args] = explode(' ',unscript($_POST['cmd']??''),2);
// find absolute path of command
foreach (glob("$docroot/plugins/*/scripts",GLOB_NOSORT) as $path) {
if ($name = realpath("$path/$command")) break;
}
$pid = 0; // preset to not started
if ($command && strncmp($name,$path,strlen($path))===0) {
if (isset($_POST['pid'])) {
// return running pid
$pid = pgrep($name);
} elseif (!pgrep($name)) {
// only execute when command and valid path is given and command not already running
exec("echo \"$name $args\" | at -M now >/dev/null 2>&1");
$pid = 1; // started
}
}
echo $pid;
?>

View File

@@ -22,29 +22,26 @@ $var = (array)@parse_ini_file("$get/var.ini");
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/syslinux','/var/log','/var/log/plugins','/boot/extra','/var/log/packages','/var/lib/pkgtools/packages','/tmp'];
function curl_socket($socket, $url, $postdata = NULL) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, $socket);
if ($postdata !== NULL) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
function write($message) {
$nchan = curl_init();
curl_setopt_array($nchan,[
CURLOPT_URL => "http://localhost/pub/diagnostics?buffer_length=0",
CURLOPT_UNIX_SOCKET_PATH => "/var/run/nginx.socket",
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => true
]);
curl_exec($nchan);
curl_close($nchan);
}
function publish($endpoint, $message){
curl_socket("/var/run/nginx.socket", "http://localhost/pub/$endpoint?buffer_length=1", $message);
}
function exert($cmd, &$save=null) {
function run($cmd, &$save=null) {
global $cli,$diag;
// execute command with timeout of 30s
publish("diagnostic",$cmd);
// output command for display
write($cmd);
// execute command with timeout of 30s
exec("timeout -s9 30 $cmd", $save);
return implode("\n",$save);
}
function shareDisks($share) {
return exec("shopt -s dotglob; getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".escapeshellarg("/usr/local/emhttp/mnt/user/$share")." 2>/dev/null") ?: "";
}
@@ -55,7 +52,7 @@ function anonymize($text,$select) {
case 1:
// remove any stray references to the GUID that may wind up in .ini files (notably Unassigned Devices)
$text = str_replace(end(explode("-",$unraid_vars['regGUID'])),"...",$text);
$rows = explode("\n", $text);
$regex = "/\b((disk|cache|parity|cpu|eth|dev)[0-9]+)|(smart|flash|flashbackup|cache|parity|cpu$customShares)\b/";
foreach ($rows as &$row) {
@@ -91,39 +88,34 @@ function cache_filter($disks) {
function pools_filter($disks) {
return array_unique(array_map('prefix',array_keys(cache_filter($disks))));
}
function download_url($url, $path = "", $bg = false, $timeout = 15) {
function download_url($url, $path="", $bg=false, $timeout=15) {
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_FRESH_CONNECT,true);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,10);
curl_setopt($ch,CURLOPT_TIMEOUT,$timeout);
curl_setopt($ch,CURLOPT_ENCODING,"");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt_array($ch,[
CURLOPT_URL => $url,
CURLOPT_FRESH_CONNECT => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_ENCODING => "",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true
]);
$out = curl_exec($ch);
curl_close($ch);
if ( $path )
file_put_contents($path,$out);
if ($path) file_put_contents($path,$out);
return $out ?: false;
}
function geturls_certdetails($file, $hostname, $ip="") {
// called by the geturls() function
// best to ensure the file exists before calling this function
if (!file_exists($file)) return ['', '', ''];
// read the cert
$data = null;
exec("/usr/bin/openssl x509 -noout -subject -nameopt multiline -in ".escapeshellarg($file), $data);
$data = implode("\n", $data);
// determine cn
preg_match('/ *commonName *= (.*)/', $data, $matches);
$cn = trim($matches[1]);
if (strpos($cn, ".myunraid.net") !== false) {
$type = 'myunraid.net';
$iphost = str_replace('.','-',$ip);
@@ -147,28 +139,18 @@ function geturls_certdetails($file, $hostname, $ip="") {
$type = 'user-provided';
}
}
return [$cn, $cn_priv, $type];
}
function geturls_checkhost($host, $hostpriv, $expectedip, $dnsserver) {
// called by the geturls() function
// dns lookups will fail if there is no TLD or if it is ".local", so skip it
if (strpos($host, '.') === false || strpos($host, '.local') !== false) {
return '';
}
if (strpos($host, '.') === false || strpos($host, '.local') !== false) return '';
$result = @dns_get_record($host, DNS_A);
$ip = ($result) ? $result[0]['ip'] : '';
if ($ip == '') {
return " ERROR: When using DNS server {$dnsserver}, the host {$hostpriv} does not resolve.\n";
}
if ($ip == '') return " ERROR: When using DNS server {$dnsserver}, the host {$hostpriv} does not resolve.\n";
if ($ip != $expectedip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$ip = "[redacted]";
}
if (filter_var($expectedip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$expectedip = "[redacted]";
}
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) $ip = "[redacted]";
if (filter_var($expectedip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) $expectedip = "[redacted]";
return " ERROR: When using DNS server {$dnsserver}, {$hostpriv} resolves to {$ip}. It should resolve to {$expectedip}\n";
}
return '';
@@ -190,7 +172,6 @@ function geturls() {
$rebindip = "192.168.42.42";
$rebindtest_ip = exec("host -4 $rebindtesturl 2>/dev/null|sed -n 's/.*has address //p'");
$rebind_msg = ($rebindtest_ip != $rebindip) ? "is enabled, $rebindtestdomain urls will not work" : "is disabled, $rebindtestdomain urls will work";
// show raw data from config files
$urls = '';
$urls .= "Server Name: {$var['NAME']}\n";
@@ -202,7 +183,6 @@ function geturls() {
$urls .= "USE SSL: {$var['USE_SSL']}\n";
$urls .= "DNS Rebinding Protection {$rebind_msg} on this network\n\n";
$urls .= "Available URLs:\n (the URL marked with an asterisk is the primary url for this server)\n";
// calculate variables
$cert_path = "/boot/config/ssl/certs/";
$host_name = $var['NAME'];
@@ -214,29 +194,26 @@ function geturls() {
$https_2_cert = 'certificate_bundle.pem';
$http_primary = $https_1_primary = $https_2_primary = $http_msg = $https_1_msg = $https_2_msg = '';
switch($var['USE_SSL']) {
case "no":
$http_primary = '*';
break;
case "yes":
$https_1_primary = '*';
$http_msg = "\n (this will redirect to the primary url)";
break;
case "auto":
$http_msg = "\n (this will redirect to the primary url)";
$https_1_msg = "\n (this will redirect to the primary url)";
$https_2_primary = '*';
break;
case "no":
$http_primary = '*';
break;
case "yes":
$https_1_primary = '*';
$http_msg = "\n (this will redirect to the primary url)";
break;
case "auto":
$http_msg = "\n (this will redirect to the primary url)";
$https_1_msg = "\n (this will redirect to the primary url)";
$https_2_primary = '*';
break;
}
// calculate http ip url
$http_ip_url = "http://{$internalip_priv}{$http_port}";
$urls .= "HTTP IP url: {$http_ip_url}{$http_msg}\n";
// calculate http url
$http_url = "http://{$expected_host}{$http_port}";
$urls .= "{$http_primary}HTTP url: {$http_url}{$http_msg}\n";
$urls .= geturls_checkhost($expected_host, $expected_host, $internalip, $dnsserver);
// calculate https url - self-signed or user-provided in tower_unraid_bundle.pem
// this is available when USE_SSL != no, and the certificate file exists
if ($var['USE_SSL'] != "no" && file_exists("{$cert_path}{$https_1_cert}")) {
@@ -252,7 +229,6 @@ function geturls() {
$urls .= "HTTPS url 1 (undefined): https://{$expected_host}{$https_port}\n (this url is not configured, it will not work)\n";
$urls .= geturls_checkhost($expected_host, $expected_host, $internalip, $dnsserver);
}
// calculate https url for certificate_bundle.pem
// this is available if the certificate file exists, regardless of the USE_SSL setting
// this is usually a (my)unraid.net LE cert, but it can also be a user-provided cert
@@ -265,11 +241,9 @@ function geturls() {
$urls .= " ERROR: the certificate Subject CN in {$https_2_cert} should be {$expected_host}\n";
}
}
if ($var['USE_SSL'] != "no") {
$telnet_disabled = ($var['USE_TELNET'] == "no") ? " (disabled)" : "";
$ssh_disabled = ($var['USE_SSH'] == "no") ? " (disabled)" : "";
$urls .= "\nTip: if DNS goes down and you lose access to the webgui, use telnet{$telnet_disabled}, ";
$urls .= "ssh{$ssh_disabled}, or a local keyboard/monitor to run:\n";
$urls .= " use_ssl no\n";
@@ -277,11 +251,10 @@ function geturls() {
if ($var['USE_SSL'] == "auto") {
$urls .= "Or:\n";
$urls .= " use_ssl yes\n";
$urls .= "to make 'HTTPS url 1' the primary.";
$urls .= "to make 'HTTPS url 1' the primary.";
}
$urls .= "\nOnce DNS has been restored, navigate to Settings -> Management Access and set 'Use SSL' back to '{$var['USE_SSL']}'\n";
}
// get a list of the certificate files on the flash drive
$dirlisting[0] = "{$cert_path}";
if (file_exists($cert_path)) {
@@ -292,28 +265,29 @@ function geturls() {
$urls .= "\n\n".implode("\n", $dirlisting)."\n";
$urls = str_replace("\n", "\r\n", $urls);
return $urls;
}
exert("mkdir -p /boot/logs");
// diagnostics start
run("mkdir -p /boot/logs");
if ($cli) {
// script is called from CLI
// script is called from CLI
echo "Starting diagnostics collection... ";
$server = isset($var['NAME']) ? str_replace(' ','_',strtolower($var['NAME'])) : 'tower';
$date = date('Ymd-Hi');
$diag = "$server-diagnostics-$date";
$zip = "/boot/logs/$diag.zip";
} else {
// script is called from GUI
// script is called from GUI
$diag = basename($zip, '.zip');
$split = explode('-', $diag);
$date = "{$split[2]}-{$split[3]}";
}
// don't anonymize system share names
$vardomain = (array)@parse_ini_file('/boot/config/domain.cfg');
$vardocker = (array)@parse_ini_file('/boot/config/docker.cfg');
$showshares = [];
$vardomain = (array)@parse_ini_file('/boot/config/domain.cfg');
$vardocker = (array)@parse_ini_file('/boot/config/docker.cfg');
$showshares = [];
$showshares[] = current(array_slice(explode('/',$vardomain['IMAGE_FILE']), 3, 1)).'.cfg';
$showshares[] = current(array_slice(explode('/',$vardomain['DOMAINDIR']), 3, 1)).'.cfg';
$showshares[] = current(array_slice(explode('/',$vardomain['MEDIADIR']), 3, 1)).'.cfg';
@@ -323,27 +297,32 @@ $showshares[] = current(array_slice(explode('/',$vardocker['DOCKER_APP_CONFIG_PA
$showshares[] = current(array_slice(explode('/',$vardocker['DOCKER_HOME']), 3, 1)).'.cfg';
foreach ($showshares as $show) {
$showme = str_replace(".cfg","",$show);
if ($showme)
$customShares .= "|$showme";
if ($showme) $customShares .= "|$showme";
}
// create folder structure
exert("mkdir -p ".escapeshellarg("/$diag/system")." ".escapeshellarg("/$diag/config")." ".escapeshellarg("/$diag/logs")." ".escapeshellarg("/$diag/shares")." ".escapeshellarg("/$diag/smart")." ".escapeshellarg("/$diag/qemu")." ".escapeshellarg("/$diag/xml"));
run("mkdir -p ".escapeshellarg("/$diag/system")." ".escapeshellarg("/$diag/config")." ".escapeshellarg("/$diag/logs")." ".escapeshellarg("/$diag/shares")." ".escapeshellarg("/$diag/smart")." ".escapeshellarg("/$diag/qemu")." ".escapeshellarg("/$diag/xml"));
// get utilization of running processes
exert("top -bn1 -o%CPU 2>/dev/null|todos >".escapeshellarg("/$diag/system/top.txt"));
run("top -bn1 -o%CPU 2>/dev/null|todos >".escapeshellarg("/$diag/system/top.txt"));
// make Unraid version reference
$unraid = parse_ini_file('/etc/unraid-version');
$unraid_vars = parse_ini_file('/var/local/emhttp/var.ini');
file_put_contents("/$diag/unraid-".$unraid['version'].".txt",$unraid['version']."\r\n");
// add bz*.sha256 values
exert("tail /boot/bz*.sha256 >> ".escapeshellarg("/$diag/unraid-".$unraid['version'].".txt"));
run("tail /boot/bz*.sha256 >> ".escapeshellarg("/$diag/unraid-".$unraid['version'].".txt"));
// copy ini variables
foreach (glob("$get/*.ini") as $file) {
$ini = basename($file,".ini");
// skip users file in anonymized mode
if ($all || $ini != "users") file_put_contents("/$diag/system/vars.txt",preg_replace(["/\n/","/^Array/"],["\r\n",$ini],anonymize(print_r(parse_ini_file($file,true),true),1)),FILE_APPEND);
}
// Create loads.txt
$cpuload = exert("uptime")." Cores: ".exert("nproc")."\r\n".(string)@file_get_contents("$get/cpuload.ini")."\r\n";
$cpuload = run("uptime")." Cores: ".run("nproc")."\r\n".(string)@file_get_contents("$get/cpuload.ini")."\r\n";
$diskload = (array)@file("$get/diskload.ini");
$disks = (array)@parse_ini_file("$get/disks.ini",true);
$loadTxt = [];
@@ -357,44 +336,51 @@ foreach ($diskload as $loadLine) {
}
}
file_put_contents("/$diag/system/loads.txt",$cpuload.implode("\r\n",$loadTxt));
// individual commands execution (suppress errors)
exert("lscpu 2>/dev/null|todos >".escapeshellarg("/$diag/system/lscpu.txt"));
exert("lsscsi -vgl 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsscsi.txt"));
exert("lspci -knn 2>/dev/null|todos >".escapeshellarg("/$diag/system/lspci.txt"));
exert("lsusb 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsusb.txt"));
exert("free -mth 2>/dev/null|todos >".escapeshellarg("/$diag/system/memory.txt"));
exert("ps -auxf --sort=-pcpu 2>/dev/null|todos >".escapeshellarg("/$diag/system/ps.txt"));
exert("lsof -Pni 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsof.txt"));
exert("lsmod|sort 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsmod.txt"));
exert("df -h 2>/dev/null|todos >".escapeshellarg("/$diag/system/df.txt"));
exert("ifconfig -a -s 2>/dev/null|grep -Po '^(eth|bond)[0-9]+'", $ports);
exert("dmidecode -qt2|awk -F: '/^\tManufacturer:/{m=\$2};/^\tProduct Name:/{p=\$2} END{print m\" -\"p}' 2>/dev/null|todos >".escapeshellarg("/$diag/system/motherboard.txt"));
exert("dmidecode -qt0 2>/dev/null|todos >>".escapeshellarg("/$diag/system/motherboard.txt"));
exert("cat /proc/meminfo 2>/dev/null|todos >".escapeshellarg("/$diag/system/meminfo.txt"));
exert("dmidecode --type 17 2>/dev/null|todos >>".escapeshellarg("/$diag/system/meminfo.txt"));
run("lscpu 2>/dev/null|todos >".escapeshellarg("/$diag/system/lscpu.txt"));
run("lsscsi -vgl 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsscsi.txt"));
run("lspci -knn 2>/dev/null|todos >".escapeshellarg("/$diag/system/lspci.txt"));
run("lsusb 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsusb.txt"));
run("free -mth 2>/dev/null|todos >".escapeshellarg("/$diag/system/memory.txt"));
run("ps -auxf --sort=-pcpu 2>/dev/null|todos >".escapeshellarg("/$diag/system/ps.txt"));
run("lsof -Pni 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsof.txt"));
run("lsmod|sort 2>/dev/null|todos >".escapeshellarg("/$diag/system/lsmod.txt"));
run("df -h 2>/dev/null|todos >".escapeshellarg("/$diag/system/df.txt"));
run("ifconfig -a -s 2>/dev/null|grep -Po '^(eth|bond)[0-9]+'", $ports);
run("dmidecode -qt2|awk -F: '/^\tManufacturer:/{m=\$2};/^\tProduct Name:/{p=\$2} END{print m\" -\"p}' 2>/dev/null|todos >".escapeshellarg("/$diag/system/motherboard.txt"));
run("dmidecode -qt0 2>/dev/null|todos >>".escapeshellarg("/$diag/system/motherboard.txt"));
run("cat /proc/meminfo 2>/dev/null|todos >".escapeshellarg("/$diag/system/meminfo.txt"));
run("dmidecode --type 17 2>/dev/null|todos >>".escapeshellarg("/$diag/system/meminfo.txt"));
// create ethernet information information (suppress errors)
foreach ($ports as $port) {
exert("ethtool ".escapeshellarg($port)." 2>/dev/null|todos >>".escapeshellarg("/$diag/system/ethtool.txt"));
run("ethtool ".escapeshellarg($port)." 2>/dev/null|todos >>".escapeshellarg("/$diag/system/ethtool.txt"));
file_put_contents("/$diag/system/ethtool.txt", "\r\n", FILE_APPEND);
exert("ethtool -i ".escapeshellarg($port)." 2>/dev/null|todos >>".escapeshellarg("/$diag/system/ethtool.txt"));
run("ethtool -i ".escapeshellarg($port)." 2>/dev/null|todos >>".escapeshellarg("/$diag/system/ethtool.txt"));
file_put_contents("/$diag/system/ethtool.txt", "--------------------------------\r\n", FILE_APPEND);
}
exert("ifconfig -a 2>/dev/null|todos >".escapeshellarg("/$diag/system/ifconfig.txt"));
run("ifconfig -a 2>/dev/null|todos >".escapeshellarg("/$diag/system/ifconfig.txt"));
// create system information (suppress errors)
exert("find /sys/kernel/iommu_groups/ -type l 2>/dev/null|sort -V|todos >".escapeshellarg("/$diag/system/iommu_groups.txt"));
exert("todos </proc/cmdline >".escapeshellarg("/$diag/system/cmdline.txt"));
run("find /sys/kernel/iommu_groups/ -type l 2>/dev/null|sort -V|todos >".escapeshellarg("/$diag/system/iommu_groups.txt"));
run("todos </proc/cmdline >".escapeshellarg("/$diag/system/cmdline.txt"));
// create folder structure listing
$dest = "/$diag/system/folders.txt";
foreach ($folders as $folder) {
if (is_dir($folder)) exert("echo -ne ".escapeshellarg("\r\n$folder\r\n")." >>".escapeshellarg($dest).";ls -l ".escapeshellarg($folder)."|todos >>".escapeshellarg("$dest")); else exert("echo -ne ".escapeshellarg("\r\n$folder\r\nfolder does not exist\r\n")." >>".escapeshellarg("$dest"));
if (is_dir($folder)) run("echo -ne ".escapeshellarg("\r\n$folder\r\n")." >>".escapeshellarg($dest).";ls -l ".escapeshellarg($folder)."|todos >>".escapeshellarg("$dest")); else run("echo -ne ".escapeshellarg("\r\n$folder\r\nfolder does not exist\r\n")." >>".escapeshellarg("$dest"));
}
// copy configuration files (suppress errors)
exert("cp /boot/config/*.{cfg,conf,dat} ".escapeshellarg("/$diag/config")." 2>/dev/null");
exert("cp /boot/config/go ".escapeshellarg("/$diag/config/go.txt")." 2>/dev/null");
run("cp /boot/config/*.{cfg,conf,dat} ".escapeshellarg("/$diag/config")." 2>/dev/null");
run("cp /boot/config/go ".escapeshellarg("/$diag/config/go.txt")." 2>/dev/null");
if (!$all)
exert("sed -i -e '/password/c ***line removed***' -e '/user/c ***line removed***' -e '/pass/c ***line removed***' ".escapeshellarg("/$diag/config/go.txt"));
run("sed -i -e '/password/c ***line removed***' -e '/user/c ***line removed***' -e '/pass/c ***line removed***' ".escapeshellarg("/$diag/config/go.txt"));
// anonymize configuration files
if (!$all) exert("sed -ri 's/^((disk|flash)(Read|Write)List.*=\")[^\"]+/\\1.../' ".escapeshellarg("/$diag/config/*.cfg")." 2>/dev/null");
if (!$all)
run("sed -ri 's/^((disk|flash)(Read|Write)List.*=\")[^\"]+/\\1.../' ".escapeshellarg("/$diag/config/*.cfg")." 2>/dev/null");
// copy share information (anonymize if applicable)
$files = glob("/boot/config/shares/*.cfg");
@@ -404,12 +390,12 @@ foreach ($files as $file) {
$dest = anonymize($dest,2);
}
@copy($file, $dest);
if (!$all) exert("sed -ri 's/^(share(Comment|ReadList|WriteList)=\")[^\"]+/\\1.../' ".escapeshellarg($dest)." 2>/dev/null");
if (!$all) run("sed -ri 's/^(share(Comment|ReadList|WriteList)=\")[^\"]+/\\1.../' ".escapeshellarg($dest)." 2>/dev/null");
$share = pathinfo(basename($file),PATHINFO_FILENAME);
$shareExists = explode(",",shareDisks($share));
unset($exists);
foreach ($shareExists as $anon) {
if ( !$all )
if (!$all) {
if (!preg_match("/\b((disk)[0-9]+)|(cache)\b/", $anon)) {
$len = strlen($anon);
if ($len>2) {
@@ -417,20 +403,23 @@ foreach ($files as $file) {
$exists[] = substr($anon,0,1).$dash.substr($anon,-1);
}
}
else
} else {
$exists[] = $anon;
}
}
$shareDisk .= $exists ? str_pad(pathinfo($dest,PATHINFO_FILENAME),34).str_pad(exec("cat ".escapeshellarg($file)." | grep shareUseCache"),22)." Exists on ".implode(", ",$exists)."\r\n" : "";
$exists = $exists ?: ["no drives"];
file_put_contents($dest,"# Share exists on ".implode(", ",$exists)."\r\n",FILE_APPEND);
}
file_put_contents("/$diag/shares/shareDisks.txt",$shareDisk);
// create default user shares information
$shares = (array)@parse_ini_file("$get/shares.ini", true);
foreach ($shares as $share) {
$name = $share['name'];
if (!in_array("/boot/config/shares/$name.cfg",$files)) file_put_contents(anonymize("/$diag/shares/$name.cfg",2),"# This share has default settings.\r\n# Share exists on ".shareDisks($name)."\r\n");
}
// copy pools information (anonymize)
$files = glob("/boot/config/pools/*.cfg");
@mkdir("/$diag/config/pools");
@@ -438,6 +427,7 @@ foreach ($files as $file) {
$dest = anonymize("/$diag/config/pools/".basename($file),2);
@copy($file,$dest);
}
// copy modprobe information
$files = glob("/boot/config/modprobe.d/*.conf");
if ($files) {
@@ -447,22 +437,24 @@ if ($files) {
@copy($file,$dest);
}
}
// copy docker information (if existing)
$max = 1*1024*1024; //=1MB
$docker = "/var/log/docker.log";
if (file_exists($docker)) {
$log = "/$diag/logs/docker";
exert("todos <$docker >".escapeshellarg("$log.txt"));
run("todos <$docker >".escapeshellarg("$log.txt"));
if (filesize($docker)>=$max) {
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
}
}
// create SMART reports (suppress errors)
$disks = (array)@parse_ini_file("$get/disks.ini", true);
include_once "$docroot/webGui/include/CustomMerge.php";
include_once "$docroot/webGui/include/Wrappers.php";
exert("ls -l /dev/disk/by-id/[asun]* 2>/dev/null|sed '/-part/d;s|^.*/by-id/[^-]*-||;s|-> ../../||;s|:|-|'", $devices);
run("ls -l /dev/disk/by-id/[asun]* 2>/dev/null|sed '/-part/d;s|^.*/by-id/[^-]*-||;s|-> ../../||;s|:|-|'", $devices);
foreach ($devices as $device) {
list($name,$port) = explode(' ',$device);
$diskName = ''; $type = '';
@@ -477,135 +469,145 @@ foreach ($devices as $device) {
}
$port = port_name($port);
$status = $find['status'] == "DISK_OK" ? "" : " - {$find['status']}";
exert("smartctl -x $type ".escapeshellarg("/dev/$port")." 2>/dev/null|todos >".escapeshellarg("/$diag/smart/$name-$date $diskName ($port)$status.txt"));
run("smartctl -x $type ".escapeshellarg("/dev/$port")." 2>/dev/null|todos >".escapeshellarg("/$diag/smart/$name-$date $diskName ($port)$status.txt"));
}
// create pool btrfs information
foreach (pools_filter($disks) as $pool) {
if (strpos($disks[$pool]['fsType'],'btrfs')!==false) {
exert("echo 'Pool: $pool'|todos >>".escapeshellarg("/$diag/system/btrfs-usage.txt"));
exert("/sbin/btrfs filesystem usage -T /mnt/$pool 2>/dev/null|todos >>".escapeshellarg("/$diag/system/btrfs-usage.txt"));
run("echo 'Pool: $pool'|todos >>".escapeshellarg("/$diag/system/btrfs-usage.txt"));
run("/sbin/btrfs filesystem usage -T /mnt/$pool 2>/dev/null|todos >>".escapeshellarg("/$diag/system/btrfs-usage.txt"));
}
}
// create installed plugin information
$pluginList = json_decode(download_url("https://raw.githubusercontent.com/Squidly271/AppFeed/master/pluginList.json"),true);
if ( ! $pluginList )
$installedPlugins = "Could not download current plugin versions\r\n\r\n";
if (!$pluginList) $installedPlugins = "Could not download current plugin versions\r\n\r\n";
$plugins = glob("/var/log/plugins/*.plg");
foreach ($plugins as $plugin) {
$plgVer = exert("plugin version ".escapeshellarg($plugin));
$plgURL = exert("plugin pluginURL ".escapeshellarg($plugin));
$plgVer = run("plugin version ".escapeshellarg($plugin));
$plgURL = run("plugin pluginURL ".escapeshellarg($plugin));
$installedPlugins .= basename($plugin)." - $plgVer";
if ( $pluginList && ! $pluginList[$plgURL] && basename($plugin) !== "unRAIDServer.plg")
if ($pluginList && ! $pluginList[$plgURL] && basename($plugin) !== "unRAIDServer.plg")
$installedPlugins .= " (Unknown to Community Applications)";
if ( $pluginList[$plgURL]['blacklist'] )
if ($pluginList[$plgURL]['blacklist'])
$installedPlugins .= " (Blacklisted)";
if ( $pluginList[$plgURL]['deprecated'] || ( $pluginList[$plgURL]['dmax'] && version_compare($pluginList[$plgURL]['dmax'],$unraid['version'],"<") ) )
if ($pluginList[$plgURL]['deprecated'] || ($pluginList[$plgURL]['dmax'] && version_compare($pluginList[$plgURL]['dmax'],$unraid['version'],"<")))
$installedPlugins .= " (Deprecated)";
if ( $pluginList[$plgURL]['version'] > $plgVer )
if ($pluginList[$plgURL]['version'] > $plgVer)
$installedPlugins .= " (Update available: {$pluginList[$plgURL]['version']})";
elseif ($pluginList[$plgURL])
$installedPlugins .= " (Up to date)";
if ( $pluginList[$plgURL]['max'] && version_compare($pluginList[$plgURL]['max'],$unraid['version'],"<") )
if ($pluginList[$plgURL]['max'] && version_compare($pluginList[$plgURL]['max'],$unraid['version'],"<"))
$installedPlugins .= " (Incompatible)";
if ( $pluginList[$plgURL]['min'] && version_compare($pluginList[$plgURL]['min'],$unraid['version'],">") )
if ($pluginList[$plgURL]['min'] && version_compare($pluginList[$plgURL]['min'],$unraid['version'],">"))
$installedPlugins .= " (Incompatible)";
$installedPlugins .= "\r\n";
}
$installedPlugins = $installedPlugins ?: "No additional Plugins Installed";
file_put_contents("/$diag/system/plugins.txt",$installedPlugins);
// determine urls
file_put_contents("/$diag/system/urls.txt",geturls());
// copy libvirt information (if existing)
$libvirtd = "/var/log/libvirt/libvirtd.log";
if (file_exists($libvirtd)) {
$log = "/$diag/logs/libvirt";
exert("todos <$libvirtd >".escapeshellarg("$log.txt"));
run("todos <$libvirtd >".escapeshellarg("$log.txt"));
if (filesize($libvirtd)>=$max) {
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
}
}
// copy VMs information (if existing)
$qemu = glob("/var/log/libvirt/qemu/*.log*");
if ($qemu) {
foreach ($qemu as $file) {
$log = "/$diag/qemu/".basename($file,'.log');
exert("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
if (filesize($file)>=$max) {
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
}
}
} else {
file_put_contents("/$diag/qemu/no qemu log files","");
}
// copy VM XML config files
exert("cp /etc/libvirt/qemu/*.xml ".escapeshellarg("/$diag/xml")." 2>/dev/null");
run("cp /etc/libvirt/qemu/*.xml ".escapeshellarg("/$diag/xml")." 2>/dev/null");
// anonymize MAC OSK info
$all_xml = glob("/$diag/xml/*.xml");
foreach ($all_xml as $xml) {
exert("sed -ri 's/(,osk=).+/\\1.../' ".escapeshellarg("$xml")." 2>/dev/null");
exert("sed -ri 's/(passwd=).+/\\1.../' ".escapeshellarg("$xml")." 2>/dev/null");
run("sed -ri 's/(,osk=).+/\\1.../' ".escapeshellarg("$xml")." 2>/dev/null");
run("sed -ri 's/(passwd=).+/\\1.../' ".escapeshellarg("$xml")." 2>/dev/null");
}
// copy syslog information (anonymize if applicable)
$max = 2*1024*1024; //=2MB
foreach (glob("/var/log/syslog*") as $file) {
$log = "/$diag/logs/".basename($file);
exert("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
if (!$all) {
unset($titles,$rows);
exert("grep -Po 'file: \K[^\"]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
exert("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
exert("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
run("grep -Po 'file: \K[^\"]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
run("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
run("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
foreach ($titles as $mover) {
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
exert("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
//exert("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
run("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
//run("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
exert("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) exert("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
run("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) run("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
// replace consecutive repeated lines in syslog
exert("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
run("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
// remove SHA256 hashes
exert("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
run("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
// truncate syslog if too big
if (basename($file)=='syslog' && filesize($file)>=$max) exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
if (basename($file)=='syslog' && filesize($file)>=$max) run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
}
// copy dhcplog
$dhcplog = "/var/log/dhcplog";
if (file_exists($dhcplog)) {
$log = "/$diag/logs/dhcplog.txt";
exert("todos <$dhcplog >".escapeshellarg($log));
run("todos <$dhcplog >".escapeshellarg($log));
}
// copy graphql-api.log
$graphql = "/var/log/graphql-api.log";
if (file_exists($graphql)) {
$log = "/$diag/logs/graphql-api.txt";
exert("todos <$graphql >".escapeshellarg($log));
run("todos <$graphql >".escapeshellarg($log));
}
// copy vfio-pci log
$vfiopci = "/var/log/vfio-pci";
if (file_exists($vfiopci)) {
$log = "/$diag/logs/vfio-pci.txt";
exert("todos <$vfiopci >".escapeshellarg($log));
run("todos <$vfiopci >".escapeshellarg($log));
}
// generate unraid-api.txt
if (file_exists("/usr/local/sbin/unraid-api")) {
$log = "/$diag/system/unraid-api.txt";
exert("unraid-api report | todos >".escapeshellarg($log));
run("unraid-api report | todos >".escapeshellarg($log));
}
// create resulting zip file and remove temp folder
exert("zip -qmr ".escapeshellarg($zip)." ".escapeshellarg("/$diag"));
run("zip -qmr ".escapeshellarg($zip)." ".escapeshellarg("/$diag"));
if ($cli) {
echo "done.\nZIP file '$zip' created.\n";
} else {
copy($zip,"/boot/logs/".basename($zip));
}
publish("diagnostic",basename($zip)."FINISHED");
// signal we are DONE
write('_DONE_');
?>

View File

@@ -3,9 +3,12 @@ body.stop-scrolling{height:100%;overflow:hidden}
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";/* IE8 */
background-color:rgba(0, 0, 0, 0.4);position:fixed;left:0;right:0;top:0;bottom:0;display:none;z-index:10000}
.sweet-alert{background-color:white;font-family:clear-sans;width:478px;padding:17px;border-radius:5px;text-align:center;position:fixed;left:50%;top:50%;margin-left:-256px;margin-top:-200px;overflow:hidden;display:none;z-index:99999}
.sweet-alert.nchan{height:600px;width:900px;margin-left:-480px}
@media all and (max-width:540px){.sweet-alert{width:auto;margin-left:0;margin-right:0;left:15px;right:15px}}
.sweet-alert h2{color:#575757;font-size:3rem;text-align:center;font-weight:600;text-transform:none;position:relative;margin:25px 0;padding:0;line-height:40px;display:block}
.sweet-alert pre h2{text-align:left;font-size:1.8rem;line-height:normal}
.sweet-alert p{color:#797979;font-size:1.5rem;text-align:center;font-weight:300;position:relative;text-align:inherit;float:none;margin:0;padding:0;line-height:normal}
.sweet-alert pre p{text-align:left;font-size:1.3rem}
.sweet-alert fieldset{border:none;position:relative}
.sweet-alert .sa-error-container{background-color:#f1f1f1;margin-left:-17px;margin-right:-17px;overflow:hidden;padding:0 10px;max-height:0;webkit-transition:padding 0.15s, max-height 0.15s;transition:padding 0.15s, max-height 0.15s}
.sweet-alert .sa-error-container.show{padding:10px 0;max-height:100px;webkit-transition:padding 0.2s, max-height 0.2s;transition:padding 0.25s, max-height 0.25s}