package collect import ( "bytes" "context" "errors" "os/exec" "time" ) // run executes a command with a timeout and returns stdout even on non-zero // exit (smartctl encodes state in its exit code and still prints JSON). func run(timeout time.Duration, name string, args ...string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() cmd := exec.CommandContext(ctx, name, args...) var out, errb bytes.Buffer cmd.Stdout, cmd.Stderr = &out, &errb err := cmd.Run() if err != nil { var ee *exec.ExitError if errors.As(err, &ee) { return out.Bytes(), ee } return out.Bytes(), errors.New(name + ": " + err.Error() + " " + errb.String()) } return out.Bytes(), nil }