Repository: prometheus/procfs
Pull request #322 (2020-08-25 07:01:03)

Add GIDs to ProcStatus struct
@discordianfish @pgier Just added a trivial parse of process user GIDs from status like UIDs and same tests. Please check it out.


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3ea6b88..4224ea8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -34,7 +34,7 @@ jobs:
     steps:
     - checkout
     - run: sudo pip install codespell
-    - run: codespell --skip=".git,./vendor,ttar,fixtures.ttar,./fixtures,go.mod,go.sum" -L uint,packages\',ded,alo,als,te,sie
+    - run: codespell --skip=".git,./vendor,ttar,fixtures.ttar,./fixtures,go.mod,go.sum" -L uint,packages\',ded,alo,als,te,sie,hart
 
 workflows:
   version: 2
diff --git a/cpuinfo.go b/cpuinfo.go
index 935157e..b9fb589 100644
--- a/cpuinfo.go
+++ b/cpuinfo.go
@@ -407,6 +407,46 @@ func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) {
 	return cpuinfo, nil
 }
 
+func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
+	scanner := bufio.NewScanner(bytes.NewReader(info))
+
+	firstLine := firstNonEmptyLine(scanner)
+	if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
+		return nil, errors.New("invalid cpuinfo file: " + firstLine)
+	}
+	field := strings.SplitN(firstLine, ": ", 2)
+	v, err := strconv.ParseUint(field[1], 0, 32)
+	if err != nil {
+		return nil, err
+	}
+	firstcpu := CPUInfo{Processor: uint(v)}
+	cpuinfo := []CPUInfo{firstcpu}
+	i := 0
+
+	for scanner.Scan() {
+		line := scanner.Text()
+		if !strings.Contains(line, ":") {
+			continue
+		}
+		field := strings.SplitN(line, ": ", 2)
+		switch strings.TrimSpace(field[0]) {
+		case "processor":
+			v, err := strconv.ParseUint(field[1], 0, 32)
+			if err != nil {
+				return nil, err
+			}
+			i = int(v)
+			cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor
+			cpuinfo[i].Processor = uint(v)
+		case "hart":
+			cpuinfo[i].CoreID = field[1]
+		case "isa":
+			cpuinfo[i].ModelName = field[1]
+		}
+	}
+	return cpuinfo, nil
+}
+
 func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode
 	return nil, errors.New("not implemented")
 }
diff --git a/cpuinfo_others.go b/cpuinfo_others.go
index db3809d..95b5b4e 100644
--- a/cpuinfo_others.go
+++ b/cpuinfo_others.go
@@ -12,7 +12,7 @@
 // limitations under the License.
 
 // +build linux
-// +build !386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!s390x
+// +build !386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x
 
 package procfs
 
diff --git a/fixtures.ttar b/fixtures.ttar
index bcfadf4..12494d7 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -467,7 +467,7 @@ Pid:	26231
 PPid:	1
 TracerPid:	0
 Uid:	1000	1000	1000	0
-Gid:	0	0	0	0
+Gid:	1001	1001	1001	0
 FDSize:	128
 Groups:
 NStgid:	1
diff --git a/proc_status.go b/proc_status.go
index c58346d..6edd833 100644
--- a/proc_status.go
+++ b/proc_status.go
@@ -72,8 +72,10 @@ type ProcStatus struct {
 	// Number of involuntary context switches.
 	NonVoluntaryCtxtSwitches uint64
 
-	// UIDs of the process (Real, effective, saved set, and filesystem UIDs (GIDs))
+	// UIDs of the process (Real, effective, saved set, and filesystem UIDs)
 	UIDs [4]string
+	// GIDs of the process (Real, effective, saved set, and filesystem GIDs)
+	GIDs [4]string
 }
 
 // NewStatus returns the current status information of the process.
@@ -119,6 +121,8 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt
 		s.Name = vString
 	case "Uid":
 		copy(s.UIDs[:], strings.Split(vString, "\t"))
+	case "Gid":
+		copy(s.GIDs[:], strings.Split(vString, "\t"))
 	case "VmPeak":
 		s.VmPeak = vUintBytes
 	case "VmSize":


Test patch:
diff --git a/cpuinfo_test.go b/cpuinfo_test.go
index 954f4e7..bfec15d 100644
--- a/cpuinfo_test.go
+++ b/cpuinfo_test.go
@@ -203,6 +203,18 @@ timebase	: 512000000
 platform	: pSeries
 model		: IBM,8233-E8B
 machine		: CHRP IBM,8233-E8B
+`
+
+	cpuinfoRiscv64 = `
+processor	: 0
+hart		: 0
+isa		: rv64imafdcsu
+mmu		: sv48
+
+processor	: 1
+hart		: 1
+isa		: rv64imafdcsu
+mmu		: sv48
 `
 )
 
@@ -345,3 +357,19 @@ func TestCPUInfoParsePPC(t *testing.T) {
 		t.Errorf("want cpu mhz %v, have %v", want, have)
 	}
 }
+
+func TestCPUInfoParseRISCV64(t *testing.T) {
+	cpuinfo, err := parseCPUInfoRISCV([]byte(cpuinfoRiscv64))
+	if err != nil || cpuinfo == nil {
+		t.Fatalf("unable to parse ppc cpu info: %v", err)
+	}
+	if want, have := 2, len(cpuinfo); want != have {
+		t.Errorf("want number of processors %v, have %v", want, have)
+	}
+	if want, have := "1", cpuinfo[1].CoreID; want != have {
+		t.Errorf("want CoreId %v, have %v", want, have)
+	}
+	if want, have := "rv64imafdcsu", cpuinfo[1].ModelName; want != have {
+		t.Errorf("want ModelName %v, have %v", want, have)
+	}
+}
diff --git a/proc_status_test.go b/proc_status_test.go
index 828c1c9..e132848 100644
--- a/proc_status_test.go
+++ b/proc_status_test.go
@@ -91,3 +91,19 @@ func TestProcStatusUIDs(t *testing.T) {
 		t.Errorf("want uids %s, have %s", want, have)
 	}
 }
+
+func TestProcStatusGIDs(t *testing.T) {
+	p, err := getProcFixtures(t).Proc(26231)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s, err := p.NewStatus()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if want, have := [4]string{"1001", "1001", "1001", "0"}, s.GIDs; want != have {
+		t.Errorf("want uids %s, have %s", want, have)
+	}
+}