diff --git a/plugins/dynamix.plugin.manager/PluginHelpers.page b/plugins/dynamix.plugin.manager/PluginHelpers.page index a39f746cf..ddc642d82 100644 --- a/plugins/dynamix.plugin.manager/PluginHelpers.page +++ b/plugins/dynamix.plugin.manager/PluginHelpers.page @@ -15,14 +15,22 @@ Link='nav-user' ?> diff --git a/plugins/dynamix.plugin.manager/PluginInstall.page b/plugins/dynamix.plugin.manager/PluginInstall.page index 86d0bccc6..3c7275cd0 100644 --- a/plugins/dynamix.plugin.manager/PluginInstall.page +++ b/plugins/dynamix.plugin.manager/PluginInstall.page @@ -15,17 +15,31 @@ Tag="download" */ ?> + **_(Enter URL of remote plugin file or local plugin file)_**
diff --git a/plugins/dynamix.plugin.manager/Plugins.page b/plugins/dynamix.plugin.manager/Plugins.page index f536bdc9d..3f0717a0f 100644 --- a/plugins/dynamix.plugin.manager/Plugins.page +++ b/plugins/dynamix.plugin.manager/Plugins.page @@ -18,8 +18,10 @@ Code="e944" */ ?> @@ -27,8 +29,29 @@ $check = $notify['version'] ? 0 : 1; #plugin_tree{width:33%;height:200px;overflow-y:scroll} table tbody td{line-height:normal} + diff --git a/plugins/dynamix.plugin.manager/Update.page b/plugins/dynamix.plugin.manager/Update.page index 4e25e6c42..9d41425a6 100644 --- a/plugins/dynamix.plugin.manager/Update.page +++ b/plugins/dynamix.plugin.manager/Update.page @@ -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} +
diff --git a/plugins/dynamix.plugin.manager/include/PluginHelpers.php b/plugins/dynamix.plugin.manager/include/PluginHelpers.php index df9c88aba..6c95d4b5d 100644 --- a/plugins/dynamix.plugin.manager/include/PluginHelpers.php +++ b/plugins/dynamix.plugin.manager/include/PluginHelpers.php @@ -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' ? "" : ""; + $check = $method=='remove' ? "" : ""; $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"; + return "$check"; } // trying our best to find an icon diff --git a/plugins/dynamix.plugin.manager/include/ShowPlugins.php b/plugins/dynamix.plugin.manager/include/ShowPlugins.php index e2b5ab0ee..82f0b5a6a 100644 --- a/plugins/dynamix.plugin.manager/include/ShowPlugins.php +++ b/plugins/dynamix.plugin.manager/include/ShowPlugins.php @@ -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 .= " "; + $version .= " "; } 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 ""; if (!$init && !$os) echo "\0".$updates; -if (!$init && file_exists($alerts)) echo "\0".$alerts; ?> diff --git a/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks b/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks new file mode 100755 index 000000000..f8b529c81 --- /dev/null +++ b/plugins/dynamix.plugin.manager/post-hooks/post_plugin_checks @@ -0,0 +1,54 @@ +#!/usr/bin/php -q + +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()); + } + } +} +?> diff --git a/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks b/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks new file mode 100755 index 000000000..997e1d0e6 --- /dev/null +++ b/plugins/dynamix.plugin.manager/pre-hooks/pre_plugin_checks @@ -0,0 +1,34 @@ +#!/usr/bin/php -q + + 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); + } + } +} +?> diff --git a/plugins/dynamix.plugin.manager/scripts/PluginAPI.php b/plugins/dynamix.plugin.manager/scripts/PluginAPI.php index 5a2ffcd18..41d6cc442 100644 --- a/plugins/dynamix.plugin.manager/scripts/PluginAPI.php +++ b/plugins/dynamix.plugin.manager/scripts/PluginAPI.php @@ -1,6 +1,6 @@ $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; -} +} ?> \ No newline at end of file diff --git a/plugins/dynamix.plugin.manager/scripts/checkall b/plugins/dynamix.plugin.manager/scripts/checkall index 1a797eda2..c9924b3a5 100755 --- a/plugins/dynamix.plugin.manager/scripts/checkall +++ b/plugins/dynamix.plugin.manager/scripts/checkall @@ -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"); } ?> \ No newline at end of file diff --git a/plugins/dynamix.plugin.manager/scripts/language b/plugins/dynamix.plugin.manager/scripts/language index 1bbb42321..7a2265937 100755 --- a/plugins/dynamix.plugin.manager/scripts/language +++ b/plugins/dynamix.plugin.manager/scripts/language @@ -1,9 +1,11 @@ #!/usr/bin/php -q '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); ?> diff --git a/plugins/dynamix.plugin.manager/scripts/multiplugin b/plugins/dynamix.plugin.manager/scripts/multiplugin new file mode 100755 index 000000000..e704e0068 --- /dev/null +++ b/plugins/dynamix.plugin.manager/scripts/multiplugin @@ -0,0 +1,48 @@ +#!/usr/bin/php -q + + '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"); +} +?> diff --git a/plugins/dynamix.plugin.manager/scripts/plugin b/plugins/dynamix.plugin.manager/scripts/plugin index 8042c409e..419fde618 100755 --- a/plugins/dynamix.plugin.manager/scripts/plugin +++ b/plugins/dynamix.plugin.manager/scripts/plugin @@ -4,6 +4,8 @@ // License: GPLv2 only // // Program updates made by Bergware International (April 2020) +// Program updates made by Bergware International (June 2022) + $usage = << '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); } -// +// 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); ?> diff --git a/plugins/dynamix.plugin.manager/scripts/plugin_rm b/plugins/dynamix.plugin.manager/scripts/plugin_rm index b7f63e8bc..bcd608d65 100755 --- a/plugins/dynamix.plugin.manager/scripts/plugin_rm +++ b/plugins/dynamix.plugin.manager/scripts/plugin_rm @@ -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 diff --git a/plugins/dynamix.plugin.manager/scripts/showchanges b/plugins/dynamix.plugin.manager/scripts/showchanges new file mode 100755 index 000000000..7e681b770 --- /dev/null +++ b/plugins/dynamix.plugin.manager/scripts/showchanges @@ -0,0 +1,50 @@ +#!/usr/bin/php -q + + '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')."!*")); +} +?> diff --git a/plugins/dynamix/Apps.page b/plugins/dynamix/Apps.page index be4dc0e37..e816baebf 100644 --- a/plugins/dynamix/Apps.page +++ b/plugins/dynamix/Apps.page @@ -3,8 +3,8 @@ Name="Apps" Code="e942" --- 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"); } diff --git a/plugins/dynamix/Diagnostics.page b/plugins/dynamix/Diagnostics.page index 44764eb79..c7181e57b 100644 --- a/plugins/dynamix/Diagnostics.page +++ b/plugins/dynamix/Diagnostics.page @@ -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} + :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. diff --git a/plugins/dynamix/include/DefaultPageLayout.php b/plugins/dynamix/include/DefaultPageLayout.php index 8d47ebf38..6955bfdce 100644 --- a/plugins/dynamix/include/DefaultPageLayout.php +++ b/plugins/dynamix/include/DefaultPageLayout.php @@ -21,7 +21,7 @@ $config = "/boot/config"; $entity = $notify['entity'] & 1 == 1; $alerts = '/tmp/plugins/my_alerts.txt'; -function annotate($text) {echo "\n\n";} +function annotate($text) {echo "\n\n";} ?> lang=""> @@ -59,10 +59,13 @@ html{font-size:%} .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} "; +$notes = " "; ?> @@ -100,9 +103,15 @@ var expiretime = "; @@ -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=' : '/logging.htm?cmd='+cmd+'&csrf_token='+csrf_token+'&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+'
',text:"

",html:true,animation:'none',confirmButtonText:""},function(){ + plugins.stop(); + $('.sweet-alert').hide('fast').removeClass('nchan'); + setTimeout(function(){bannerAlert("",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+'
',text:"

",html:true,animation:'none',confirmButtonText:""},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+'
',text:"

",html:true,animation:'none',showCancelButton:true,confirmButtonText:"",cancelButtonText:""},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 = " "+text; + if (warning) text = " "+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 += ""; 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="",600,900); + openChanges("showchanges /tmp/plugins/unRAIDServer.txt",""); } function showUpgrade(text,noDismiss=false) { if ($.cookie('os_upgrade')==null) { @@ -321,11 +400,6 @@ function showUpgrade(text,noDismiss=false) { osUpgradeWarning = addBannerWarning(text.replace(/(.+?)<\/a>/,"$1").replace(/(.*)<\/b>/,"$1"),false,noDismiss); } } -function confirmUpgrade() { - swal({title:" Unraid OS",text:"?",type:'warning',html:true,showCancelButton:true,confirmButtonText:"",cancelButtonText:""},function(){ - openBox("/plugins/dynamix.plugin.manager/scripts/plugin&arg1=update&arg2=unRAIDServer.plg"," 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:" Unraid OS",text:"?",type:'warning',html:true,showCancelButton:true,confirmButtonText:"",cancelButtonText:""},function(){ + setTimeout(function(){openPlugin("plugin update unRAIDServer.plg"," Unraid OS");},250); + }); + } else { + setTimeout(function(){openPlugin("plugin update unRAIDServer.plg"," Unraid OS");},250); + } +} function openUpgrade() { hideUpgrade(); - - openBox('/plugins/dynamix.plugin.manager/include/ShowChanges.php?file=',"",600,900,true,'confirmUpgrade'); - - confirmUpgrade(); - + $.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 ","",'confirmUpgrade'); + } + }); } function digits(number) { if (number < 10) return 'one'; @@ -626,7 +713,7 @@ defaultPage.on('message', function(msg,meta) { case 'Formatting': var status = " "; break; default : var status = " "+_('Array '+ini['fsState'])+""; } - if (ini['mdResyncPos']>0) { + if (ini['mdResyncPos'] > 0) { var resync = ini['mdResyncAction'].split(/\s+/); switch (resync[0]) { case 'recon': var action = resync[1]=='P' ? "" : ""; 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('
'); + if (data.slice(-1) == '\r') { + text[text.length-1] = data.slice(0,-1); + } else { + text.push(data.slice(0,-1)); + } + box.html(text.join('
')).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); showNotice(" "); diff --git a/plugins/dynamix/include/Download.php b/plugins/dynamix/include/Download.php index ebb9c3629..fe1f0f986 100644 --- a/plugins/dynamix/include/Download.php +++ b/plugins/dynamix/include/Download.php @@ -1,6 +1,6 @@ /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': diff --git a/plugins/dynamix/include/StartCommand.php b/plugins/dynamix/include/StartCommand.php new file mode 100644 index 000000000..61b5e3b8a --- /dev/null +++ b/plugins/dynamix/include/StartCommand.php @@ -0,0 +1,40 @@ + +/dev/null 2>&1"); + $pid = 1; // started + } +} +echo $pid; +?> diff --git a/plugins/dynamix/scripts/diagnostics b/plugins/dynamix/scripts/diagnostics index 3707936ff..b00df533c 100755 --- a/plugins/dynamix/scripts/diagnostics +++ b/plugins/dynamix/scripts/diagnostics @@ -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 ".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 ".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_'); ?> diff --git a/plugins/dynamix/styles/jquery.sweetalert.css b/plugins/dynamix/styles/jquery.sweetalert.css index 9873db2a7..c18243996 100644 --- a/plugins/dynamix/styles/jquery.sweetalert.css +++ b/plugins/dynamix/styles/jquery.sweetalert.css @@ -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}
"._('No plugins installed')."