// Misc returnes miscellaneous host-wide statistics. // Note: the name should be changed near future. func Misc() (*MiscStat, error) { filename := common.HostProc("stat") out, err := ioutil.ReadFile(filename) if err != nil { return nil, err } ret := &MiscStat{} lines := strings.Split(string(out), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) != 2 { continue } v, err := strconv.ParseInt(fields[1], 10, 64) if err != nil { continue } switch fields[0] { case "procs_running": ret.ProcsRunning = int(v) case "procs_blocked": ret.ProcsBlocked = int(v) case "ctxt": ret.Ctxt = int(v) default: continue } } return ret, nil }
// Get num_fds from /proc/(pid)/fd func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) { pid := p.Pid statPath := common.HostProc(strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { return 0, nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) numFDs := int32(len(fnames)) var openfiles []*OpenFilesStat for _, fd := range fnames { fpath := filepath.Join(statPath, fd) filepath, err := os.Readlink(fpath) if err != nil { continue } t, err := strconv.ParseUint(fd, 10, 64) if err != nil { return numFDs, openfiles, err } o := &OpenFilesStat{ Path: filepath, Fd: t, } openfiles = append(openfiles, o) } return numFDs, openfiles, nil }
func LoadAvg() (*LoadAvgStat, error) { filename := common.HostProc("loadavg") line, err := ioutil.ReadFile(filename) if err != nil { return nil, err } values := strings.Fields(string(line)) load1, err := strconv.ParseFloat(values[0], 64) if err != nil { return nil, err } load5, err := strconv.ParseFloat(values[1], 64) if err != nil { return nil, err } load15, err := strconv.ParseFloat(values[2], 64) if err != nil { return nil, err } ret := &LoadAvgStat{ Load1: load1, Load5: load5, Load15: load15, } return ret, nil }
func Times(percpu bool) ([]TimesStat, error) { filename := common.HostProc("stat") var lines = []string{} if percpu { var startIdx uint = 1 for { linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1) line := linen[0] if !strings.HasPrefix(line, "cpu") { break } lines = append(lines, line) startIdx++ } } else { lines, _ = common.ReadLinesOffsetN(filename, 0, 1) } ret := make([]TimesStat, 0, len(lines)) for _, line := range lines { ct, err := parseStatLine(line) if err != nil { continue } ret = append(ret, *ct) } return ret, nil }
// Get status from /proc/(pid)/status func (p *process) fillFromStatus() error { pid := p.Pid statPath := common.HostProc(strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) if err != nil { return err } lines := strings.Split(string(contents), "\n") for _, line := range lines { tabParts := strings.SplitN(line, "\t", 2) if len(tabParts) < 2 { continue } value := tabParts[1] switch strings.TrimRight(tabParts[0], ":") { case "Uid": p.uids = make([]int32, 0, 4) for _, i := range strings.Split(value, "\t") { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.uids = append(p.uids, int32(v)) } } } return nil }
func IOCounters() (map[string]IOCountersStat, error) { filename := common.HostProc("diskstats") lines, err := common.ReadLines(filename) if err != nil { return nil, err } ret := make(map[string]IOCountersStat, 0) empty := IOCountersStat{} for _, line := range lines { fields := strings.Fields(line) name := fields[2] reads, err := strconv.ParseUint((fields[3]), 10, 64) if err != nil { return ret, err } rbytes, err := strconv.ParseUint((fields[5]), 10, 64) if err != nil { return ret, err } rtime, err := strconv.ParseUint((fields[6]), 10, 64) if err != nil { return ret, err } writes, err := strconv.ParseUint((fields[7]), 10, 64) if err != nil { return ret, err } wbytes, err := strconv.ParseUint((fields[9]), 10, 64) if err != nil { return ret, err } wtime, err := strconv.ParseUint((fields[10]), 10, 64) if err != nil { return ret, err } iotime, err := strconv.ParseUint((fields[12]), 10, 64) if err != nil { return ret, err } d := IOCountersStat{ ReadBytes: rbytes * SectorSize, WriteBytes: wbytes * SectorSize, ReadCount: reads, WriteCount: writes, ReadTime: rtime, WriteTime: wtime, IoTime: iotime, } if d == empty { continue } d.Name = name d.SerialNumber = GetDiskSerialNumber(name) ret[name] = d } return ret, nil }
func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, error) { pid := p.Pid statPath := common.HostProc(strconv.Itoa(int(pid)), "stat") contents, err := ioutil.ReadFile(statPath) if err != nil { return "", 0, nil, 0, 0, err } fields := strings.Fields(string(contents)) i := 1 for !strings.HasSuffix(fields[i], ")") { i++ } termmap, err := getTerminalMap() terminal := "" if err == nil { t, err := strconv.ParseUint(fields[i+5], 10, 64) if err != nil { return "", 0, nil, 0, 0, err } terminal = termmap[t] } ppid, err := strconv.ParseInt(fields[i+2], 10, 32) if err != nil { return "", 0, nil, 0, 0, err } utime, err := strconv.ParseFloat(fields[i+12], 64) if err != nil { return "", 0, nil, 0, 0, err } stime, err := strconv.ParseFloat(fields[i+13], 64) if err != nil { return "", 0, nil, 0, 0, err } cpuTimes := &cpu.TimesStat{ CPU: "cpu", User: float64(utime / ClockTicks), System: float64(stime / ClockTicks), } bootTime, _ := host.BootTime() t, err := strconv.ParseUint(fields[i+20], 10, 64) if err != nil { return "", 0, nil, 0, 0, err } ctime := (t / uint64(ClockTicks)) + uint64(bootTime) createTime := int64(ctime * 1000) // p.Nice = mustParseInt32(fields[18]) // use syscall instead of parse Stat file snice, _ := syscall.Getpriority(PrioProcess, int(pid)) nice := int32(snice) // FIXME: is this true? return terminal, int32(ppid), cpuTimes, createTime, nice, nil }
// NewProcess creates a new Process instance, it only stores the pid and // checks that the process exists. Other method on Process can be used // to get more information about the process. An error will be returned // if the process does not exist. func NewProcess(pid int32) (*Process, error) { p := &Process{ Pid: int32(pid), } file, err := os.Open(common.HostProc(strconv.Itoa(int(p.Pid)))) defer file.Close() return p, err }
// Get cwd from /proc/(pid)/cwd func (p *Process) fillFromCwd() (string, error) { pid := p.Pid cwdPath := common.HostProc(strconv.Itoa(int(pid)), "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { return "", err } return string(cwd), nil }
// Get exe from /proc/(pid)/exe func (p *Process) fillFromExe() (string, error) { pid := p.Pid exePath := common.HostProc(strconv.Itoa(int(pid)), "exe") exe, err := os.Readlink(exePath) if err != nil { return "", err } return string(exe), nil }
func TestGetProcInodesAll(t *testing.T) { if os.Getenv("CIRCLECI") == "true" { t.Skip("Skip CI") } root := common.HostProc("") v, err := getProcInodesAll(root) assert.Nil(t, err) assert.NotEmpty(t, v) }
// NetProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Available protocols: // ip,icmp,icmpmsg,tcp,udp,udplite func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { if len(protocols) == 0 { protocols = netProtocols } stats := make([]ProtoCountersStat, 0, len(protocols)) protos := make(map[string]bool, len(protocols)) for _, p := range protocols { protos[p] = true } filename := common.HostProc("net/snmp") lines, err := common.ReadLines(filename) if err != nil { return nil, err } linecount := len(lines) for i := 0; i < linecount; i++ { line := lines[i] r := strings.IndexRune(line, ':') if r == -1 { return nil, errors.New(filename + " is not fomatted correctly, expected ':'.") } proto := strings.ToLower(line[:r]) if !protos[proto] { // skip protocol and data line i++ continue } // Read header line statNames := strings.Split(line[r+2:], " ") // Read data line i++ statValues := strings.Split(lines[i][r+2:], " ") if len(statNames) != len(statValues) { return nil, errors.New(filename + " is not fomatted correctly, expected same number of columns.") } stat := ProtoCountersStat{ Protocol: proto, Stats: make(map[string]int64, len(statNames)), } for j := range statNames { value, err := strconv.ParseInt(statValues[j], 10, 64) if err != nil { return nil, err } stat.Stats[statNames[j]] = value } stats = append(stats, stat) } return stats, nil }
func VirtualMemory() (*VirtualMemoryStat, error) { filename := common.HostProc("meminfo") lines, _ := common.ReadLines(filename) // flag if MemAvailable is in /proc/meminfo (kernel 3.14+) memavail := false ret := &VirtualMemoryStat{} for _, line := range lines { fields := strings.Split(line, ":") if len(fields) != 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) value = strings.Replace(value, " kB", "", -1) t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, err } switch key { case "MemTotal": ret.Total = t * 1024 case "MemFree": ret.Free = t * 1024 case "MemAvailable": memavail = true ret.Available = t * 1024 case "Buffers": ret.Buffers = t * 1024 case "Cached": ret.Cached = t * 1024 case "Active": ret.Active = t * 1024 case "Inactive": ret.Inactive = t * 1024 case "Writeback": ret.Writeback = t * 1024 case "WritebackTmp": ret.WritebackTmp = t * 1024 case "Dirty": ret.Dirty = t * 1024 } } if !memavail { ret.Available = ret.Free + ret.Buffers + ret.Cached } ret.Used = ret.Total - ret.Available ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0 return ret, nil }
// Get memory info from /proc/(pid)/statm func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) { pid := p.Pid memPath := common.HostProc(strconv.Itoa(int(pid)), "statm") contents, err := ioutil.ReadFile(memPath) if err != nil { return nil, nil, err } fields := strings.Split(string(contents), " ") vms, err := strconv.ParseUint(fields[0], 10, 64) if err != nil { return nil, nil, err } rss, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return nil, nil, err } memInfo := &MemoryInfoStat{ RSS: rss * PageSize, VMS: vms * PageSize, } shared, err := strconv.ParseUint(fields[2], 10, 64) if err != nil { return nil, nil, err } text, err := strconv.ParseUint(fields[3], 10, 64) if err != nil { return nil, nil, err } lib, err := strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, nil, err } dirty, err := strconv.ParseUint(fields[5], 10, 64) if err != nil { return nil, nil, err } memInfoEx := &MemoryInfoExStat{ RSS: rss * PageSize, VMS: vms * PageSize, Shared: shared * PageSize, Text: text * PageSize, Lib: lib * PageSize, Dirty: dirty * PageSize, } return memInfo, memInfoEx, nil }
func KernelVersion() (version string, err error) { filename := common.HostProc("sys/kernel/osrelease") if common.PathExists(filename) { contents, err := common.ReadLines(filename) if err != nil { return "", err } if len(contents) > 0 { version = contents[0] } } return version, nil }
// NetFilterCounters returns iptables conntrack statistics // the currently in use conntrack count and the max. // If the file does not exist or is invalid it will return nil. func FilterCounters() ([]FilterStat, error) { countfile := common.HostProc("sys/net/netfilter/nf_conntrackCount") maxfile := common.HostProc("sys/net/netfilter/nf_conntrackMax") count, err := common.ReadInts(countfile) if err != nil { return nil, err } stats := make([]FilterStat, 0, 1) max, err := common.ReadInts(maxfile) if err != nil { return nil, err } payload := FilterStat{ ConnTrackCount: count[0], ConnTrackMax: max[0], } stats = append(stats, payload) return stats, nil }
// Get cmdline from /proc/(pid)/cmdline func (p *Process) fillFromCmdline() (string, error) { pid := p.Pid cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return "", err } ret := strings.FieldsFunc(string(cmdline), func(r rune) bool { if r == '\u0000' { return true } return false }) return strings.Join(ret, " "), nil }
func SwapMemory() (*SwapMemoryStat, error) { sysinfo := &syscall.Sysinfo_t{} if err := syscall.Sysinfo(sysinfo); err != nil { return nil, err } ret := &SwapMemoryStat{ Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit), Free: uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit), } ret.Used = ret.Total - ret.Free //check Infinity if ret.Total != 0 { ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0 } else { ret.UsedPercent = 0 } filename := common.HostProc("vmstat") lines, _ := common.ReadLines(filename) for _, l := range lines { fields := strings.Fields(l) if len(fields) < 2 { continue } switch fields[0] { case "pswpin": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sin = value * 4 * 1024 case "pswpout": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sout = value * 4 * 1024 } } return ret, nil }
func (p *Process) fillSliceFromCmdline() ([]string, error) { pid := p.Pid cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline") cmdline, err := ioutil.ReadFile(cmdPath) if err != nil { return nil, err } if len(cmdline) == 0 { return nil, nil } if cmdline[len(cmdline)-1] == 0 { cmdline = cmdline[:len(cmdline)-1] } parts := bytes.Split(cmdline, []byte{0}) var strParts []string for _, p := range parts { strParts = append(strParts, string(p)) } return strParts, nil }
// getFileSystems returns supported filesystems from /proc/filesystems func getFileSystems() ([]string, error) { filename := common.HostProc("filesystems") lines, err := common.ReadLines(filename) if err != nil { return nil, err } var ret []string for _, line := range lines { if !strings.HasPrefix(line, "nodev") { ret = append(ret, strings.TrimSpace(line)) continue } t := strings.Split(line, "\t") if len(t) != 2 || t[1] != "zfs" { continue } ret = append(ret, strings.TrimSpace(t[1])) } return ret, nil }
// BootTime returns the system boot time expressed in seconds since the epoch. func BootTime() (uint64, error) { filename := common.HostProc("stat") lines, err := common.ReadLines(filename) if err != nil { return 0, err } for _, line := range lines { if strings.HasPrefix(line, "btime") { f := strings.Fields(line) if len(f) != 2 { return 0, fmt.Errorf("wrong btime format") } b, err := strconv.ParseInt(f[1], 10, 64) if err != nil { return 0, err } return uint64(b), nil } } return 0, fmt.Errorf("could not find btime") }
// Get IO status from /proc/(pid)/io func (p *Process) fillFromIO() (*IOCountersStat, error) { pid := p.Pid ioPath := common.HostProc(strconv.Itoa(int(pid)), "io") ioline, err := ioutil.ReadFile(ioPath) if err != nil { return nil, err } lines := strings.Split(string(ioline), "\n") ret := &IOCountersStat{} for _, line := range lines { field := strings.Fields(line) if len(field) < 2 { continue } t, err := strconv.ParseUint(field[1], 10, 64) if err != nil { return nil, err } param := field[0] if strings.HasSuffix(param, ":") { param = param[:len(param)-1] } switch param { case "syscr": ret.ReadCount = t case "syscw": ret.WriteCount = t case "readBytes": ret.ReadBytes = t case "writeBytes": ret.WriteBytes = t } } return ret, nil }
// Pids retunres all pids. // Note: this is a copy of process_linux.Pids() // FIXME: Import process occures import cycle. // move to common made other platform breaking. Need consider. func Pids() ([]int32, error) { var ret []int32 d, err := os.Open(common.HostProc()) if err != nil { return nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) if err != nil { return nil, err } for _, fname := range fnames { pid, err := strconv.ParseInt(fname, 10, 32) if err != nil { // if not numeric name, just skip continue } ret = append(ret, int32(pid)) } return ret, nil }
// NetIOCounters returnes network I/O statistics for every network // interface installed on the system. If pernic argument is false, // return only sum of all information (which name is 'all'). If true, // every network interface installed on the system is returned // separately. func IOCounters(pernic bool) ([]IOCountersStat, error) { filename := common.HostProc("net/dev") return IOCountersByFile(pernic, filename) }
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) { filename := common.HostProc(strconv.Itoa(int(p.Pid)), "net/dev") return net.IOCountersByFile(pernic, filename) }
// Get various status from /proc/(pid)/status func (p *Process) fillFromStatus() error { pid := p.Pid statPath := common.HostProc(strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) if err != nil { return err } lines := strings.Split(string(contents), "\n") p.numCtxSwitches = &NumCtxSwitchesStat{} p.memInfo = &MemoryInfoStat{} for _, line := range lines { tabParts := strings.SplitN(line, "\t", 2) if len(tabParts) < 2 { continue } value := tabParts[1] switch strings.TrimRight(tabParts[0], ":") { case "Name": p.name = strings.Trim(value, " \t") case "State": p.status = value[0:1] case "Uid": p.uids = make([]int32, 0, 4) for _, i := range strings.Split(value, "\t") { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.uids = append(p.uids, int32(v)) } case "Gid": p.gids = make([]int32, 0, 4) for _, i := range strings.Split(value, "\t") { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.gids = append(p.gids, int32(v)) } case "Threads": v, err := strconv.ParseInt(value, 10, 32) if err != nil { return err } p.numThreads = int32(v) case "voluntary_ctxt_switches": v, err := strconv.ParseInt(value, 10, 64) if err != nil { return err } p.numCtxSwitches.Voluntary = v case "nonvoluntary_ctxt_switches": v, err := strconv.ParseInt(value, 10, 64) if err != nil { return err } p.numCtxSwitches.Involuntary = v case "VmRSS": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.RSS = v * 1024 case "VmSize": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.VMS = v * 1024 case "VmSwap": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.Swap = v * 1024 } } return nil }
// MemoryMaps get memory maps from /proc/(pid)/smaps func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) { pid := p.Pid var ret []MemoryMapsStat smapsPath := common.HostProc(strconv.Itoa(int(pid)), "smaps") contents, err := ioutil.ReadFile(smapsPath) if err != nil { return nil, err } lines := strings.Split(string(contents), "\n") // function of parsing a block getBlock := func(first_line []string, block []string) (MemoryMapsStat, error) { m := MemoryMapsStat{} m.Path = first_line[len(first_line)-1] for _, line := range block { if strings.Contains(line, "VmFlags") { continue } field := strings.Split(line, ":") if len(field) < 2 { continue } v := strings.Trim(field[1], " kB") // remove last "kB" t, err := strconv.ParseUint(v, 10, 64) if err != nil { return m, err } switch field[0] { case "Size": m.Size = t case "Rss": m.Rss = t case "Pss": m.Pss = t case "Shared_Clean": m.SharedClean = t case "Shared_Dirty": m.SharedDirty = t case "Private_Clean": m.PrivateClean = t case "Private_Dirty": m.PrivateDirty = t case "Referenced": m.Referenced = t case "Anonymous": m.Anonymous = t case "Swap": m.Swap = t } } return m, nil } blocks := make([]string, 16) for _, line := range lines { field := strings.Split(line, " ") if strings.HasSuffix(field[0], ":") == false { // new block section if len(blocks) > 0 { g, err := getBlock(field, blocks) if err != nil { return &ret, err } ret = append(ret, g) } // starts new block blocks = make([]string, 16) } else { blocks = append(blocks, line) } } return &ret, nil }
func Virtualization() (string, string, error) { var system string var role string filename := common.HostProc("xen") if common.PathExists(filename) { system = "xen" role = "guest" // assume guest if common.PathExists(filename + "/capabilities") { contents, err := common.ReadLines(filename + "/capabilities") if err == nil { if common.StringsHas(contents, "control_d") { role = "host" } } } } filename = common.HostProc("modules") if common.PathExists(filename) { contents, err := common.ReadLines(filename) if err == nil { if common.StringsContains(contents, "kvm") { system = "kvm" role = "host" } else if common.StringsContains(contents, "vboxdrv") { system = "vbox" role = "host" } else if common.StringsContains(contents, "vboxguest") { system = "vbox" role = "guest" } } } filename = common.HostProc("cpuinfo") if common.PathExists(filename) { contents, err := common.ReadLines(filename) if err == nil { if common.StringsHas(contents, "QEMU Virtual CPU") || common.StringsHas(contents, "Common KVM processor") || common.StringsHas(contents, "Common 32-bit KVM processor") { system = "kvm" role = "guest" } } } filename = common.HostProc() if common.PathExists(filename + "/bc/0") { system = "openvz" role = "host" } else if common.PathExists(filename + "/vz") { system = "openvz" role = "guest" } // not use dmidecode because it requires root if common.PathExists(filename + "/self/status") { contents, err := common.ReadLines(filename + "/self/status") if err == nil { if common.StringsHas(contents, "s_context:") || common.StringsHas(contents, "VxID:") { system = "linux-vserver" } // TODO: guest or host } } if common.PathExists(filename + "/self/cgroup") { contents, err := common.ReadLines(filename + "/self/cgroup") if err == nil { if common.StringsHas(contents, "lxc") || common.StringsHas(contents, "docker") { system = "lxc" role = "guest" } else if common.PathExists("/usr/bin/lxc-version") { // TODO: which system = "lxc" role = "host" } } } return system, role, nil }
// CPUInfo on linux will return 1 item per physical thread. // // CPUs have three levels of counting: sockets, cores, threads. // Cores with HyperThreading count as having 2 threads per core. // Sockets often come with many physical CPU cores. // For example a single socket board with two cores each with HT will // return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1. func Info() ([]InfoStat, error) { filename := common.HostProc("cpuinfo") lines, _ := common.ReadLines(filename) var ret []InfoStat c := InfoStat{CPU: -1, Cores: 1} for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) switch key { case "processor": if c.CPU >= 0 { err := finishCPUInfo(&c) if err != nil { return ret, err } ret = append(ret, c) } c = InfoStat{Cores: 1} t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.CPU = int32(t) case "vendorId": c.VendorID = value case "cpu family": c.Family = value case "model": c.Model = value case "model name": c.ModelName = value case "stepping": t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.Stepping = int32(t) case "cpu MHz": t, err := strconv.ParseFloat(value, 64) if err != nil { return ret, err } c.Mhz = t case "cache size": t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64) if err != nil { return ret, err } c.CacheSize = int32(t) case "physical id": c.PhysicalID = value case "core id": c.CoreID = value case "flags", "Features": c.Flags = strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' }) } } if c.CPU >= 0 { err := finishCPUInfo(&c) if err != nil { return ret, err } ret = append(ret, c) } return ret, nil }
// Return a list of network connections opened by a process. func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { tmap, ok := netConnectionKindMap[kind] if !ok { return nil, fmt.Errorf("invalid kind, %s", kind) } root := common.HostProc() var err error var inodes map[string][]inodeMap if pid == 0 { inodes, err = getProcInodesAll(root) } else { inodes, err = getProcInodes(root, pid) if len(inodes) == 0 { // no connection for the pid return []ConnectionStat{}, nil } } if err != nil { return nil, fmt.Errorf("cound not get pid(s), %d", pid) } dupCheckMap := make(map[string]bool) var ret []ConnectionStat for _, t := range tmap { var path string var ls []connTmp path = fmt.Sprintf("%s/net/%s", root, t.filename) switch t.family { case syscall.AF_INET: fallthrough case syscall.AF_INET6: ls, err = processInet(path, t, inodes, pid) case syscall.AF_UNIX: ls, err = processUnix(path, t, inodes, pid) } if err != nil { return nil, err } for _, c := range ls { conn := ConnectionStat{ Fd: c.fd, Family: c.family, Type: c.sockType, Laddr: c.laddr, Raddr: c.raddr, Status: c.status, Pid: c.pid, } if c.pid == 0 { conn.Pid = c.boundPid } else { conn.Pid = c.pid } // check duplicate using JSON format json := conn.String() _, exists := dupCheckMap[json] if !exists { ret = append(ret, conn) dupCheckMap[json] = true } } } return ret, nil }