From ad3c02c22c281b98fe7acecd14969da0957e9f24 Mon Sep 17 00:00:00 2001 From: kdwycz Date: Mon, 15 Sep 2025 20:23:56 +0800 Subject: [PATCH] Merge branch 'main' into dev --- install.ps1 | 1 + install.sh | 39 +++++++-- monitoring/unit/mem.go | 2 +- monitoring/unit/os_linux.go | 163 +++++++++++++++++++++++++++++++----- 4 files changed, 176 insertions(+), 29 deletions(-) diff --git a/install.ps1 b/install.ps1 index a5869ba..2579296 100644 --- a/install.ps1 +++ b/install.ps1 @@ -40,6 +40,7 @@ if ($GitHubProxy -ne '') { $ProxyDisplay = $GitHubProxy } else { $ProxyDisplay = switch ($env:PROCESSOR_ARCHITECTURE) { 'AMD64' { $arch = 'amd64' } 'ARM64' { $arch = 'arm64' } + 'x86' { $arch = '386' } Default { Log-Error "Unsupported architecture: $env:PROCESSOR_ARCHITECTURE"; exit 1 } } diff --git a/install.sh b/install.sh index 4d68bd7..8d24b33 100755 --- a/install.sh +++ b/install.sh @@ -57,6 +57,13 @@ case $os_type in Linux) os_name="linux" ;; + FreeBSD) + os_name="freebsd" + ;; + MINGW*|MSYS*|CYGWIN*) + os_name="windows" + target_dir="/c/komari" # Use C:\komari on Windows + ;; *) log_error "Unsupported operating system: $os_type" exit 1 @@ -295,23 +302,45 @@ install_dependencies # Install vnstat if needed for month-rotate install_vnstat +# Architecture detection with platform-specific support arch=$(uname -m) case $arch in x86_64) arch="amd64" ;; - aarch64) + aarch64|arm64) arch="arm64" ;; - arm64) - arch="arm64" + i386|i686) + # x86 (32-bit) support + case $os_name in + freebsd|linux|windows) + arch="386" + ;; + *) + log_error "32-bit x86 architecture not supported on $os_name" + exit 1 + ;; + esac + ;; + armv7*|armv6*) + # ARM 32-bit support + case $os_name in + freebsd|linux) + arch="arm" + ;; + *) + log_error "32-bit ARM architecture not supported on $os_name" + exit 1 + ;; + esac ;; *) - log_error "Unsupported architecture: $arch" + log_error "Unsupported architecture: $arch on $os_name" exit 1 ;; esac -log_info "Detected architecture: ${GREEN}$arch${NC}" +log_info "Detected OS: ${GREEN}$os_name${NC}, Architecture: ${GREEN}$arch${NC}" version_to_install="latest" if [ -n "$install_version" ]; then diff --git a/monitoring/unit/mem.go b/monitoring/unit/mem.go index 4926398..1b8f7e2 100644 --- a/monitoring/unit/mem.go +++ b/monitoring/unit/mem.go @@ -24,7 +24,7 @@ func Ram() RamInfo { return raminfo } raminfo.Total = v.Total - raminfo.Used = v.Used + raminfo.Used = v.Total - v.Available return raminfo } diff --git a/monitoring/unit/os_linux.go b/monitoring/unit/os_linux.go index eb2fae0..3caa991 100644 --- a/monitoring/unit/os_linux.go +++ b/monitoring/unit/os_linux.go @@ -11,14 +11,21 @@ import ( ) func OSName() string { + // Check if it's an Android system + if androidVersion := detectAndroid(); androidVersion != "" { + return androidVersion + } + + // Check if it's a Proxmox VE if pveVersion := detectProxmoxVE(); pveVersion != "" { return pveVersion } - + + // Check if it's a Synology if synologyName := detectSynology(); synologyName != "" { return synologyName } - + file, err := os.Open("/etc/os-release") if err != nil { return "Linux" @@ -45,7 +52,7 @@ func detectSynology() string { "/etc/synoinfo.conf", "/etc.defaults/synoinfo.conf", } - + for _, file := range synologyFiles { if info, err := os.Stat(file); err == nil && !info.IsDir() { if synologyInfo := readSynologyInfo(file); synologyInfo != "" { @@ -53,11 +60,11 @@ func detectSynology() string { } } } - + if info, err := os.Stat("/usr/syno"); err == nil && info.IsDir() { return "Synology DSM" } - + return "" } @@ -67,37 +74,37 @@ func readSynologyInfo(filename string) string { return "" } defer file.Close() - + var unique, udcCheckState string - + scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) - + if strings.HasPrefix(line, "unique=") { unique = strings.Trim(strings.TrimPrefix(line, "unique="), `"`) } else if strings.HasPrefix(line, "udc_check_state=") { udcCheckState = strings.Trim(strings.TrimPrefix(line, "udc_check_state="), `"`) } } - + if unique != "" && strings.Contains(unique, "synology_") { parts := strings.Split(unique, "_") if len(parts) >= 3 { model := strings.ToUpper(parts[len(parts)-1]) - + result := "Synology " + model - + if udcCheckState != "" { result += " DSM " + udcCheckState } else { result += " DSM" } - + return result } } - + return "" } @@ -105,21 +112,21 @@ func detectProxmoxVE() string { if _, err := exec.LookPath("pveversion"); err != nil { return "" } - + out, err := exec.Command("pveversion").Output() if err != nil { return "" } - + output := strings.TrimSpace(string(out)) lines := strings.Split(output, "\n") - + var version string var codename string - + for _, line := range lines { line = strings.TrimSpace(line) - + if strings.HasPrefix(line, "pve-manager/") { parts := strings.Split(line, "/") if len(parts) >= 2 { @@ -130,9 +137,9 @@ func detectProxmoxVE() string { version = versionPart } } - + } - + if version != "" { if file, err := os.Open("/etc/os-release"); err == nil { defer file.Close() @@ -146,23 +153,133 @@ func detectProxmoxVE() string { } } } - + if version != "" { if codename != "" { return "Proxmox VE " + version + " (" + codename + ")" } return "Proxmox VE " + version } - + return "Proxmox VE" } +// detectAndroid detects if the system is Android and returns detailed information +func detectAndroid() string { + // 1. Try to get Android version info using the getprop command + cmdGetprop := exec.Command("getprop", "ro.build.version.release") + version, err := cmdGetprop.Output() + if err == nil && len(version) > 0 { + versionStr := strings.TrimSpace(string(version)) + + // Get device model + cmdGetModel := exec.Command("getprop", "ro.product.model") + model, err2 := cmdGetModel.Output() + modelStr := strings.TrimSpace(string(model)) + + // Get manufacturer information + cmdGetBrand := exec.Command("getprop", "ro.product.brand") + brand, err3 := cmdGetBrand.Output() + brandStr := strings.TrimSpace(string(brand)) + + result := "Android " + versionStr + + // Add brand and model information (if available) + if err2 == nil && modelStr != "" { + if err3 == nil && brandStr != "" && brandStr != modelStr { + result += " (" + brandStr + " " + modelStr + ")" + } else { + result += " (" + modelStr + ")" + } + } + + return result + } + + // 2. Try to check Android system build.prop file + if _, err := os.Stat("/system/build.prop"); err == nil { + return readAndroidBuildProp() + } + + // 3. Check for typical Android directory structure + if isAndroidSystem() { + return "Android" + } + + return "" +} + +// readAndroidBuildProp reads Android version information from build.prop file +func readAndroidBuildProp() string { + file, err := os.Open("/system/build.prop") + if err != nil { + return "Android" + } + defer file.Close() + + var version, model, brand string + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + + if strings.HasPrefix(line, "ro.build.version.release=") { + version = strings.TrimPrefix(line, "ro.build.version.release=") + } else if strings.HasPrefix(line, "ro.product.model=") { + model = strings.TrimPrefix(line, "ro.product.model=") + } else if strings.HasPrefix(line, "ro.product.brand=") { + brand = strings.TrimPrefix(line, "ro.product.brand=") + } + + // If all information has been collected, we can exit early + if version != "" && model != "" && brand != "" { + break + } + } + + if version != "" { + result := "Android " + version + + if model != "" { + if brand != "" && brand != model { + result += " (" + brand + " " + model + ")" + } else { + result += " (" + model + ")" + } + } + + return result + } + + return "Android" +} + +// isAndroidSystem determines if the system is Android by checking typical directory structure +func isAndroidSystem() bool { + androidDirs := []string{ + "/system/app", + "/system/priv-app", + "/data/app", + "/sdcard", + } + + dirCount := 0 + for _, dir := range androidDirs { + if info, err := os.Stat(dir); err == nil && info.IsDir() { + dirCount++ + } + } + + // Consider it an Android system only if at least 2 directories exist + return dirCount >= 2 +} + // KernelVersion returns the kernel version on Linux systems func KernelVersion() string { out, err := exec.Command("uname", "-r").Output() if err != nil { return "Unknown" } - + return strings.TrimSpace(string(out)) }