From c901ee769bd725c1e67c76761cd7a3e0373e56e7 Mon Sep 17 00:00:00 2001 From: nazunalika Date: Mon, 27 Dec 2021 11:45:46 -0700 Subject: [PATCH] Add SysInfo Functions Add sysinfo functions, template updates, stuff like that --- modules/paste/method.go | 62 ++++---- modules/paste/sysinfo.go | 294 ++++++++++++++++++++++++++++++++++++ modules/setting/template.go | 129 ++++++++++++++++ modules/utility/pipes.go | 53 +++++++ 4 files changed, 502 insertions(+), 36 deletions(-) create mode 100644 modules/setting/template.go create mode 100644 modules/utility/pipes.go diff --git a/modules/paste/method.go b/modules/paste/method.go index 89202d8..7b5ffe7 100644 --- a/modules/paste/method.go +++ b/modules/paste/method.go @@ -3,6 +3,7 @@ package paste import ( "fmt" + "io/ioutil" "os" "github.com/rocky-linux/rpaste/modules/utility" @@ -21,47 +22,36 @@ var ( func runPaste(ctx *cli.Context) error { // check - stdResults := utility.StdInChecker() + stdMethod := utility.StdInChecker() + sysInfoMethod := ctx.Bool("sysinfo") - // If there's no more than 1 argument (the executable itself is arg 0), we - // will check for stdin, and if not, print out the usage information. - //if stdResults { - // fio, err := os.Stdin.Stat() - // if (fio.Mode() & os.ModeCharDevice) == 0 { - // bytes, _ := ioutil.ReadAll(os.Stdin) - // PasteData = string(bytes) - // } else if err != nil { - // fmt.Printf("Could not read from stdin: (%s)\n", err) - // os.Exit(1) - // } - //} else { - // cli.ShowAppHelp(ctx) - // os.Exit(0) - //} + // Check sysinfo is enabled and run through all the required stuff + if sysInfoMethod { + PasteData = SysInfoGather() + } - // Check args for a file or sysinfo - //if len(PasteData) == 0 { - // if ctx.Bool("sysinfo") { - // //PasteData = GatherSysInfo() - // PasteData = "Sys Info" - // } else { - // // Path is expected at the end of the command (matches current rpaste) - // argList := os.Args - // lastArg := argList[len(argList)-1] - // fileBytes, err := ioutil.ReadFile(lastArg) - // if err != nil { - // panic(err) - // } - // PasteData = string(fileBytes) - // } - //} + if stdMethod && PasteData == "" { + fio, err := os.Stdin.Stat() + if (fio.Mode() & os.ModeCharDevice) == 0 { + bytes, _ := ioutil.ReadAll(os.Stdin) + PasteData = string(bytes) + } else if err != nil { + fmt.Printf("Could not read from stdin: (%s)\n", err) + os.Exit(1) + } + } else if !stdMethod && PasteData == "" { + argList := os.Args + lastArg := argList[len(argList)-1] + fileBytes, err := ioutil.ReadFile(lastArg) + if err != nil { + panic(err) + } + PasteData = string(fileBytes) + } // Check that PasteData is text, and not binary - fmt.Println(len(PasteData)) - for i, arg := range os.Args { - fmt.Println("item", i, "is", arg) - } + fmt.Println(PasteData) return nil } diff --git a/modules/paste/sysinfo.go b/modules/paste/sysinfo.go index 79d30f5..f62a730 100644 --- a/modules/paste/sysinfo.go +++ b/modules/paste/sysinfo.go @@ -1,2 +1,296 @@ // sysinfo package paste + +import ( + "bytes" + "io/ioutil" + "os/exec" + "regexp" + "strconv" + "strings" + "text/template" + + "github.com/rocky-linux/rpaste/modules/setting" +) + +var ( + buf bytes.Buffer +) + +type SystemInfo struct { + OsRelease string + DesktopEnvs string + DesktopInstalled string + SELinuxStatus string + SELinuxErrors string + CPUInfo string + Support64bit string + VirtSupport string + LoadAverage string + MemUsage string + TopCPUHogs string + TopMemHogs string + DiskUsage string + BlockDevs string + PciDevs string + USBDevs string + DRMInfo string + XorgModules string + GLSupport string + XorgErrors string + DmesgTail string + LastTenReboots string + DnfRepoList string + DnfRepoFiles string + YumConf string + LastTwentyPackages string + EFISupport string +} + +func osRelease() string { + app := "uniq" + args := []string{"/etc/os-release"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + + return string(cmd) +} + +func desktopEnvs() string { + // The below just returns whatever the match is, rather than each match. The + // original command (and by extension, the original fpaste python script and + // rpaste bash script) would spit out more than just the expected result + app := "ps" + args := []string{ + "-eo", + "comm=", + } + cmd, _ := exec.Command(app, args...).CombinedOutput() + re, _ := regexp.Compile(`(gnome-session|startkde|startactive|xfce.?-session|fluxbox|blackbox|hackedbox|ratpoison|enlightenment|icewm-session|od-session|wmaker|wmx|openbox-lxde|openbox-gnome-session|openbox-kde-session|mwm|e16|fvwm|xmonad|sugar-session|mate-session|lxqt-session|cinnamon)`) + values := re.FindString(string(cmd)) + return values +} + +func desktopInstalled() string { + app := "ls" + args := []string{ + "-m", + "/usr/share/xsessions/", + } + cmd, _ := exec.Command(app, args...).CombinedOutput() + re, _ := regexp.Compile(`\.desktop`) + values := re.ReplaceAllString(string(cmd), "") + return values +} + +func selinuxStatus() string { + app1 := "getenforce" + app2 := "grep -v '^#' /etc/sysconfig/selinux" + cmd1, _ := exec.Command(app1).CombinedOutput() + cmd2, _ := exec.Command("/bin/sh", "-c", app2).CombinedOutput() + combined := string(cmd1) + string(cmd2) + return combined +} + +func selinuxErrors() string { + // I'm not proud of this + app := "journalctl --since yesterday |grep avc: | grep -Eo comm='[^ ]+' | sort |uniq -c |sort -rn" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func cpuInfo() string { + // I'm not proud of this + app := "grep 'model name' /proc/cpuinfo | awk -F: '{print $2}' | uniq -c | sed -re 's/^ +//'" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func support64Bit() string { + text := " lm " + file, _ := ioutil.ReadFile("/proc/cpuinfo") + string := string(file) + return strconv.FormatBool(strings.Contains(string, text)) +} + +func virtSupport() string { + re, _ := regexp.Compile(`(vmx|svm)`) + file, _ := ioutil.ReadFile("/proc/cpuinfo") + exists := re.Match(file) + return strconv.FormatBool(exists) +} + +func loadAverage() string { + app := "uptime" + cmd, _ := exec.Command(app).CombinedOutput() + return string(cmd) +} + +func memUsage() string { + app := "free" + args := []string{"-m"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func topCPUHogs() string { + // I'm not proud of this + app := "ps axuScnh | sort -rnk3 | head -5" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func topMemHogs() string { + // I'm not proud of this + app := "ps axuScnh | sort -rnk4 | head -5" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func diskUsage() string { + app := "df" + args := []string{"-hT"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func blockDevs() string { + app := "/sbin/blkid" + cmd, _ := exec.Command(app).CombinedOutput() + return string(cmd) +} + +func pciDevs() string { + app := "/sbin/lspci" + args := []string{"-nn"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func usbDevs() string { + app := "/bin/lsusb" + cmd, _ := exec.Command(app).CombinedOutput() + return string(cmd) +} + +func drmInfo() string { + // I'm not proud of this + app := "journalctl -k -b | grep -o 'kernel:.*drm.*$' | cut -d ' ' -f 2-" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func xorgModules() string { + // I'm not proud of this + app := "grep LoadModule /var/log/Xorg.0.log ~/.local/share/xorg/Xorg.0.log | cut -d '\"' -f 2 | xargs" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func glSupport() string { + // I'm not proud of this + // turn to golang regexp? we would rather get the error output regardless + app := "glxinfo | grep -E 'OpenGL version|OpenGL renderer'" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func xorgErrors() string { + // I'm not proud of this + app := "grep '^\\[.*(EE)' /var/log/Xorg.0.log ~/.local/share/xorg/Xorg.0.log | cut -d ':' -f 2-" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func dmesgTail() string { + // I'm not proud of this + // Maybe I can implement a tail-like function + app := "dmesg | tail" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func lastTenReboots() string { + app := "last" + args := []string{ + "-x", + "-n10", + "reboot", + "runlevel", + } + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func dnfRepoList() string { + app := "dnf" + args := []string{"repolist"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func dnfRepoFiles() string { + app := "ls" + args := []string{ + "-l", + "/etc/yum.repos.d/", + } + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func yumConf() string { + app := "grep -v '^#' /etc/yum.conf" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func lastTwentyPkgs() string { + app := "rpm -qa --nodigest --nosignature --last | head -20" + cmd, _ := exec.Command("/bin/sh", "-c", app).CombinedOutput() + return string(cmd) +} + +func efiSupport() string { + app := "efibootmgr" + args := []string{"-v"} + cmd, _ := exec.Command(app, args...).CombinedOutput() + return string(cmd) +} + +func SysInfoGather() string { + sysInfoData := SystemInfo{ + OsRelease: osRelease(), + DesktopEnvs: desktopEnvs(), + DesktopInstalled: desktopInstalled(), + SELinuxStatus: selinuxStatus(), + SELinuxErrors: selinuxErrors(), + CPUInfo: cpuInfo(), + Support64bit: support64Bit(), + VirtSupport: virtSupport(), + LoadAverage: loadAverage(), + MemUsage: memUsage(), + TopCPUHogs: topCPUHogs(), + TopMemHogs: topMemHogs(), + DiskUsage: diskUsage(), + BlockDevs: blockDevs(), + PciDevs: pciDevs(), + USBDevs: usbDevs(), + DRMInfo: drmInfo(), + XorgModules: xorgModules(), + GLSupport: glSupport(), + XorgErrors: xorgErrors(), + DmesgTail: dmesgTail(), + LastTenReboots: lastTenReboots(), + DnfRepoList: dnfRepoList(), + DnfRepoFiles: dnfRepoFiles(), + YumConf: yumConf(), + LastTwentyPackages: lastTwentyPkgs(), + EFISupport: efiSupport(), + } + + t := template.New("sysinfo") + t, _ = t.Parse(setting.SysInfoTemplate) + t.Execute(&buf, sysInfoData) + sysInfoResults := buf.String() + return sysInfoResults +} diff --git a/modules/setting/template.go b/modules/setting/template.go new file mode 100644 index 0000000..8a68cdc --- /dev/null +++ b/modules/setting/template.go @@ -0,0 +1,129 @@ +package setting + +var SysInfoTemplate = `################################################################################ +# OS Release +# +{{.OsRelease}} + +################################################################################ +# Desktop Environments +# +{{.DesktopEnvs}} + +################################################################################ +# Desktop Installed +# +{{.DesktopInstalled}} + +################################################################################ +# SELinux Status +# +{{.SELinuxStatus}} + +################################################################################ +# SELinux Errors +# +{{.SELinuxErrors}} + +################################################################################ +# CPU Info +# +{{.CPUInfo}} + +################################################################################ +# 64-bit Support +# +{{.Support64bit}} + +################################################################################ +# Virtualization Support +# +{{.VirtSupport}} + +################################################################################ +# Load Average +# +{{.LoadAverage}} + +################################################################################ +# Memory usage +# +{{.MemUsage}} + +################################################################################ +# Top 5 CPU hogs +# +{{.TopCPUHogs}} + +################################################################################ +# Top 5 memory hogs +# +{{.TopMemHogs}} + +################################################################################ +# Disk space usage +# +{{.DiskUsage}} + +################################################################################ +# Block Devices +# +{{.BlockDevs}} + +################################################################################ +# PCI devices +# +{{.PciDevs}} + +################################################################################ +# USB devices +# +{{.USBDevs}} + +################################################################################ +# DRM Information +# +{{.DRMInfo}} + +################################################################################ +# Xorg modules +# +{{.XorgModules}} + +################################################################################ +# GL Support +# +{{.GLSupport}} + +################################################################################ +# Xorg errors +# +{{.XorgErrors}} + +################################################################################ +# Kernel Buffer Tail +# +{{.DmesgTail}} + +################################################################################ +# Last few reboots +# +{{.LastTenReboots}} + +################################################################################ +# DNF Repos +# +{{.DnfRepoList}} +{{.DnfRepoFiles}} +{{.YumConf}} + +################################################################################ +# Last 20 packages +# +{{.LastTwentyPackages}} + +################################################################################ +# EFI Support +# +{{.EFISupport}} +` diff --git a/modules/utility/pipes.go b/modules/utility/pipes.go new file mode 100644 index 0000000..6ad9a84 --- /dev/null +++ b/modules/utility/pipes.go @@ -0,0 +1,53 @@ +package utility + +import ( + "bytes" + "io" + "log" + "os/exec" +) + +func ExecutePipe(outbuffer *bytes.Buffer, stack ...*exec.Cmd) (err error) { + var errbuffer bytes.Buffer + pipestack := make([]*io.PipeWriter, len(stack)-1) + i := 0 + + for ; i < len(stack)-1; i++ { + stdin_pipe, stdoutpipe := io.Pipe() + stack[i].Stdout = stdoutpipe + stack[i].Stderr = &errbuffer + stack[i+1].Stdin = stdin_pipe + pipestack[i] = stdoutpipe + } + + stack[i].Stdout = outbuffer + stack[i].Stderr = &errbuffer + + if err := callpipe(stack, pipestack); err != nil { + log.Fatalln(string(errbuffer.Bytes()), err) + } + + return err +} + +func callpipe(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) { + if stack[0].Process == nil { + if err = stack[0].Start(); err != nil { + return err + } + } + + if len(stack) > 1 { + if err = stack[1].Start(); err != nil { + return err + } + defer func() { + if err == nil { + pipes[0].Close() + err = callpipe(stack[1:], pipes[1:]) + } + }() + } + + return stack[0].Wait() +}