-
Notifications
You must be signed in to change notification settings - Fork 0
/
goutmp.go
151 lines (131 loc) · 3.41 KB
/
goutmp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2023~2024 wangqi. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package goutmp
import (
"encoding/binary"
"fmt"
"os"
"strconv"
"time"
"unsafe"
)
// set GOFLAGS="-tags=utmps" before nvim for musl based linux
// set GOFLAGS="-tags=utmp" before nvim for glibc based linux
// check whether device exist, the line parameter should be form of "pts/0" or "ttys001"
func DeviceExists(line string) bool {
deviceName := fmt.Sprintf("/dev/%s", line)
_, err := os.Lstat(deviceName)
return err == nil
}
// return true if we can read from the utmp data file
func HasUtmpSupport() bool {
r := GetRecord()
return r != nil
}
// // return remote client hostname or IP if host lookup fails
// // addr is expected to be of the format given by net.Addr.String()
// // eg., "127.0.0.1:80" or "[::1]:80"
// func GetHost(addr string) (h string) {
// if !strings.Contains(addr, "[") {
// h = strings.Split(addr, ":")[0]
// } else {
// h = strings.Split(strings.Split(addr, "[")[1], "]")[0]
// }
// hList, e := net.LookupAddr(h)
// // fmt.Printf("lookupAddr:%v\n", hList)
// if e == nil {
// h = hList[0]
// }
// return
// }
func (u *Utmpx) GetHost() string { return b2s(u.Host[:UTMPS_UT_HOSTSIZE]) }
func (u *Utmpx) GetId() int {
i, _ := strconv.Atoi(b2s(u.Id[:UTMPS_UT_IDSIZE]))
return i
}
func (u *Utmpx) GetLine() string { return b2s(u.Line[:UTMPS_UT_LINESIZE]) }
func (u *Utmpx) GetPid() int { return int(u.Pid) }
func (u *Utmpx) GetTime() time.Time { return time.Unix(u.Tv.Sec, u.Tv.Usec) }
func (u *Utmpx) GetType() int { return int(u.Type) }
func (u *Utmpx) GetUser() string { return b2s(u.User[:UTMPS_UT_NAMESIZE]) }
func (u *Utmpx) SetHost(s string) {
data := []byte(s)
for i := range u.Host {
if i < len(data) {
u.Host[i] = int8(data[i])
} else {
break
}
}
}
func (u *Utmpx) SetId(id int) {
data := []byte(fmt.Sprintf("%d", id))
for i := range u.Id {
if i < len(data) && i < UTMPS_UT_IDSIZE {
u.Id[i] = int8(data[i])
} else {
break
}
}
}
func (u *Utmpx) SetLine(s string) {
data := []byte(s)
for i := range u.Line {
if i < len(data) {
u.Line[i] = int8(data[i])
} else {
break
}
}
}
func (u *Utmpx) SetPid(pid int) { u.Pid = int32(pid) }
func (u *Utmpx) SetTime(t time.Time) {
u.Tv.Sec = t.Unix()
u.Tv.Usec = (t.UnixNano() / 1e3 % 1e3)
}
func (u *Utmpx) SetType(t int) { u.Type = int16(t) }
func (u *Utmpx) SetUser(s string) {
data := []byte(s)
for i := range u.User {
if i < len(data) {
u.User[i] = int8(data[i])
} else {
break
}
}
}
// convert int8 arrary to string
func b2s(bs []int8) string {
// https://stackoverflow.com/questions/28848187/how-to-convert-int8-to-string
ba := make([]byte, 0, len(bs))
for _, b := range bs {
if b == 0 { // skip zero
continue
}
ba = append(ba, byte(b))
}
return string(ba)
}
// return true if we can read from the utmp data file
// func HasUtmpSupport() bool {
// r := GetUtmpx()
// if r != nil {
// return true
// }
// return false
// }
var hostEndian binary.ByteOrder
func init() {
// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
buf := [2]byte{}
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD)
switch buf {
case [2]byte{0xCD, 0xAB}:
hostEndian = binary.LittleEndian
case [2]byte{0xAB, 0xCD}:
hostEndian = binary.BigEndian
default:
panic("Could not determine native endianness.")
}
}