mirror of
https://github.com/unraid/webgui.git
synced 2026-04-24 11:19:25 -05:00
6d10f36547
To help with the usual questions of why are all my drives spinning up etc. Also helps with diagnosis with mover logging being disabled by default.
259 lines
13 KiB
PHP
Executable File
259 lines
13 KiB
PHP
Executable File
#!/usr/bin/php -q
|
|
<?PHP
|
|
/* Copyright 2005-2018, Lime Technology
|
|
* Copyright 2012-2018, 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.
|
|
*/
|
|
?>
|
|
<?
|
|
$opt = getopt('a',['all']);
|
|
$all = isset($opt['a']) || isset($opt['all']);
|
|
$zip = $all ? $argv[2] : $argv[1];
|
|
$cli = empty($zip);
|
|
$get = "/var/local/emhttp";
|
|
$var = file_exists("$get/var.ini") ? parse_ini_file("$get/var.ini") : [];
|
|
|
|
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
|
$folders = ['/boot','/boot/config','/boot/config/plugins','/boot/extra','/boot/syslinux','/var/log','/var/log/plugins','/var/log/packages','/tmp'];
|
|
|
|
function exert($cmd, &$save=null) {
|
|
// execute command with timeout of 30s
|
|
exec("timeout -s9 30 $cmd", $save);
|
|
return implode("\n",$save);
|
|
}
|
|
|
|
function anonymize($text,$select) {
|
|
global $all;
|
|
if ($all) return $text;
|
|
switch ($select) {
|
|
case 1:
|
|
$rows = explode("\n", $text);
|
|
foreach ($rows as &$row) {
|
|
if (!preg_match("/\b(disk|cache|parity|flash)\d*\b/", $row)) {
|
|
$row = preg_replace("/^(\s*\[\S).*(\S\])( => Array)$/","$1..$2$3",$row);
|
|
$row = preg_replace("/^(\s*\[(name|nameOrig|comment|flashGUID|regGUID|regTo|readList|writeList|csrf_token)\] => \S).*(\S)$/","$1..$3",$row);
|
|
}
|
|
}
|
|
return implode("\n", $rows);
|
|
case 2:
|
|
$name = basename($text,'.cfg');
|
|
$len = strlen($name);
|
|
if ($len>2) {
|
|
$dash = str_repeat('-',$len-2);
|
|
$name = preg_replace("/^(\S).*(\S)/","$1$dash$2",$name);
|
|
$i = 1;
|
|
while (file_exists(dirname($text)."/$name.cfg")) {$name = substr($name,0,$len)." ($i)"; $i++;}
|
|
}
|
|
return dirname($text)."/$name.cfg";
|
|
}
|
|
}
|
|
|
|
if ($cli) {
|
|
// script is called from CLI
|
|
echo "Starting diagnostics collection... ";
|
|
exert("mkdir -p /boot/logs");
|
|
$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
|
|
$diag = basename($zip, '.zip');
|
|
$split = explode('-', $diag);
|
|
$date = "{$split[2]}-{$split[3]}";
|
|
}
|
|
// create folder structure
|
|
exert("mkdir -p ".escapeshellarg("/$diag/system")." ".escapeshellarg("/$diag/config")." ".escapeshellarg("/$diag/logs")." ".escapeshellarg("/$diag/shares")." ".escapeshellarg("/$diag/smart")." ".escapeshellarg("/$diag/qemu"));
|
|
// get utilization of running processes
|
|
exert("top -bn1 -o%CPU 2>/dev/null|todos >".escapeshellarg("/$diag/system/top.txt"));
|
|
// make Unraid version reference
|
|
$unraid = parse_ini_file('/etc/unraid-version');
|
|
file_put_contents("/$diag/unraid-".$unraid['version'].".txt",$unraid['version']);
|
|
// 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".file_get_contents("/var/local/emhttp/cpuload.ini")."\r\n";
|
|
$diskload = file("/var/local/emhttp/diskload.ini");
|
|
$disks = parse_ini_file("/var/local/emhttp/disks.ini",true);
|
|
foreach ( $diskload as $loadLine ) {
|
|
$load = explode("=",$loadLine);
|
|
foreach ( $disks as $disk ) {
|
|
if ( $load[0] == $disk['device'] ) {
|
|
$loadTxt[] = "{$disk['device']} ({$disk['name']})=".trim($load[1]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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"));
|
|
// create ethernet information information (suppress errors)
|
|
foreach ($ports as $port) {
|
|
exert("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"));
|
|
file_put_contents("/$diag/system/ethtool.txt", "--------------------------------\r\n", FILE_APPEND);
|
|
}
|
|
exert("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"));
|
|
// 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"));
|
|
}
|
|
// copy configuration files (suppress errors)
|
|
exert("cp /boot/config/*.{cfg,conf,dat} /boot/config/go ".escapeshellarg("/$diag/config")." 2>/dev/null");
|
|
// anonymize configuration files
|
|
if (!$all) exert("sed -ri 's/^((disk|flash)(Read|Write)List.*=\")[^\"]+/\\1.../' ".escapeshellarg("/$diag/config/*.cfg")." 2>/dev/null");
|
|
|
|
// don't anonymize system share names
|
|
$vardomain = file_exists('/boot/config/domain.cfg') ? parse_ini_file('/boot/config/domain.cfg') : [];
|
|
$vardocker = file_exists('/boot/config/docker.cfg') ? 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';
|
|
$showshares[] = current(array_slice(explode('/',$vardomain['DISKDIR']), 3, 1)).'.cfg';
|
|
$showshares[] = current(array_slice(explode('/',$vardocker['DOCKER_IMAGE_FILE']), 3, 1)).'.cfg';
|
|
$showshares[] = current(array_slice(explode('/',$vardocker['DOCKER_APP_CONFIG_PATH']), 3, 1)).'.cfg';
|
|
$showshares[] = current(array_slice(explode('/',$vardocker['DOCKER_HOME']), 3, 1)).'.cfg';
|
|
|
|
// copy share information (anonymize if applicable)
|
|
$files = glob("/boot/config/shares/*.cfg");
|
|
foreach ($files as $file) {
|
|
$dest = "/$diag/shares/".basename($file);
|
|
if (!in_array(basename($file),$showshares)) {
|
|
$dest = anonymize($dest,2);
|
|
}
|
|
@copy($file, $dest);
|
|
if (!$all) exert("sed -ri 's/^(share(Comment|ReadList|WriteList)=\")[^\"]+/\\1.../' ".escapeshellarg($dest)." 2>/dev/null");
|
|
$share = pathinfo(basename($file),PATHINFO_FILENAME);
|
|
if ( is_dir("/mnt/user0/$share") ) { file_put_contents($dest,"# Share exists on array\r\n",FILE_APPEND); }
|
|
if ( is_dir("/mnt/cache/$share") ) { file_put_contents($dest,"# Share exists on cache drive\r\n",FILE_APPEND); }
|
|
}
|
|
// create default user shares information
|
|
$shares = file_exists("$get/shares.ini") ? 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");
|
|
if ( is_dir("/mnt/user0/$name") ) { file_put_contents($dest,"# Share exists on array\r\n",FILE_APPEND); }
|
|
if ( is_dir("/mnt/cache/$name") ) { file_put_contents($dest,"# Share exists on cache drive\r\n",FILE_APPEND); }
|
|
}
|
|
// 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"));
|
|
if (filesize($docker)>=$max) {
|
|
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
|
|
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
|
|
}
|
|
}
|
|
// create SMART reports (suppress errors)
|
|
$disks = file_exists("$get/disks.ini") ? parse_ini_file("$get/disks.ini", true) : [];
|
|
include_once "$docroot/webGui/include/CustomMerge.php";
|
|
include_once "$docroot/webGui/include/Wrappers.php";
|
|
exert("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 = '';
|
|
foreach ($disks as $find) {
|
|
if ($find['device']==$port) {
|
|
$diskName = $find['name'];
|
|
$type = get_value($find,'smType','');
|
|
get_ctlr_options($type, $find);
|
|
$port = $find['smDevice'] ?? $port;
|
|
break;
|
|
}
|
|
}
|
|
$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"));
|
|
}
|
|
// create cache pool information
|
|
if (is_dir('/mnt/cache') && strpos($disks['cache']['fsType'],'btrfs')!==false) {
|
|
exert("/sbin/btrfs filesystem usage -T /mnt/cache 2>/dev/null|todos >".escapeshellarg("/$diag/system/btrfs-usage.txt"));
|
|
}
|
|
// create installed plugin information
|
|
$plugins = glob("/var/log/plugins/*.plg");
|
|
foreach ($plugins as $plugin) {
|
|
$installedPlugins .= basename($plugin)." - ".exert("plugin version ".escapeshellarg($plugin))."\r\n";
|
|
}
|
|
$installedPlugins = $installedPlugins ?: "No additional Plugins Installed";
|
|
file_put_contents("/$diag/system/plugins.txt",$installedPlugins);
|
|
// 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"));
|
|
if (filesize($libvirtd)>=$max) {
|
|
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
|
|
exert("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"));
|
|
if (filesize($file)>=$max) {
|
|
exert("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
|
|
exert("truncate -s '<$max' ".escapeshellarg("$log.txt"));
|
|
}
|
|
}
|
|
} else
|
|
file_put_contents("/$diag/qemu/no qemu log files","");
|
|
// 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"));
|
|
if (!$all) {
|
|
unset($titles,$rows);
|
|
exert("grep -Po 'logger: moving \"\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|(host: \").+(\.unraid\.net:[0-9]+\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
|
|
foreach ($titles as $mover) {
|
|
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
|
|
exert("sed -ri 's|(logger: [.>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");
|
|
}
|
|
// 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"));
|
|
// 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"));
|
|
}
|
|
// create resulting zip file and remove temp folder
|
|
exert("zip -qmr ".escapeshellarg($zip)." ".escapeshellarg("/$diag"));
|
|
if ($cli) echo "done.\nZIP file '$zip' created.\n";
|
|
?>
|