You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.1 KiB
Go
349 lines
9.1 KiB
Go
2 years ago
|
// +build linux darwin
|
||
|
|
||
|
package staros
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
//FindProcessByName 通过进程名来查询应用信息
|
||
|
func FindProcessByName(name string) (datas []Process, err error) {
|
||
|
return FindProcess(func(in Process) bool {
|
||
|
if name == in.Name {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// FindProcess 通过进程信息来查询应用信息
|
||
|
func FindProcess(compare func(Process) bool) (datas []Process, err error) {
|
||
|
var name, main string
|
||
|
var mainb []byte
|
||
|
var netErr error
|
||
|
var netInfo []NetConn
|
||
|
paths, err := ioutil.ReadDir("/proc")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
netInfo, netErr = NetConnections(false, "")
|
||
|
appendNetInfo := func(p *Process) {
|
||
|
if netErr != nil {
|
||
|
p.netErr = netErr
|
||
|
return
|
||
|
}
|
||
|
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
|
||
|
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
|
||
|
p.netErr = err
|
||
|
return
|
||
|
}
|
||
|
for _, fd := range fds {
|
||
|
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
|
||
|
if err != nil {
|
||
|
p.netErr = err
|
||
|
return
|
||
|
}
|
||
|
start := strings.Index(socket, "[")
|
||
|
if start < 0 {
|
||
|
continue
|
||
|
}
|
||
|
sid := socket[start+1 : len(socket)-1]
|
||
|
for _, v := range netInfo {
|
||
|
if v.Inode == sid {
|
||
|
v.Pid = p.Pid
|
||
|
v.Process = p
|
||
|
p.netConn = append(p.netConn, v)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for _, v := range paths {
|
||
|
if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") {
|
||
|
name, err = readAsString("/proc/" + v.Name() + "/comm")
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
var tmp Process
|
||
|
tmp.LocalPath, err = os.Readlink("/proc/" + v.Name() + "/exe")
|
||
|
tmp.Path = tmp.LocalPath
|
||
|
tmp.LocalPath = filepath.Dir(tmp.LocalPath)
|
||
|
tmp.ExecPath, err = os.Readlink("/proc/" + v.Name() + "/cwd")
|
||
|
tmp.Name = strings.TrimSpace(name)
|
||
|
main, err = readAsString("/proc/" + v.Name() + "/status")
|
||
|
if err != nil {
|
||
|
tmp.Err = err
|
||
|
if compare(tmp) {
|
||
|
appendNetInfo(&tmp)
|
||
|
datas = append(datas, tmp)
|
||
|
continue
|
||
|
}
|
||
|
} else {
|
||
|
data := splitBy(main, ":")
|
||
|
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
||
|
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
||
|
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
||
|
uids := splitBySpace(data["Uid"])
|
||
|
gids := splitBySpace(data["Gid"])
|
||
|
tmp.RUID, _ = strconv.Atoi(uids[0])
|
||
|
tmp.EUID, _ = strconv.Atoi(uids[1])
|
||
|
tmp.RGID, _ = strconv.Atoi(gids[0])
|
||
|
tmp.EGID, _ = strconv.Atoi(gids[1])
|
||
|
tmp.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
|
||
|
tmp.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
|
||
|
tmp.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
|
||
|
tmp.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
|
||
|
tmp.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
|
||
|
tmp.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
|
||
|
tmp.VmLck *= 1024
|
||
|
tmp.VmData *= 1024
|
||
|
tmp.VmPeak *= 1024
|
||
|
tmp.VmSize *= 1024
|
||
|
tmp.VmHWM *= 1024
|
||
|
tmp.VmRSS *= 1024
|
||
|
}
|
||
|
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline")
|
||
|
if err != nil {
|
||
|
tmp.Err = err
|
||
|
if compare(tmp) {
|
||
|
appendNetInfo(&tmp)
|
||
|
datas = append(datas, tmp)
|
||
|
continue
|
||
|
}
|
||
|
} else {
|
||
|
args := bytes.Split(mainb, []byte{0})
|
||
|
for _, v := range args {
|
||
|
tmp.Args = append(tmp.Args, string(v))
|
||
|
}
|
||
|
}
|
||
|
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/environ")
|
||
|
if err != nil {
|
||
|
tmp.Err = err
|
||
|
if compare(tmp) {
|
||
|
appendNetInfo(&tmp)
|
||
|
datas = append(datas, tmp)
|
||
|
continue
|
||
|
}
|
||
|
} else {
|
||
|
args := bytes.Split(mainb, []byte{0})
|
||
|
for _, v := range args {
|
||
|
tmp.Env = append(tmp.Env, string(v))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
main, err = readAsString("/proc/" + v.Name() + "/stat")
|
||
|
if err != nil {
|
||
|
tmp.Err = err
|
||
|
if compare(tmp) {
|
||
|
appendNetInfo(&tmp)
|
||
|
datas = append(datas, tmp)
|
||
|
continue
|
||
|
}
|
||
|
} else {
|
||
|
times := splitBySpace(main)
|
||
|
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
||
|
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
||
|
}
|
||
|
if compare(tmp) {
|
||
|
appendNetInfo(&tmp)
|
||
|
datas = append(datas, tmp)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// FindProcessByPid 通过Pid来查询应用信息
|
||
|
func FindProcessByPid(pid int64) (datas Process, err error) {
|
||
|
var name, main string
|
||
|
var mainb []byte
|
||
|
if !Exists("/proc/" + fmt.Sprint(pid) + "/comm") {
|
||
|
err = errors.New("Not Found")
|
||
|
return
|
||
|
}
|
||
|
netInfo, netErr := NetConnections(false, "")
|
||
|
appendNetInfo := func(p *Process) {
|
||
|
if netErr != nil {
|
||
|
p.netErr = netErr
|
||
|
return
|
||
|
}
|
||
|
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
|
||
|
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
|
||
|
p.netErr = err
|
||
|
return
|
||
|
}
|
||
|
for _, fd := range fds {
|
||
|
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
|
||
|
if err != nil {
|
||
|
p.netErr = err
|
||
|
return
|
||
|
}
|
||
|
start := strings.Index(socket, "[")
|
||
|
if start < 0 {
|
||
|
continue
|
||
|
}
|
||
|
sid := socket[start+1 : len(socket)-1]
|
||
|
for _, v := range netInfo {
|
||
|
if v.Inode == sid {
|
||
|
v.Pid = p.Pid
|
||
|
v.Process = p
|
||
|
p.netConn = append(p.netConn, v)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/status")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
data := splitBy(main, ":")
|
||
|
datas.Name = strings.TrimSpace(name)
|
||
|
datas.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
|
||
|
datas.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
|
||
|
datas.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
|
||
|
uids := splitBySpace(data["Uid"])
|
||
|
gids := splitBySpace(data["Gid"])
|
||
|
datas.RUID, _ = strconv.Atoi(uids[0])
|
||
|
datas.EUID, _ = strconv.Atoi(uids[1])
|
||
|
datas.RGID, _ = strconv.Atoi(gids[0])
|
||
|
datas.EGID, _ = strconv.Atoi(gids[1])
|
||
|
datas.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
|
||
|
datas.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
|
||
|
datas.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
|
||
|
datas.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
|
||
|
datas.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
|
||
|
datas.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
|
||
|
datas.VmLck *= 1024
|
||
|
datas.VmData *= 1024
|
||
|
datas.VmPeak *= 1024
|
||
|
datas.VmSize *= 1024
|
||
|
datas.VmHWM *= 1024
|
||
|
datas.VmRSS *= 1024
|
||
|
appendNetInfo(&datas)
|
||
|
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline")
|
||
|
if err != nil {
|
||
|
datas.Err = err
|
||
|
err = nil
|
||
|
} else {
|
||
|
args := bytes.Split(mainb, []byte{0})
|
||
|
for _, v := range args {
|
||
|
datas.Args = append(datas.Args, string(v))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/environ")
|
||
|
if err != nil {
|
||
|
datas.Err = err
|
||
|
err = nil
|
||
|
} else {
|
||
|
args := bytes.Split(mainb, []byte{0})
|
||
|
for _, v := range args {
|
||
|
datas.Env = append(datas.Env, string(v))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe")
|
||
|
datas.Path = datas.LocalPath
|
||
|
datas.LocalPath = filepath.Dir(datas.LocalPath)
|
||
|
datas.ExecPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/cwd")
|
||
|
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/stat")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
times := splitBySpace(main)
|
||
|
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
|
||
|
datas.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func Daemon(path string, args ...string) (int, error) {
|
||
|
cmd := exec.Command(path, args...)
|
||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||
|
Setsid: true,
|
||
|
}
|
||
|
if err := cmd.Start(); err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
pid := cmd.Process.Pid
|
||
|
err := cmd.Process.Release()
|
||
|
return pid, err
|
||
|
}
|
||
|
|
||
|
func DaemonWithUser(uid, gid uint32, groups []uint32, path string, args ...string) (int, error) {
|
||
|
cmd := exec.Command(path, args...)
|
||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||
|
Credential: &syscall.Credential{
|
||
|
Uid: uid,
|
||
|
Gid: gid,
|
||
|
Groups: groups,
|
||
|
},
|
||
|
Setsid: true,
|
||
|
}
|
||
|
if err := cmd.Start(); err != nil {
|
||
|
return -1, err
|
||
|
}
|
||
|
pid := cmd.Process.Pid
|
||
|
err := cmd.Process.Release()
|
||
|
return pid, err
|
||
|
}
|
||
|
|
||
|
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
|
||
|
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
|
||
|
Credential: &syscall.Credential{
|
||
|
Uid: uid,
|
||
|
Gid: gid,
|
||
|
Groups: groups,
|
||
|
},
|
||
|
Setsid: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (starcli *StarCmd) Release() error {
|
||
|
if starcli.CMD.SysProcAttr == nil {
|
||
|
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
|
||
|
Setsid: true,
|
||
|
}
|
||
|
} else {
|
||
|
if !starcli.CMD.SysProcAttr.Setsid {
|
||
|
starcli.CMD.SysProcAttr.Setsid = true
|
||
|
}
|
||
|
}
|
||
|
if !starcli.IsRunning() {
|
||
|
if err := starcli.CMD.Start(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
time.Sleep(time.Millisecond * 10)
|
||
|
return starcli.CMD.Process.Release()
|
||
|
}
|
||
|
|
||
|
func (starcli *StarCmd) SetKeepCaps() error {
|
||
|
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
|
||
|
if 0 != err {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func SetKeepCaps() error {
|
||
|
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
|
||
|
if 0 != err {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|