//go:build !windows
// +build !windows

package utils

import (
	"bytes"
	"context"
	log "github.com/sirupsen/logrus"
	"os/exec"
	"syscall"
	"time"
)

func ScriptCMD(path string, param ...string) (string, error) {
	// TODO: 执行command, 没有超时的限制吗？需要升级go版本, 升级到1.6也不行哈, 换一种方式context @jay
	// cmd := exec.Command(path, param...)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer cancel()
	cmd := exec.CommandContext(ctx, path, param...)
	var out bytes.Buffer
	cmd.Stdout = &out
	// cmd.Timeout = time.Second * 10
	err := cmd.Run()
	result := out.String()

	log.Infof("cmd content : [%s] cmd error :[%v]", result, err)
	if err != nil {
		log.Errorf("path %s param %v error %s", path, param, err)
		return result, err
	}
	//result = out.String()
	return result, err
}

func ScriptCMDNO(path string, param ...string) (string, error) {
	return ScriptCMD(path, param...)
	//cmd := exec.Command(path, param...)
	//var out bytes.Buffer
	//cmd.Stdout = &out
	//err := cmd.Run()
	//if err != nil {
	//	log.Error(err)
	//	return "", err
	//}
	//result := out.String()
	//return result, err
}

// 提权cmd
func AuthoritativeCMD(uid32 uint32, waitTime time.Duration, osEnv []string, command string, args ...string) (string, error) {
	log.Infof("AuthoritativeCMD [command = %s][args = %v][waitTime=%v][uid=%d]", command, args, waitTime, uid32)
	ctx, cancel := context.WithTimeout(context.Background(), waitTime)
	defer cancel()
	cmd := exec.CommandContext(ctx, command, args...)
	cmd.Env = osEnv
	cmd.SysProcAttr = &syscall.SysProcAttr{
		// 设置子进程为相同pgid，防止子进程再次fork的子进程脱管
		//Setpgid: true,
		// 提权执行
		Credential: &syscall.Credential{
			Uid: uid32,
		},
	}
	go func() {
		defer func() {
			if err := recover(); err != nil {
				log.Errorf("AuthoritativeCMD panic:%v", err)
			}
		}()
		select {
		case <-ctx.Done():
			err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
			if err == nil {
				log.Warnf("Timeout kill success : [%d], err:[%v]", cmd.Process.Pid, err)
			}
		}
	}()
	content, err := cmd.CombinedOutput()
	log.Infof("cmd content : [%s] cmd error :[%v]", content, err)
	if err != nil {
		return string(content), err
	}
	return string(content), err
}

func BackgroundCMD(uid32 uint32, waitTime time.Duration, osEnv []string, command string, args ...string) (string, error) {
	return "ok", nil
}
