package utils import ( "bufio" "fmt" "os" "os/exec" "strconv" "strings" "syscall" ) // FileExists checks if a file exists func FileExists(path string) bool { _, err := os.Stat(path) return !os.IsNotExist(err) } // ReadFileLines reads a file and returns its lines func ReadFileLines(path string) ([]string, error) { file, err := os.Open(path) if err != nil { return nil, err } defer file.Close() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } return lines, scanner.Err() } // ReadFirstLine reads the first line of a file func ReadFirstLine(path string) (string, error) { lines, err := ReadFileLines(path) if err != nil { return "", err } if len(lines) == 0 { return "", fmt.Errorf("file is empty") } return lines[0], nil } // ParseKeyValue parses a key=value string func ParseKeyValue(line string) (string, string, bool) { parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { return "", "", false } key := strings.TrimSpace(parts[0]) value := strings.TrimSpace(parts[1]) // Remove quotes if present value = strings.Trim(value, `"'`) return key, value, true } // ParseInt64 safely parses a string to int64 func ParseInt64(s string) int64 { val, err := strconv.ParseInt(s, 10, 64) if err != nil { return 0 } return val } // ParseInt safely parses a string to int func ParseInt(s string) int { val, err := strconv.Atoi(s) if err != nil { return 0 } return val } // IsRoot checks if the current user is root func IsRoot() bool { return os.Geteuid() == 0 } // RunCommand executes a command and returns its output func RunCommand(name string, args ...string) (string, error) { cmd := exec.Command(name, args...) output, err := cmd.Output() if err != nil { return "", err } return strings.TrimSpace(string(output)), nil } // RunCommandWithInput executes a command with stdin input func RunCommandWithInput(input, name string, args ...string) (string, error) { cmd := exec.Command(name, args...) cmd.Stdin = strings.NewReader(input) output, err := cmd.Output() if err != nil { return "", err } return strings.TrimSpace(string(output)), nil } // CommandExists checks if a command exists in PATH func CommandExists(cmd string) bool { _, err := exec.LookPath(cmd) return err == nil } // GetUserConfirmation prompts user for yes/no confirmation func GetUserConfirmation(prompt string) bool { fmt.Printf("%s (y/N): ", prompt) var response string fmt.Scanln(&response) response = strings.ToLower(strings.TrimSpace(response)) return response == "y" || response == "yes" } // GetUserInput prompts user for input with a default value func GetUserInput(prompt, defaultValue string) string { if defaultValue != "" { fmt.Printf("%s [%s]: ", prompt, defaultValue) } else { fmt.Printf("%s: ", prompt) } var input string fmt.Scanln(&input) input = strings.TrimSpace(input) if input == "" { return defaultValue } return input } // EnsureRoot ensures the program is running with root privileges func EnsureRoot() error { if !IsRoot() { return fmt.Errorf("this operation requires root privileges") } return nil } // RequestElevation requests privilege elevation using sudo func RequestElevation(args []string) error { if IsRoot() { return nil } fmt.Println("This operation requires elevated privileges.") if !GetUserConfirmation("Continue with sudo?") { return fmt.Errorf("operation cancelled by user") } // Prepare sudo command sudoArgs := append([]string{os.Args[0]}, args...) cmd := exec.Command("sudo", sudoArgs...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // Execute with sudo err := cmd.Run() if err != nil { if exitError, ok := err.(*exec.ExitError); ok { if status, ok := exitError.Sys().(syscall.WaitStatus); ok { os.Exit(status.ExitStatus()) } } return fmt.Errorf("failed to execute with elevated privileges: %w", err) } // Exit successfully since the elevated process completed os.Exit(0) return nil // This line will never be reached } // SanitizeInput sanitizes user input by removing potentially dangerous characters func SanitizeInput(input string) string { // Remove null bytes and control characters sanitized := strings.ReplaceAll(input, "\x00", "") sanitized = strings.TrimSpace(sanitized) // Basic validation - reject inputs with shell metacharacters dangerous := []string{";", "&", "|", "`", "$", "(", ")", "<", ">", "\"", "'"} for _, char := range dangerous { if strings.Contains(sanitized, char) { return "" } } return sanitized } // FormatBytes formats bytes into human-readable format func FormatBytes(bytes int64) string { const unit = 1024 if bytes < unit { return fmt.Sprintf("%d B", bytes) } div, exp := int64(unit), 0 for n := bytes / unit; n >= unit; n /= unit { div *= unit exp++ } units := []string{"KB", "MB", "GB", "TB", "PB"} return fmt.Sprintf("%.1f %s", float64(bytes)/float64(div), units[exp]) } // Contains checks if a slice contains a string func Contains(slice []string, item string) bool { for _, s := range slice { if s == item { return true } } return false } // RemoveEmpty removes empty strings from a slice func RemoveEmpty(slice []string) []string { var result []string for _, s := range slice { if strings.TrimSpace(s) != "" { result = append(result, s) } } return result }