diff --git a/network.go b/network.go new file mode 100644 index 0000000..815f4f7 --- /dev/null +++ b/network.go @@ -0,0 +1,85 @@ +// +build !windows + +package staros + +import ( + "errors" + "io/ioutil" + "strconv" + "strings" + "time" +) + +func NetUsage() ([]NetAdapter, error) { + data, err := ioutil.ReadFile("/proc/net/dev") + if err != nil { + return []NetAdapter{}, err + } + sps := strings.Split(strings.TrimSpace(string(data)), "\n") + if len(sps) < 3 { + return []NetAdapter{}, errors.New("No Adaptor") + } + var res []NetAdapter + netLists := sps[2:] + for _, v := range netLists { + v = strings.ReplaceAll(v, " ", " ") + for strings.Contains(v, " ") { + v = strings.ReplaceAll(v, " ", " ") + } + v = strings.TrimSpace(v) + card := strings.Split(v, " ") + name := strings.ReplaceAll(card[0], ":", "") + recvBytes, _ := strconv.Atoi(card[1]) + sendBytes, _ := strconv.Atoi(card[9]) + res = append(res, NetAdapter{name, uint64(recvBytes), uint64(sendBytes)}) + } + return res, nil +} + +func NetUsageByname(name string) (NetAdapter, error) { + ada, err := NetUsage() + if err != nil { + return NetAdapter{}, err + } + for _, v := range ada { + if v.Name == name { + return v, nil + } + } + return NetAdapter{}, errors.New("Not Found") +} + +func NetSpeeds(duration time.Duration) ([]NetSpeed, error) { + list1, err := NetUsage() + if err != nil { + return []NetSpeed{}, err + } + time.Sleep(duration) + list2, err := NetUsage() + if err != nil { + return []NetSpeed{}, err + } + if len(list1) > len(list2) { + return []NetSpeed{}, errors.New("NetWork Adaptor Num Not ok") + } + var res []NetSpeed + for k, v := range list1 { + recv := float64(list2[k].RecvBytes-v.RecvBytes) / duration.Seconds() + send := float64(list2[k].SendBytes-v.SendBytes) / duration.Seconds() + res = append(res, NetSpeed{v.Name, recv, send}) + } + return res, nil +} + +func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) { + ada, err := NetSpeeds(duration) + if err != nil { + return NetSpeed{}, err + } + for _, v := range ada { + if v.Name == name { + return v, nil + } + } + return NetSpeed{}, errors.New("Not Found") +} diff --git a/network_windows.go b/network_windows.go new file mode 100644 index 0000000..12578a3 --- /dev/null +++ b/network_windows.go @@ -0,0 +1,26 @@ +// +build windows + +package staros + +import ( + "time" +) + +func NetUsage() ([]NetAdapter, error) { + var res []NetAdapter + return res, nil +} + +func NetUsageByname(name string) (NetAdapter, error) { + return NetAdapter{}, nil +} + +func NetSpeeds(duration time.Duration) ([]NetSpeed, error) { + var res []NetSpeed + return res, nil +} + +func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) { + + return NetSpeed{}, nil +} diff --git a/os_linux.go b/os_linux.go index d0027ad..028f1ee 100644 --- a/os_linux.go +++ b/os_linux.go @@ -1,4 +1,4 @@ -// +build linux darwin +// +build !windows package staros @@ -105,8 +105,6 @@ func CpuUsage(sleep time.Duration) float64 { //fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks) } - - func DiskUsage(path string) (disk DiskStatus) { fs := syscall.Statfs_t{} err := syscall.Statfs(path, &fs) diff --git a/os_windows.go b/os_windows.go index 55d0d0e..69c90fc 100644 --- a/os_windows.go +++ b/os_windows.go @@ -71,3 +71,7 @@ func DiskUsage(path string) (disk DiskStatus) { disk.Available = uint64(lpFreeBytesAvailable) return } + +func CpuUsage(sleep time.Duration) float64 { + return 0 +} diff --git a/process.go b/process.go new file mode 100644 index 0000000..31427a5 --- /dev/null +++ b/process.go @@ -0,0 +1,305 @@ +package staros + +import ( + "bytes" + "context" + "errors" + "io" + "os" + "os/exec" + "syscall" + "time" +) + +//StarCmd Is Here + +type StarCmd struct { + CMD *exec.Cmd + outfile io.ReadCloser + infile io.WriteCloser + errfile io.ReadCloser + running bool + runningChan chan int + //Store AlL of the Standed Outputs + stdout []byte + //Store All of the Standed Errors + errout []byte + runerr error + exitcode int + customCtx context.Context + stdoutBuf *bytes.Buffer + stderrBuf *bytes.Buffer + stdoutpoint int + stderrpoint int + prewrite []string + prewritetime time.Duration + stopctxfunc context.CancelFunc + stopctx context.Context +} + +func Command(command string, args ...string) (*StarCmd, error) { + var err error + shell := new(StarCmd) + shell.running = false + shell.prewritetime = time.Millisecond * 200 + shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0)) + shell.stderrBuf = bytes.NewBuffer(make([]byte, 0)) + shell.runningChan = make(chan int, 3) + cmd := exec.Command(command, args...) + shell.CMD = cmd + shell.infile, err = shell.CMD.StdinPipe() + if err != nil { + return shell, err + } + shell.errfile, err = shell.CMD.StderrPipe() + if err != nil { + return shell, err + } + shell.outfile, err = shell.CMD.StdoutPipe() + if err != nil { + return shell, err + } + shell.runerr = nil + shell.exitcode = -999 + return shell, nil +} +func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) { + var err error + shell := new(StarCmd) + shell.running = false + shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0)) + shell.stderrBuf = bytes.NewBuffer(make([]byte, 0)) + shell.runningChan = make(chan int, 3) + shell.prewritetime = time.Millisecond * 200 + shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background()) + cmd := exec.CommandContext(ctx, command, args...) + shell.CMD = cmd + shell.infile, err = shell.CMD.StdinPipe() + if err != nil { + return shell, err + } + shell.errfile, err = shell.CMD.StderrPipe() + if err != nil { + return shell, err + } + shell.outfile, err = shell.CMD.StdoutPipe() + if err != nil { + return shell, err + } + shell.runerr = nil + shell.exitcode = -999 + return shell, nil +} + +func (starcli *StarCmd) queryStdout(ctx context.Context) { + for starcli.running && starcli.CMD != nil { + select { + case <-ctx.Done(): + return + default: + break + } + out := make([]byte, 65535) + n, err := starcli.outfile.Read(out) + if n != 0 { + starcli.stdoutBuf.Write(out[:n]) + for _, v := range out[:n] { + starcli.stdout = append(starcli.stdout, v) + } + } + if err != nil { + if err == io.EOF { + break + } else { + starcli.runerr = err + return + } + } + } +} + +func (starcli *StarCmd) queryStderr(ctx context.Context) { + for starcli.running && starcli.CMD != nil { + select { + case <-ctx.Done(): + return + default: + break + } + out := make([]byte, 65535) + n, err := starcli.errfile.Read(out) + if n != 0 { + starcli.stderrBuf.Write(out[:n]) + for _, v := range out[:n] { + starcli.errout = append(starcli.errout, v) + } + } + if err != nil { + if err == io.EOF { + break + } else { + starcli.runerr = err + return + } + } + } + return +} +func (starcli *StarCmd) NowLineOutput() (string, error) { + buf, _ := starcli.stdoutBuf.ReadBytes('\n') + buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n')) + if len(buferr) != 0 { + return string(buf), errors.New(string(buferr)) + } + return string(buf), nil +} + +func (starcli *StarCmd) NowLineStdOut() string { + buf, _ := starcli.stdoutBuf.ReadBytes('\n') + return string(buf) +} + +func (starcli *StarCmd) NowLineStdErr() error { + buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n')) + if len(buferr) != 0 { + return errors.New(string(buferr)) + } + return nil +} + +func (starcli *StarCmd) NowAllOutput() (string, error) { + var outstr string + buf := make([]byte, starcli.stdoutBuf.Len()) + n, _ := starcli.stdoutBuf.Read(buf) + if n != 0 { + outstr = string(buf[:n]) + } + if starcli.runerr != nil { + return outstr, starcli.runerr + } + buf = make([]byte, starcli.stderrBuf.Len()) + n, _ = starcli.stderrBuf.Read(buf) + if n != 0 { + return outstr, errors.New(string(buf[:n])) + } + return outstr, nil +} + +func (starcli *StarCmd) NowStdOut() string { + var outstr string + buf := make([]byte, starcli.stdoutBuf.Len()) + n, _ := starcli.stdoutBuf.Read(buf) + if n != 0 { + outstr = string(buf[:n]) + } + return outstr +} + +func (starcli *StarCmd) NowStdErr() error { + + buf := make([]byte, starcli.stderrBuf.Len()) + n, _ := starcli.stderrBuf.Read(buf) + if n != 0 { + return errors.New(string(buf[:n])) + } + return nil +} + +func (starcli *StarCmd) AllOutPut() (string, error) { + err := starcli.runerr + if err == nil && len(starcli.errout) != 0 { + err = errors.New(string(starcli.errout)) + } + return string(starcli.stdout), err +} + +func (starcli *StarCmd) AllStdOut() string { + return string(starcli.stdout) +} + +func (starcli *StarCmd) AllStdErr() error { + err := starcli.runerr + if err == nil && len(starcli.errout) != 0 { + err = errors.New(string(starcli.errout)) + } + return err +} + +func (starcli *StarCmd) Start() error { + if err := starcli.CMD.Start(); err != nil { + return err + } + starcli.running = true + go func() { + err := starcli.CMD.Wait() + if err != nil { + starcli.runerr = err + } + starcli.stopctxfunc() + starcli.running = false + starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + starcli.runningChan <- 1 + }() + go starcli.queryStdout(starcli.stopctx) + go starcli.queryStderr(starcli.stopctx) + go func(ctx context.Context) { + if len(starcli.prewrite) != 0 { + for _, v := range starcli.prewrite { + select { + case <-ctx.Done(): + return + default: + break + } + starcli.WriteCmd(v) + time.Sleep(starcli.prewritetime) + } + } + }(starcli.stopctx) + return nil +} + +func (starcli *StarCmd) IsRunning() bool { + return starcli.running +} + +func (starcli *StarCmd) Stoped() <-chan int { + return starcli.runningChan +} + +func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) { + starcli.infile.Write([]byte(cmd + "\n")) + time.Sleep(time.Millisecond * time.Duration(wait)) + return starcli.NowAllOutput() +} + +func (starcli *StarCmd) WriteCmd(cmdstr string) { + starcli.infile.Write([]byte(cmdstr + "\n")) +} + +func (starcli *StarCmd) PreWrite(cmd ...string) { + for _, v := range cmd { + starcli.prewrite = append(starcli.prewrite, v) + } +} + +func (starcli *StarCmd) PreWriteInterval(dt time.Duration) { + starcli.prewritetime = dt +} + +func (starcli *StarCmd) ExitCode() int { + return starcli.exitcode +} + +func (starcli *StarCmd) Kill() { + starcli.CMD.Process.Kill() + starcli.running = false +} + +func (starcli *StarCmd) GetPid() int { + return starcli.CMD.Process.Pid +} + +func (starcli *StarCmd) Signal(sig os.Signal) error { + return starcli.CMD.Process.Signal(sig) +} diff --git a/process_linux.go b/process_linux.go index 443e027..7f89641 100644 --- a/process_linux.go +++ b/process_linux.go @@ -60,6 +60,7 @@ func FindProcessByName(pname string) (datas []Process, err error) { if err != nil { return } + tmp.Path = tmp.LocalPath tmp.LocalPath = filepath.Dir(tmp.LocalPath) tmp.ExecPath, err = os.Readlink("/proc/" + v.Name() + "/cwd") if err != nil { @@ -118,6 +119,7 @@ func FindProcessByPid(pid int64) (datas Process, err error) { if err != nil { return } + datas.Path = datas.LocalPath datas.LocalPath = filepath.Dir(datas.LocalPath) datas.ExecPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/cwd") if err != nil { @@ -145,3 +147,32 @@ func Daemon(path string, args ...string) (int, error) { err := cmd.Process.Release() return pid, err } + +func (starcli *StarCmd) SetRunUser(uid, gid uint32) { + starcli.CMD.SysProcAttr = &syscall.SysProcAttr{ + Credential: &syscall.Credential{ + Uid: uid, + Gid: gid, + }, + Setsid: true, + } +} + +func (starcli *StarCmd) Release() error { + if err := starcli.CMD.Start(); err != nil { + return err + } + starcli.cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, + } + starcli.cmd.Process.Release() + return nil +} + +func (starcli *StarCmd) SetKeepCaps() error { + _, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0) + if 0 != err { + return err + } + return nil +} diff --git a/process_test.go b/process_test.go index 6ff35c0..047e722 100644 --- a/process_test.go +++ b/process_test.go @@ -1,10 +1,27 @@ package staros import ( + "context" "fmt" "testing" + "time" ) func Test_Process(t *testing.T) { fmt.Println(FindProcessByPid(16652)) } + +func Test_StarCmd(t *testing.T) { + ctx, _ := context.WithTimeout(context.Background(), time.Second*5) + cmd, _ := CommandContext(ctx, "cmd.exe", "/c", "ping -t 127.0.0.1") + cmd.Start() + for cmd.IsRunning() { + fmt.Print(cmd.NowLineOutput()) + time.Sleep(time.Millisecond * 50) + } + fmt.Println(cmd.NowAllOutput()) + fmt.Print("all is ") + fmt.Println(cmd.AllOutPut()) + fmt.Println(cmd.ExitCode()) + +} diff --git a/process_win.go b/process_win.go index 22a5fa1..713741c 100644 --- a/process_win.go +++ b/process_win.go @@ -58,3 +58,7 @@ func Daemon(path string, args ...string) (int, error) { cmd.Process.Release() return pid, nil } + +func (starcli *StarCmd) SetRunUser(uid, gid uint32) { + +} diff --git a/typed.go b/typed.go index 87ac891..950f497 100644 --- a/typed.go +++ b/typed.go @@ -4,6 +4,26 @@ import ( "time" ) +const ( + KB = 1024 + MB = KB << 10 + GB = MB << 10 + TB = GB << 10 + PB = TB << 10 +) + +type NetAdapter struct { + Name string + RecvBytes uint64 + SendBytes uint64 +} + +type NetSpeed struct { + Name string + RecvBytes float64 + SendBytes float64 +} + // Process 定义一个进程的信息 type Process struct { PPid int64 @@ -11,6 +31,7 @@ type Process struct { Name string ExecPath string LocalPath string + Path string Args []string RUID int EUID int