diff --git a/common.go b/common.go index 5091d7f..f953008 100644 --- a/common.go +++ b/common.go @@ -10,6 +10,7 @@ import ( "bufio" "os" "strings" + ) // Read contents from file and split by new line. @@ -31,3 +32,20 @@ func ReadLines(filename string) ([]string, error) { return ret, err } + + +func byteToString(orig []byte) string{ + n := -1 + for i, b := range orig { + if b == 0 { + break + } + n = i + 1 + } + if n == -1{ + return string(orig) + }else{ + return string(orig[:n]) + } + +} diff --git a/host.go b/host.go index a3ed2f1..d332d33 100644 --- a/host.go +++ b/host.go @@ -7,3 +7,10 @@ type HostInfoStat struct { Uptime int64 `json:"uptime"` Procs uint64 `json:"procs"` } + +type UserStat struct { + User string `json:"user"` + Terminal string `json:"terminal"` + Host string `json:"host"` + Started int `json:"started"` +} diff --git a/host_linux.go b/host_linux.go index e1e6c1f..6f71945 100644 --- a/host_linux.go +++ b/host_linux.go @@ -1,12 +1,39 @@ -// +build linux +// +build linux,amd64 package gopsutil import ( + "encoding/binary" + "bytes" + "io/ioutil" "os" "syscall" + "unsafe" ) +type exit_status struct { + E_termination int16 // Process termination status. + E_exit int16 // Process exit status. +} +type timeval struct { + Tv_sec uint32 // Seconds. + Tv_usec uint32 // Microseconds. +} + +type utmp struct { + Ut_type int16 // Type of login. + Ut_pid int32 // Process ID of login process. + Ut_line [32]byte // Devicename. + Ut_id [4]byte // Inittab ID. + Ut_user [32]byte // Username. + Ut_host [256]byte // Hostname for remote login. + Ut_exit exit_status // Exit status of a process marked + Ut_session int32 // Session ID, used for windowing. + Ut_tv timeval // Time entry was made. + Ut_addr_v6 [16]byte // Internet address of remote host. + Unused [20]byte // Reserved for future use. // original is 20 +} + func HostInfo() (HostInfoStat, error) { ret := HostInfoStat{} @@ -19,11 +46,50 @@ func HostInfo() (HostInfoStat, error) { return ret, nil } - -func Boot_time() (int64, error){ +func Boot_time() (int64, error) { sysinfo := &syscall.Sysinfo_t{} if err := syscall.Sysinfo(sysinfo); err != nil { return 0, err } return sysinfo.Uptime, nil } + +func Users() ([]UserStat, error) { + utmpfile := "/var/run/utmp" + ret := make([]UserStat, 0) + + file, err := os.Open(utmpfile) + if err != nil { + return ret, err + } + + buf, err := ioutil.ReadAll(file) + if err != nil { + return ret, err + } + + u := utmp{} + entrySize := int(unsafe.Sizeof(u)) + count := len(buf) / entrySize + + for i := 0; i < count; i++ { + b := buf[i*entrySize : i*entrySize+entrySize] + + var u utmp + br := bytes.NewReader(b) + err := binary.Read(br, binary.LittleEndian, &u) + if err != nil { + continue + } + user := UserStat{ + User: byteToString(u.Ut_user[:]), + Terminal: byteToString(u.Ut_line[:]), + Host: byteToString(u.Ut_host[:]), + Started: int(u.Ut_tv.Tv_sec), + } + ret = append(ret, user) + } + + return ret, nil + +} diff --git a/host_test.go b/host_test.go index a617717..d4906a6 100644 --- a/host_test.go +++ b/host_test.go @@ -23,3 +23,16 @@ func TestBoot_time(t *testing.T) { t.Errorf("Could not boot time %v", v) } } + + +func TestUsers(t *testing.T) { + v, err := Users() + if err != nil { + t.Errorf("error %v", err) + } + for _, u := range v { + if u.User == ""{ + t.Errorf("Could not Users %v", v) + } + } +}