package sys import ( "bytes" "errors" "fmt" "io" "os" "os/exec" "os/signal" "os/user" "strconv" "strings" "syscall" "golang.org/x/sys/unix" ) var TERM_WIDTH = 50 func RunSilentCmd(cmd *exec.Cmd) int { err := cmd.Run() return ManageStatusCmd(cmd, err) } func RunBufferedCmd(cmd *exec.Cmd, out *bytes.Buffer) int { rs1, err := cmd.CombinedOutput() if err != nil { fmt.Println("Error: ", err) } out.Write(rs1) return ManageStatusCmd(cmd, err) } func RunCmd(cmd *exec.Cmd) int { cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return ManageStatusCmd(cmd, cmd.Run()) } func RunShellCmd(call string) int { cmd := exec.Command("sh", "-c", call) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return ManageStatusCmd(cmd, cmd.Run()) } func RunBufferedShellCmd(call string, out *bytes.Buffer) int { cmd := exec.Command("sh", "-c", call) rs1, err := cmd.CombinedOutput() if err != nil { fmt.Println("Error: ", err) } out.Write(rs1) return ManageStatusCmd(cmd, err) } func ManageStatusCmd(cmd *exec.Cmd, err error) int { if err == nil { return 0 } // Figure out the exit code if ws, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok { if ws.Exited() { return ws.ExitStatus() } if ws.Signaled() { return -int(ws.Signal()) } } return -1 } func RunInteractiveCmd(cmd string, withStderr bool, buffers ...*bytes.Buffer) int { // fmt.Printf(" == go before command : %s\n", cmd) icmd := exec.Command("bash", "-c", cmd) icmd.Stdin = os.Stdin icmd.Stdout = os.Stdout if withStderr { if len(buffers) > 0 { icmd.Stderr = buffers[0] } else { icmd.Stderr = os.Stderr } } return ManageStatusCmd(icmd, icmd.Run()) } func PipeCmd(cmd1 *exec.Cmd, cmd2 *exec.Cmd, buffers ...io.Writer) int { status := -1 // fmt.Println("> Pipe Commands") if len(buffers) > 0 { errIndex := 0 pr, pw := io.Pipe() cmd1.Stdout = pw cmd2.Stdin = pr cmd2.Stdout = buffers[errIndex] if len(buffers) > 1 { errIndex = 1 cmd2.Stderr = buffers[errIndex] } cmd1.Start() cmd2.Start() go func() { defer pw.Close() err1 := cmd1.Wait() if err1 != nil { buffers[errIndex].Write([]byte(fmt.Sprintf(" Error pipe in : %v\n", err1))) } }() err2 := cmd2.Wait() if err2 != nil { buffers[errIndex].Write([]byte(fmt.Sprintf(" Error pipe out : %v\n", err2))) status = 1 } else { status = 0 } // fmt.Println("< Pipe Commands") } return status } func UpdateTermSize() error { ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ) if err != nil { return err } TERM_WIDTH = int(ws.Col) return nil } func HandleTermChange(sigwinch chan os.Signal) { // set signal handler signal.Notify(sigwinch, syscall.SIGWINCH) go func() { for { if _, ok := <-sigwinch; !ok { return } _ = UpdateTermSize() } }() } func HandleSigKill(done chan os.Signal) { signal.Notify(done, syscall.SIGINT, syscall.SIGTERM) go func() { <-done // Will block here until user hits ctrl+c RunCmd(exec.Command("tput", "cnorm")) RunCmd(exec.Command("tput", "-x", "clear")) os.Exit(0) }() } func IsRunningOnPod() bool { var bufout bytes.Buffer return PipeCmd(exec.Command("cat", "/proc/1/cgroup"), exec.Command("grep", "kubepods"), &bufout) == 0 } func IsFileExists(path string) bool { exists := false if _, err := os.Open(path); !errors.Is(err, os.ErrNotExist) { exists = true } return exists } func CheckFileSize(remoteSize int64, path string) bool { var size int64 = -1 if IsFileExists(path) { if infos, err := os.Stat(path); err == nil { size = infos.Size() } } return size == remoteSize } func CheckSumFile(remoteChecksum string, path string) bool { var checksum string = "" if IsFileExists(path) { var buf bytes.Buffer RunBufferedCmd(exec.Command("sha256sum", path), &buf) checksum = strings.Split(buf.String(), " ")[0] } return checksum == remoteChecksum } func IsRootUser() bool { done := false if usr, err := user.Current(); err == nil { done = usr.Uid == "0" && usr.HomeDir == "/root" } return done } func IsUser(name string) bool { done := false if usr, err := user.Current(); err == nil { done = usr.Name == name } return done } func IsSystemUser(name string) bool { done := false if usr, err := user.Current(); err == nil { var id int if id, err = strconv.Atoi(usr.Uid); err != nil { done = id < 1000 } } return done }