Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set ProctState.Username on darwin and linux #16

Merged
merged 1 commit into from
Jan 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ os:
- osx

go:
- 1.5.1
- 1.5.3

env:
global:
Expand Down
11 changes: 11 additions & 0 deletions sigar_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"encoding/binary"
"fmt"
"io"
"os/user"
"strconv"
"syscall"
"time"
"unsafe"
Expand Down Expand Up @@ -256,6 +258,15 @@ func (self *ProcState) Get(pid int) error {

self.Nice = int(info.pbsd.pbi_nice)

// Get process username. Fallback to UID if username is not available.
uid := strconv.Itoa(int(info.pbsd.pbi_uid))
user, err := user.LookupId(uid)
if err == nil && user.Username != "" {
self.Username = user.Username
} else {
self.Username = uid
}

return nil
}

Expand Down
50 changes: 50 additions & 0 deletions sigar_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"io"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
Expand Down Expand Up @@ -218,6 +220,22 @@ func (self *ProcState) Get(pid int) error {

self.Processor, _ = strconv.Atoi(fields[36])

// Read /proc/[pid]/status to get the uid, then lookup uid to get username.
status, err := getProcStatus(pid)
if err != nil {
return fmt.Errorf("failed to read process status for pid %d. %v", pid, err)
}
uids, err := getUIDs(status)
if err != nil {
return fmt.Errorf("failed to read process status for pid %d. %v", pid, err)
}
user, err := user.LookupId(uids[0])
if err == nil {
self.Username = user.Username
} else {
self.Username = uids[0]
}

return nil
}

Expand Down Expand Up @@ -393,3 +411,35 @@ func readProcFile(pid int, name string) ([]byte, error) {

return contents, err
}

// getProcStatus reads /proc/[pid]/status which contains process status
// information in human readable form.
func getProcStatus(pid int) (map[string]string, error) {
status := make(map[string]string, 42)
path := filepath.Join(Procd, strconv.Itoa(pid), "status")
err := readFile(path, func(line string) bool {
fields := strings.SplitN(line, ":", 2)
if len(fields) == 2 {
status[fields[0]] = strings.TrimSpace(fields[1])
}

return true
})
return status, err
}

// getUIDs reads the "Uid" value from status and splits it into four values --
// real, effective, saved set, and file system UIDs.
func getUIDs(status map[string]string) ([]string, error) {
uidLine, ok := status["Uid"]
if !ok {
return nil, fmt.Errorf("Uid not found in proc status")
}

uidStrs := strings.Fields(uidLine)
if len(uidStrs) != 4 {
return nil, fmt.Errorf("Uid line ('%s') did not contain four values", uidLine)
}

return uidStrs, nil
}
29 changes: 29 additions & 0 deletions sigar_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// +build linux darwin windows

package sigar_test

import (
"os"
"os/user"
"testing"

sigar "github.com/elastic/gosigar"
)

func TestProcStateUsername(t *testing.T) {
proc := sigar.ProcState{}
err := proc.Get(os.Getpid())
if err != nil {
t.Fatal(err)
}

user, err := user.Current()
if err != nil {
t.Fatal(err)
}

if user.Username != proc.Username {
t.Fatalf("Usernames don't match, expected %s, but got %s",
user.Username, proc.Username)
}
}