Compare commits

..

20 Commits

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea
.vscode

@ -0,0 +1,28 @@
// +build darwin
package staros
import (
"os"
"os/exec"
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 0.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 0
)
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
func Beep(freq float64, duration int) error {
osa, err := exec.LookPath("osascript")
if err != nil {
// Output the only beep we can
_, err = os.Stdout.Write([]byte{7})
return err
}
cmd := exec.Command(osa, "-e", `beep`)
return cmd.Run()
}

@ -0,0 +1,138 @@
// +build linux
package staros
import (
"errors"
"os"
"syscall"
"time"
"unsafe"
)
// Constants
const (
// This number represents the fixed frequency of the original PC XT's timer chip, which is approximately 1.193 MHz. This number
// is divided with the desired frequency to obtain a counter value, that is subsequently fed into the timer chip, tied to the PC speaker.
clockTickRate = 1193180
// linux/kd.h, start sound generation (0 for off)
kiocsound = 0x4B2F
// linux/input-event-codes.h
evSnd = 0x12 // Event type
sndTone = 0x02 // Sound
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 440.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 200
)
// inputEvent represents linux/input.h event structure.
type inputEvent struct {
Time syscall.Timeval // time in seconds since epoch at which event occurred
Type uint16 // event type
Code uint16 // event code related to the event type
Value int32 // event value related to the event type
}
// ioctl system call manipulates the underlying device parameters of special files.
func ioctl(fd, name, data uintptr) error {
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, name, data)
if e != 0 {
return e
}
return nil
}
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
//
// On Linux it needs permission to access `/dev/tty0` or `/dev/input/by-path/platform-pcspkr-event-spkr` files for writing,
// and `pcspkr` module must be loaded. User must be in correct groups, usually `input` and/or `tty`.
//
// If it can not open device files, it will fallback to sending Bell character (https://en.wikipedia.org/wiki/Bell_character).
// For bell character in X11 terminals you can enable bell with `xset b on`. For console check `setterm` and `--blength` or `--bfreq` options.
//
// On macOS this just sends bell character. Enable `Audible bell` in Terminal --> Preferences --> Settings --> Advanced.
//
// On Windows it uses Beep function via syscall.
//
// On Web it plays hard coded beep sound.
func Beep(freq float64, duration int) error {
if freq == 0 {
freq = DefaultFreq
} else if freq > 20000 {
freq = 20000
} else if freq < 0 {
freq = DefaultFreq
}
if duration == 0 {
duration = DefaultDuration
}
period := int(float64(clockTickRate) / freq)
var evdev bool
f, err := os.OpenFile("/dev/tty0", os.O_WRONLY, 0644)
if err != nil {
e := err
f, err = os.OpenFile("/dev/input/by-path/platform-pcspkr-event-spkr", os.O_WRONLY, 0644)
if err != nil {
e = errors.New("beeep: " + e.Error() + "; " + err.Error())
// Output the only beep we can
_, err = os.Stdout.Write([]byte{7})
if err != nil {
return errors.New(e.Error() + "; " + err.Error())
}
return nil
}
evdev = true
}
defer f.Close()
if evdev { // Use Linux evdev API
ev := inputEvent{}
ev.Type = evSnd
ev.Code = sndTone
ev.Value = int32(freq)
d := *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
// Start beep
f.Write(d[:])
time.Sleep(time.Duration(duration) * time.Millisecond)
ev.Value = 0
d = *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
// Stop beep
f.Write(d[:])
} else { // Use ioctl
// Start beep
err = ioctl(f.Fd(), kiocsound, uintptr(period))
if err != nil {
return err
}
time.Sleep(time.Duration(duration) * time.Millisecond)
// Stop beep
err = ioctl(f.Fd(), kiocsound, uintptr(0))
if err != nil {
return err
}
}
return nil
}

@ -0,0 +1,37 @@
package staros
import (
"fmt"
"testing"
"time"
)
const (
rat float64 = 1.059463094 //2^(1/12)
C float64 = 493.8833013 * rat
CU = C * rat * rat
D = CU * rat
DU = D * rat
E = DU * rat
F = E * rat
FU = F * rat
G = FU * rat
GU = G * rat
A = GU * rat
AU = A * rat
B = AU * rat
)
func beepMusic(qual ...float64) {
for _, v := range qual {
fmt.Println(v)
Beep(v, 700)
time.Sleep(time.Millisecond * 1000)
}
}
func Test_Music(t *testing.T) {
beepMusic(G, D, A, AU, A, G, F, D, DU, D, C, D, AU/2, C, G/2, C, D)
time.Sleep(time.Second * 3)
beepMusic(D,AU,A,G,A,D*2,F*2,G*2,F*2,D*2,D*2,C*2,D*2,DU*2,D*2,AU,A,E,G,FU)
}

@ -0,0 +1,41 @@
// +build windows
package staros
import (
"syscall"
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 587.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 500
)
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
func Beep(freq float64, duration int) error {
if freq == 0 {
freq = DefaultFreq
} else if freq > 32767 {
freq = 32767
} else if freq < 37 {
freq = DefaultFreq
}
if duration == 0 {
duration = DefaultDuration
}
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
beep32, _ := syscall.GetProcAddress(kernel32, "Beep")
defer syscall.FreeLibrary(kernel32)
_, _, e := syscall.Syscall(uintptr(beep32), uintptr(2), uintptr(int(freq)), uintptr(duration), 0)
if e != 0 {
return e
}
return nil
}

@ -1,6 +1,18 @@
package staros package staros
import "os" import (
"errors"
"os"
)
var ERR_ALREADY_LOCKED = errors.New("ALREADY LOCKED")
var ERR_TIMEOUT = errors.New("TIME OUT")
func NewFileLock(filepath string) FileLock {
return FileLock{
filepath: filepath,
}
}
// 检测文件/文件夹是否存在 // 检测文件/文件夹是否存在
func Exists(path string) bool { func Exists(path string) bool {

@ -0,0 +1,91 @@
//+build darwin
package staros
import (
"b612.me/stario"
"os"
"syscall"
"time"
)
type FileLock struct {
fd int
filepath string
}
func (f *FileLock) openFileForLock() error {
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
if err != nil {
return err
}
f.filepath = f.filepath
f.fd = fd
return nil
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
return syscall.Flock(f.fd, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
if err != nil {
syscall.Close(f.fd)
if err == syscall.EWOULDBLOCK {
return ERR_ALREADY_LOCKED
}
}
return err
}
func (f *FileLock) Unlock() error {
err := syscall.Flock(f.fd, syscall.LOCK_UN)
if err != nil {
return err
}
return syscall.Close(f.fd)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
err := f.Lock(Exclusive)
select {
case <-tmout:
f.Unlock()
return nil
default:
}
return err
})
}
func timespecToTime(ts syscall.Timespec) time.Time {
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctimespec)
}
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atimespec)
}

@ -0,0 +1,23 @@
package staros
import (
"fmt"
"os"
"testing"
"time"
)
func Test_FileLock(t *testing.T) {
filename := "./test.file"
lock := NewFileLock(filename)
lock2 := NewFileLock(filename)
fmt.Println("lock1", lock.LockNoBlocking(false))
time.Sleep(time.Second)
fmt.Println("lock2", lock2.LockWithTimeout(time.Second*5, false))
fmt.Println("unlock1", lock.Unlock())
time.Sleep(time.Second)
fmt.Println("unlock2", lock2.Unlock())
fmt.Println("lock2", lock2.LockNoBlocking(true))
fmt.Println("unlock2", lock2.Unlock())
os.Remove(filename)
}

@ -1,13 +1,19 @@
//+build linux darwin //+build linux
package staros package staros
import ( import (
"b612.me/stario"
"os" "os"
"syscall" "syscall"
"time" "time"
) )
type FileLock struct {
fd int
filepath string
}
func timespecToTime(ts syscall.Timespec) time.Time { func timespecToTime(ts syscall.Timespec) time.Time {
return time.Unix(int64(ts.Sec), int64(ts.Nsec)) return time.Unix(int64(ts.Sec), int64(ts.Nsec))
} }
@ -19,3 +25,67 @@ func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
func GetFileAccessTime(fileinfo os.FileInfo) time.Time { func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim) return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim)
} }
func (f *FileLock) openFileForLock() error {
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
if err != nil {
return err
}
f.filepath = f.filepath
f.fd = fd
return nil
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
return syscall.Flock(f.fd, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
if err != nil {
syscall.Close(f.fd)
if err == syscall.EWOULDBLOCK {
return ERR_ALREADY_LOCKED
}
}
return err
}
func (f *FileLock) Unlock() error {
err := syscall.Flock(f.fd, syscall.LOCK_UN)
if err != nil {
return err
}
return syscall.Close(f.fd)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
err := f.Lock(Exclusive)
select {
case <-tmout:
f.Unlock()
return nil
default:
}
return err
})
}

@ -3,11 +3,17 @@
package staros package staros
import ( import (
"b612.me/win32api"
"os" "os"
"syscall" "syscall"
"time" "time"
) )
type FileLock struct {
filepath string
handle win32api.HANDLE
}
func GetFileCreationTime(fileinfo os.FileInfo) time.Time { func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
d := fileinfo.Sys().(*syscall.Win32FileAttributeData) d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
return time.Unix(0, d.CreationTime.Nanoseconds()) return time.Unix(0, d.CreationTime.Nanoseconds())
@ -17,3 +23,101 @@ func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
d := fileinfo.Sys().(*syscall.Win32FileAttributeData) d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
return time.Unix(0, d.LastAccessTime.Nanoseconds()) return time.Unix(0, d.LastAccessTime.Nanoseconds())
} }
func SetFileTimes(file *os.File, info os.FileInfo) {
}
func SetFileTimesbyTime(file *os.File) {
}
func (f *FileLock) openFileForLock() error {
name, err := syscall.UTF16PtrFromString(f.filepath)
if err != nil {
return err
}
handle, err := syscall.CreateFile(
name,
syscall.GENERIC_READ,
syscall.FILE_SHARE_READ,
nil,
syscall.OPEN_ALWAYS,
syscall.FILE_FLAG_OVERLAPPED|0x00000080,
0)
if err != nil {
return err
}
f.handle = win32api.HANDLE(handle)
return nil
}
func (f *FileLock) lockForTimeout(timeout time.Duration, lockType win32api.DWORD) error {
var err error
if err = f.openFileForLock(); err != nil {
return err
}
event, err := win32api.CreateEventW(nil, true, false, nil)
if err != nil {
return err
}
myEvent := &syscall.Overlapped{HEvent: syscall.Handle(event)}
defer syscall.CloseHandle(myEvent.HEvent)
_, err = win32api.LockFileEx(f.handle, lockType, 0, 1, 0, myEvent)
if err == nil {
return nil
}
if err != syscall.ERROR_IO_PENDING {
return err
}
millis := uint32(syscall.INFINITE)
if timeout >= 0 {
millis = uint32(timeout.Nanoseconds() / 1000000)
}
s, err := syscall.WaitForSingleObject(myEvent.HEvent, millis)
switch s {
case syscall.WAIT_OBJECT_0:
// success!
return nil
case syscall.WAIT_TIMEOUT:
f.Unlock()
return ERR_TIMEOUT
default:
f.Unlock()
return err
}
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(0, lockType)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(tm, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(0, lockType|win32api.LOCKFILE_FAIL_IMMEDIATELY)
}
func (f *FileLock) Unlock() error {
return syscall.Close(syscall.Handle(f.handle))
}

@ -0,0 +1,10 @@
module b612.me/staros
go 1.16
require (
b612.me/stario v0.0.10
b612.me/win32api v0.0.2
b612.me/wincmd v0.0.4
golang.org/x/sys v0.24.0
)

@ -0,0 +1,75 @@
b612.me/stario v0.0.10 h1:+cIyiDCBCjUfodMJDp4FLs+2E1jo7YENkN+sMEe6550=
b612.me/stario v0.0.10/go.mod h1:1Owmu9jzKWgs4VsmeI8YWlGwLrCwPNM/bYpxkyn+MMk=
b612.me/win32api v0.0.2 h1:5PwvPR5fYs3a/v+LjYdtRif+5Q04zRGLTVxmCYNjCpA=
b612.me/win32api v0.0.2/go.mod h1:sj66sFJDKElEjOR+0YhdSW6b4kq4jsXu4T5/Hnpyot0=
b612.me/wincmd v0.0.4 h1:fv9p1V8mw2HdUjaoZBWZy0T41JftueyLxAuch1MgtdI=
b612.me/wincmd v0.0.4/go.mod h1:o3yPoE+DpVPHGKl/q1WT1C8OaIVwHEnpeNgMFqzlwD8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

File diff suppressed because it is too large Load Diff

@ -6,7 +6,149 @@ import (
) )
func Test_Hosts(t *testing.T) { func Test_Hosts(t *testing.T) {
//RemoveHostbyIp("192.168.222.33") var h = NewHosts()
Parse() err := h.Parse("./test_hosts.txt")
fmt.Println(GetAllListbyIp()) if err != nil {
t.Error(err)
}
next := h.firstUid
for next != 0 {
node, _ := h.GetNode(next)
fmt.Printf("Last %d, Next: %d, IP: %s, Hosts: %s, Comment: %s\n", node.LastUID(), node.NextUID(), node.IP(), node.Hosts(), node.Comment())
next = node.NextUID()
}
data := h.ListHostsByIP("11.22.33.44")
if len(data) != 2 {
t.Error("Expected 2, got ", len(data))
} else {
t.Log(data)
}
data = h.ListIPsByHost("dns.b612.me")
if len(data) < 1 || data[0] != "4.5.6.7" {
t.Error("Expected 4.5.6.7, got ", data)
} else {
t.Log(data)
}
err = h.RemoveHosts("dns.b612.me")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("dns.b612.me")
if len(data) > 0 {
t.Error("Expected 0, got ", len(data))
} else {
t.Log(data)
}
err = h.RemoveHosts("test.dns.set.b612.me")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("remove.b612.me")
if len(data) < 1 || data[0] != "11.22.33.44" {
t.Error("Expected 11.22.33.44, got ", data)
} else {
t.Log(data)
}
nodes := h.ListByIP("11.22.33.44")
if nodes == nil {
t.Error("Expected not nil, got ", nodes)
} else {
t.Log(nodes)
}
nodes[0].AddHosts("hello.b612.me")
err = h.UpdateNode(nodes[0])
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("hello.b612.me")
if len(data) < 1 || data[0] != "11.22.33.44" {
t.Error("Not Expected Data", data)
} else {
t.Log(data)
}
insertNode := new(HostNode)
insertNode.SetIP("11.11.11.11")
insertNode.SetHosts("insert.b612.me")
insertNode.SetComment("Insert Node")
insertNode.SetNextUID(nodes[0].UID())
insertNode.SetLastUID(nodes[0].LastUID())
err = h.InsertNode(insertNode)
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("insert.b612.me")
if len(data) < 1 || data[0] != "11.11.11.11" {
t.Error("Expected 11.11.11.11 got ", data)
} else {
t.Log(data)
}
err = h.SaveAs("./test_hosts_01.txt")
if err != nil {
t.Error(err)
}
err = h.DeleteNode(insertNode)
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("insert.b612.me")
if len(data) > 0 {
t.Error("Expected 0 got ", data)
} else {
t.Log(data)
}
for i := 0; i < 100; i++ {
err = h.RemoveHosts("release-ftpd")
if err != nil {
t.Error(err)
}
err = h.AddHosts("2.3.4.9", "release-ftpd")
if err != nil {
t.Error(err)
}
}
err = h.SetHostIPs("ssh.b612.me", "9.9.9.9")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("ssh.b612.me")
if len(data) == 0 {
t.Error("Expected 1 got ", data)
} else {
t.Log(data)
}
err = h.SetIPHosts("10.10.10.10", "ssh.b612.me", "ssr.b612.me")
if len(data) == 0 {
t.Error("Expected 1 got ", data)
}
err = h.SaveAs("./test_hosts_02.txt")
if err != nil {
t.Error(err)
}
}
func BenchmarkAddHosts(b *testing.B) {
var h = NewHosts()
err := h.Parse("./test_hosts.txt")
if err != nil {
b.Error(err)
}
for i := 0; i < b.N; i++ {
err = h.AddHosts("1.3.4.5", "test.b612.me")
if err != nil {
b.Error(err)
}
}
} }

@ -0,0 +1,23 @@
#hosts This file describes a number of hostname-to-address
#mappings for the TCP/IP subsystem. It is mostly
#used at boot time, when no name servers are running.
#On small systems, this file can be used instead of a
#"named" name server.
#Syntax:
#IP-Address Full-Qualifie
#special IPv6 addre
127.0.0.1 localhost
127.0.0.1 b612
8.8.8.8 ssh.b612.me
#special IPv6 addresses
::1 localhost ipv6-localhost ipv6-loopback
fe00::0 ipv6-localnet
ff00::0 ipv6-mcastprefix
ff02::1 ipv6-allnodes
ff02::2 ipv6-allrouters
ff02::3 ipv6-allhosts
1.2.3.4 ssh.b612.me
4.5.6.7 dns.b612.me
8.9.10.11 release-ftpd
11.22.33.44 test.dns.set.b612.me remove.b612.me
4.5.6.7 game.b612.me

@ -14,7 +14,17 @@ func Calc(math string) (float64, error) {
if err := check(math); err != nil { if err := check(math); err != nil {
return 0, err return 0, err
} }
return calc(math) result,err:=calc(math)
if err!=nil {
return 0,err
}
return floatRound(result,15),nil
}
func floatRound(f float64, n int) float64 {
format := "%." + strconv.Itoa(n) + "f"
res, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64)
return res
} }
func check(math string) error { func check(math string) error {
@ -37,11 +47,12 @@ func check(math string) error {
if string([]rune{v}) != "+" && string([]rune{v}) != "-" { if string([]rune{v}) != "+" && string([]rune{v}) != "-" {
return fmt.Errorf("err at position %d.Reason is sign %s not correct", k, string([]rune{v})) return fmt.Errorf("err at position %d.Reason is sign %s not correct", k, string([]rune{v}))
} }
signReady = false
} else { } else {
signReady = true signReady = true
continue
} }
} }
signReady = false
} }
if bracketSum != 0 { if bracketSum != 0 {
return fmt.Errorf("Error:right bracket is not equal as left bracket") return fmt.Errorf("Error:right bracket is not equal as left bracket")
@ -188,16 +199,16 @@ func calcPool(numPool []float64, operPool []string) (float64, error) {
func calcSigFloat(floatA float64, b string, floatC float64) (float64, error) { func calcSigFloat(floatA float64, b string, floatC float64) (float64, error) {
switch b { switch b {
case "+": case "+":
return floatA + floatC, nil return floatRound(floatA + floatC,15), nil
case "-": case "-":
return floatA - floatC, nil return floatRound(floatA - floatC,15), nil
case "*": case "*":
return floatA * floatC, nil return floatRound(floatA * floatC,15), nil
case "/": case "/":
if floatC == 0 { if floatC == 0 {
return 0, errors.New("Divisor cannot be 0") return 0, errors.New("Divisor cannot be 0")
} }
return floatA / floatC, nil return floatRound(floatA / floatC,15), nil
case "^": case "^":
return math.Pow(floatA, floatC), nil return math.Pow(floatA, floatC), nil
} }

@ -2,7 +2,100 @@
package staros package staros
import (
"encoding/binary"
"fmt"
"golang.org/x/sys/unix"
"os/exec"
"strconv"
"strings"
"unsafe"
)
// Memory 系统内存信息 // Memory 系统内存信息
func Memory() MemStatus { func Memory() (MemStatus,error) {
return MemStatus{} return darwinMemory()
}
type swapUsage struct {
Total uint64
Avail uint64
Used uint64
Pagesize int32
Encrypted bool
}
func darwinMemory() (MemStatus, error) {
var err error
var res MemStatus
vm_stat, err := exec.LookPath("vm_stat")
if err != nil {
return res, err
}
out, err := exec.Command(vm_stat).CombinedOutput()
if err != nil {
return res, err
}
totalString, err := unix.Sysctl("hw.memsize")
if err != nil {
return res, err
}
// unix.sysctl() helpfully assumes the result is a null-terminated string and
// removes the last byte of the result if it's 0 :/
totalString += "\x00"
res.All = uint64(binary.LittleEndian.Uint64([]byte(totalString)))
lines := strings.Split(string(out), "\n")
pagesize := uint64(unix.Getpagesize())
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.Trim(fields[1], " .")
switch key {
case "Pages free":
free, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
res.Free = free * pagesize
case "Pages inactive":
inactive, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
res.Available = inactive * pagesize
case "Pages active":
active, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
_ = active * pagesize
case "Pages wired down":
wired, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
_ = wired * pagesize
}
}
res.Available += res.Free
res.Used = res.All - res.Available
//swap
value, err := unix.SysctlRaw("vm.swapusage")
if err != nil {
return res, err
}
if len(value) != 32 {
return res, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value))
}
swap := (*swapUsage)(unsafe.Pointer(&value[0]))
res.SwapAll = swap.Total
res.SwapUsed = swap.Used
res.SwapFree = swap.Avail
return res, err
} }

@ -5,11 +5,11 @@ package staros
import "syscall" import "syscall"
// Memory 系统内存信息 // Memory 系统内存信息
func Memory() MemStatus { func Memory() (MemStatus, error) {
var mem MemStatus var mem MemStatus
ram := new(syscall.Sysinfo_t) ram := new(syscall.Sysinfo_t)
if err := syscall.Sysinfo(ram); err != nil { if err := syscall.Sysinfo(ram); err != nil {
return mem return mem, err
} }
mem.All = uint64(ram.Totalram) mem.All = uint64(ram.Totalram)
mem.BuffCache = uint64(ram.Bufferram) mem.BuffCache = uint64(ram.Bufferram)
@ -20,5 +20,5 @@ func Memory() MemStatus {
mem.SwapFree = uint64(ram.Freeswap) mem.SwapFree = uint64(ram.Freeswap)
mem.SwapUsed = uint64(mem.SwapAll - mem.SwapFree) mem.SwapUsed = uint64(mem.SwapAll - mem.SwapFree)
mem.Used = uint64(mem.All - mem.Free) mem.Used = uint64(mem.All - mem.Free)
return mem return mem, nil
} }

@ -0,0 +1,26 @@
// +build windows
package staros
import "b612.me/win32api"
// Memory 系统内存信息
func Memory() (MemStatus, error) {
var mem MemStatus
ram := new(win32api.MEMORYSTATUSEX)
_, err := win32api.GlobalMemoryStatusEx(ram)
if err != nil {
return mem, err
}
mem.All = uint64(ram.UllTotalPhys)
mem.Free = uint64(ram.UllAvailPhys)
mem.Available = uint64(ram.UllAvailPhys)
mem.Used = uint64(mem.All - mem.Free)
mem.SwapAll = uint64(ram.UllTotalPageFile)
mem.SwapFree = uint64(ram.UllAvailPageFile)
mem.SwapUsed = mem.SwapAll - mem.SwapFree
mem.VirtualAll = uint64(mem.VirtualAll)
mem.VirtualAvail = uint64(mem.VirtualAvail)
mem.VirtualUsed = mem.VirtualAll - mem.VirtualUsed
return mem, nil
}

@ -1,85 +0,0 @@
// +build !windows
package staros
import (
"errors"
"io/ioutil"
"strconv"
"strings"
"time"
)
func NetUsage() ([]NetAdapter, error) {
data, err := ioutil.ReadFile("/proc/net/dev")
if err != nil {
return []NetAdapter{}, err
}
sps := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(sps) < 3 {
return []NetAdapter{}, errors.New("No Adaptor")
}
var res []NetAdapter
netLists := sps[2:]
for _, v := range netLists {
v = strings.ReplaceAll(v, " ", " ")
for strings.Contains(v, " ") {
v = strings.ReplaceAll(v, " ", " ")
}
v = strings.TrimSpace(v)
card := strings.Split(v, " ")
name := strings.ReplaceAll(card[0], ":", "")
recvBytes, _ := strconv.Atoi(card[1])
sendBytes, _ := strconv.Atoi(card[9])
res = append(res, NetAdapter{name, uint64(recvBytes), uint64(sendBytes)})
}
return res, nil
}
func NetUsageByname(name string) (NetAdapter, error) {
ada, err := NetUsage()
if err != nil {
return NetAdapter{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetAdapter{}, errors.New("Not Found")
}
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
list1, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
time.Sleep(duration)
list2, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
if len(list1) > len(list2) {
return []NetSpeed{}, errors.New("NetWork Adaptor Num Not ok")
}
var res []NetSpeed
for k, v := range list1 {
recv := float64(list2[k].RecvBytes-v.RecvBytes) / duration.Seconds()
send := float64(list2[k].SendBytes-v.SendBytes) / duration.Seconds()
res = append(res, NetSpeed{v.Name, recv, send})
}
return res, nil
}
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
ada, err := NetSpeeds(duration)
if err != nil {
return NetSpeed{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetSpeed{}, errors.New("Not Found")
}

@ -0,0 +1,9 @@
package staros
import (
"testing"
)
func Test_TrimSpace(t *testing.T) {
}

@ -0,0 +1,326 @@
//go:build !windows
// +build !windows
package staros
import (
"errors"
"io/ioutil"
"os"
"strconv"
"strings"
"time"
)
func NetUsage() ([]NetAdapter, error) {
data, err := ioutil.ReadFile("/proc/net/dev")
if err != nil {
return []NetAdapter{}, err
}
sps := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(sps) < 3 {
return []NetAdapter{}, errors.New("No Adaptor")
}
var res []NetAdapter
netLists := sps[2:]
for _, v := range netLists {
v = strings.ReplaceAll(v, " ", " ")
for strings.Contains(v, " ") {
v = strings.ReplaceAll(v, " ", " ")
}
v = strings.TrimSpace(v)
card := strings.Split(v, " ")
name := strings.ReplaceAll(card[0], ":", "")
recvBytes, _ := strconv.Atoi(card[1])
sendBytes, _ := strconv.Atoi(card[9])
res = append(res, NetAdapter{name, uint64(recvBytes), uint64(sendBytes)})
}
return res, nil
}
func NetUsageByname(name string) (NetAdapter, error) {
ada, err := NetUsage()
if err != nil {
return NetAdapter{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetAdapter{}, errors.New("Not Found")
}
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
list1, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
time.Sleep(duration)
list2, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
if len(list1) > len(list2) {
return []NetSpeed{}, errors.New("NetWork Adaptor Num Not ok")
}
var res []NetSpeed
for k, v := range list1 {
recv := float64(list2[k].RecvBytes-v.RecvBytes) / duration.Seconds()
send := float64(list2[k].SendBytes-v.SendBytes) / duration.Seconds()
res = append(res, NetSpeed{
Name: v.Name,
RecvSpeeds: recv,
SendSpeeds: send,
RecvBytes: list2[k].RecvBytes,
SendBytes: list2[k].SendBytes,
})
}
return res, nil
}
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
ada, err := NetSpeeds(duration)
if err != nil {
return NetSpeed{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetSpeed{}, errors.New("Not Found")
}
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
func NetConnections(analysePid bool, types string) ([]NetConn, error) {
var result []NetConn
var inodeMap map[string]int64
var err error
var fileList []string
if types == "" || strings.Contains(strings.ToLower(types), "all") {
fileList = []string{
"/proc/net/tcp",
"/proc/net/tcp6",
"/proc/net/udp",
"/proc/net/udp6",
"/proc/net/unix",
}
}
if strings.Contains(strings.ToLower(types), "tcp") {
fileList = append(fileList, "/proc/net/tcp", "/proc/net/tcp6")
}
if strings.Contains(strings.ToLower(types), "udp") {
fileList = append(fileList, "/proc/net/udp", "/proc/net/udp6")
}
if strings.Contains(strings.ToLower(types), "unix") {
fileList = append(fileList, "/proc/net/unix")
}
if analysePid {
inodeMap, err = GetInodeMap()
if err != nil {
return result, err
}
}
for _, file := range fileList {
data, err := ioutil.ReadFile(file)
if err != nil {
return result, err
}
tmpRes, err := analyseNetFiles(data, inodeMap, file[strings.LastIndex(file, "/")+1:])
if err != nil {
return result, err
}
result = append(result, tmpRes...)
}
return result, nil
}
func GetInodeMap() (map[string]int64, error) {
res := make(map[string]int64)
paths, err := ioutil.ReadDir("/proc")
if err != nil {
return nil, err
}
for _, v := range paths {
if v.IsDir() && Exists("/proc/"+v.Name()+"/fd") {
fds, err := ioutil.ReadDir("/proc/" + v.Name() + "/fd")
if err != nil && Exists("/proc/"+v.Name()+"/fd") {
return nil, err
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + v.Name() + "/fd/" + fd.Name())
if err != nil {
continue
}
if !strings.Contains(socket, "socket") {
continue
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
pid, err := strconv.ParseInt(v.Name(), 10, 64)
if err != nil {
break
}
res[socket[start+1:len(socket)-1]] = pid
}
}
}
return res, err
}
func analyseNetFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
if typed == "unix" {
return analyseUnixFiles(data, inodeMap, typed)
}
var result []NetConn
strdata := strings.TrimSpace(string(data))
strdata = remainOne(strdata, " ", " ")
csvData := strings.Split(strdata, "\n")
pidMap := make(map[int64]*Process)
for line, lineData := range csvData {
if line == 0 {
continue
}
v := strings.Split(strings.TrimSpace(lineData), " ")
var res NetConn
ip, port, err := parseHexIpPort(v[1])
if err != nil {
return result, err
}
res.LocalAddr = ip
res.LocalPort = port
ip, port, err = parseHexIpPort(v[2])
if err != nil {
return result, err
}
res.RemoteAddr = ip
res.RemotePort = port
//connection state
if strings.Contains(typed, "tcp") {
state, err := strconv.ParseInt(strings.TrimSpace(v[3]), 16, 64)
if err != nil {
return result, err
}
res.Status = TCP_STATE[state]
}
txrx_queue := strings.Split(strings.TrimSpace(v[4]), ":")
if len(txrx_queue) != 2 {
return result, errors.New("not a valid net file")
}
tx_queue, err := strconv.ParseInt(txrx_queue[0], 16, 64)
if err != nil {
return result, err
}
res.TX_Queue = tx_queue
rx_queue, err := strconv.ParseInt(txrx_queue[1], 16, 64)
if err != nil {
return result, err
}
res.RX_Queue = rx_queue
timer := strings.Split(strings.TrimSpace(v[5]), ":")
if len(timer) != 2 {
return result, errors.New("not a valid net file")
}
switch timer[0] {
case "00":
res.TimerActive = "NO_TIMER"
case "01":
//重传定时器
res.TimerActive = "RETRANSMIT"
case "02":
//连接定时器、FIN_WAIT_2定时器或TCP保活定时器
res.TimerActive = "KEEPALIVE"
case "03":
//TIME_WAIT定时器
res.TimerActive = "TIME_WAIT"
case "04":
//持续定时器
res.TimerActive = "ZERO_WINDOW_PROBE"
default:
res.TimerActive = "UNKNOWN"
}
timerJif, err := strconv.ParseInt(timer[1], 16, 64)
if err != nil {
return result, err
}
res.TimerJiffies = timerJif
timerCnt, err := strconv.ParseInt(strings.TrimSpace(v[6]), 16, 64)
if err != nil {
return result, err
}
res.RtoTimer = timerCnt
res.Uid, err = strconv.ParseInt(v[7], 10, 64)
if err != nil {
return result, err
}
res.Inode = v[9]
if inodeMap != nil && len(inodeMap) > 0 {
var ok bool
res.Pid, ok = inodeMap[res.Inode]
if !ok {
res.Pid = -1
} else {
_, ok := pidMap[res.Pid]
if !ok {
tmp, err := FindProcessByPid(res.Pid)
if err != nil {
pidMap[res.Pid] = nil
} else {
pidMap[res.Pid] = &tmp
}
}
res.Process = pidMap[res.Pid]
}
}
res.Typed = typed
result = append(result, res)
}
return result, nil
}
func analyseUnixFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
var result []NetConn
strdata := strings.TrimSpace(string(data))
strdata = remainOne(strdata, " ", " ")
csvData := strings.Split(strdata, "\n")
pidMap := make(map[int64]*Process)
for line, lineData := range csvData {
if line == 0 {
continue
}
v := strings.Split(strings.TrimSpace(lineData), " ")
var res NetConn
res.Inode = v[6]
if len(v) == 8 {
res.Socket = v[7]
}
if inodeMap != nil && len(inodeMap) > 0 {
var ok bool
res.Pid, ok = inodeMap[res.Inode]
if !ok {
res.Pid = -1
} else {
_, ok := pidMap[res.Pid]
if !ok || pidMap[res.Pid] == nil {
tmp, err := FindProcessByPid(res.Pid)
if err != nil {
pidMap[res.Pid] = nil
} else {
pidMap[res.Pid] = &tmp
}
}
if pidMap[res.Pid] != nil {
res.Uid = int64(pidMap[res.Pid].RUID)
res.Process = pidMap[res.Pid]
}
}
}
res.Typed = typed
result = append(result, res)
}
return result, nil
}

@ -24,3 +24,10 @@ func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
return NetSpeed{}, nil return NetSpeed{}, nil
} }
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
func NetConnections(analysePid bool) ([]NetConn, error) {
var result []NetConn
return result, nil
}

@ -1,8 +1,9 @@
// +build !windows // +build linux darwin unix
package staros package staros
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os/user" "os/user"
@ -12,6 +13,8 @@ import (
"time" "time"
) )
var clockTicks = 100 // default value
// StartTime 开机时间 // StartTime 开机时间
func StartTime() time.Time { func StartTime() time.Time {
tmp, _ := readAsString("/proc/stat") tmp, _ := readAsString("/proc/stat")
@ -63,9 +66,9 @@ func getCPUSample() (idle, total uint64) {
if err != nil { if err != nil {
fmt.Println("Error: ", i, fields[i], err) fmt.Println("Error: ", i, fields[i], err)
} }
total += val // tally up all the numbers to get total ticks total += val // tally up all the numbers to get total ticks
if i == 4 { // idle is the 5th field in the cpu line if i == 4 || i == 5 { // idle is the 5th field in the cpu line
idle = val idle += val
} }
} }
return return
@ -73,6 +76,55 @@ func getCPUSample() (idle, total uint64) {
} }
return return
} }
func splitProcStat(content []byte) []string {
nameStart := bytes.IndexByte(content, '(')
nameEnd := bytes.LastIndexByte(content, ')')
restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '
name := content[nameStart+1 : nameEnd]
pid := strings.TrimSpace(string(content[:nameStart]))
fields := make([]string, 3, len(restFields)+3)
fields[1] = string(pid)
fields[2] = string(name)
fields = append(fields, restFields...)
return fields
}
func getCPUSampleByPid(pid int) float64 {
contents, err := ioutil.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
if err != nil {
return 0
}
fields := splitProcStat(contents)
utime, err := strconv.ParseFloat(fields[14], 64)
if err != nil {
return 0
}
stime, err := strconv.ParseFloat(fields[15], 64)
if err != nil {
return 0
}
// There is no such thing as iotime in stat file. As an approximation, we
// will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux
// docs). Note: I am assuming at least Linux 2.6.18
var iotime float64
if len(fields) > 42 {
iotime, err = strconv.ParseFloat(fields[42], 64)
if err != nil {
iotime = 0 // Ancient linux version, most likely
}
} else {
iotime = 0 // e.g. SmartOS containers
}
return utime/float64(clockTicks) + stime/float64(clockTicks) + iotime/float64(clockTicks)
}
func CpuUsageByPid(pid int, sleep time.Duration) float64 {
total1 := getCPUSampleByPid(pid)
time.Sleep(sleep)
total2 := getCPUSampleByPid(pid)
return (total2 - total1) / sleep.Seconds() * 100
}
// CpuUsage 获取CPU使用量 // CpuUsage 获取CPU使用量
func CpuUsage(sleep time.Duration) float64 { func CpuUsage(sleep time.Duration) float64 {

@ -27,23 +27,6 @@ func IsRoot() bool {
return wincmd.Isas() return wincmd.Isas()
} }
// Memory 系统内存信息
func Memory() MemStatus {
var mem MemStatus
ram := new(win32api.MEMORYSTATUSEX)
win32api.GlobalMemoryStatusEx(ram)
mem.All = uint64(ram.UllTotalPhys)
mem.Free = uint64(ram.UllAvailPhys)
mem.Available = uint64(ram.UllAvailPhys)
mem.Used = uint64(mem.All - mem.Free)
mem.SwapAll = uint64(ram.UllTotalPageFile)
mem.SwapFree = uint64(ram.UllAvailPageFile)
mem.SwapUsed = mem.SwapAll - mem.SwapFree
mem.VirtualAll = uint64(mem.VirtualAll)
mem.VirtualAvail = uint64(mem.VirtualAvail)
mem.VirtualUsed = mem.VirtualAll - mem.VirtualUsed
return mem
}
func DiskUsage(path string) (disk DiskStatus) { func DiskUsage(path string) (disk DiskStatus) {
kernel32, err := syscall.LoadLibrary("Kernel32.dll") kernel32, err := syscall.LoadLibrary("Kernel32.dll")

@ -7,6 +7,9 @@ import (
"io" "io"
"os" "os"
"os/exec" "os/exec"
"strings"
"sync"
"sync/atomic"
"syscall" "syscall"
"time" "time"
) )
@ -14,23 +17,22 @@ import (
//StarCmd Is Here //StarCmd Is Here
type StarCmd struct { type StarCmd struct {
CMD *exec.Cmd CMD *exec.Cmd
outfile io.ReadCloser outfile io.ReadCloser
infile io.WriteCloser infile io.WriteCloser
errfile io.ReadCloser errfile io.ReadCloser
running bool running int32
runningChan chan int
//Store AlL of the Standed Outputs //Store AlL of the Standed Outputs
stdout []byte stdout []byte
//Store All of the Standed Errors //Store All of the Standed Errors
errout []byte errout []byte
runerr error runerr error
exitcode int exitcode int
customCtx context.Context
stdoutBuf *bytes.Buffer stdoutBuf *bytes.Buffer
stderrBuf *bytes.Buffer stderrBuf *bytes.Buffer
stdoutpoint int stdoutpoint int
stderrpoint int stderrpoint int
lock sync.Mutex
prewrite []string prewrite []string
prewritetime time.Duration prewritetime time.Duration
stopctxfunc context.CancelFunc stopctxfunc context.CancelFunc
@ -40,11 +42,10 @@ type StarCmd struct {
func Command(command string, args ...string) (*StarCmd, error) { func Command(command string, args ...string) (*StarCmd, error) {
var err error var err error
shell := new(StarCmd) shell := new(StarCmd)
shell.running = false shell.running = 0
shell.prewritetime = time.Millisecond * 200 shell.prewritetime = time.Millisecond * 200
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0)) shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0)) shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
shell.runningChan = make(chan int, 3)
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background()) shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
shell.CMD = cmd shell.CMD = cmd
@ -67,10 +68,9 @@ func Command(command string, args ...string) (*StarCmd, error) {
func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) { func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) {
var err error var err error
shell := new(StarCmd) shell := new(StarCmd)
shell.running = false shell.running = 0
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0)) shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0)) shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
shell.runningChan = make(chan int, 3)
shell.prewritetime = time.Millisecond * 200 shell.prewritetime = time.Millisecond * 200
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background()) shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
cmd := exec.CommandContext(ctx, command, args...) cmd := exec.CommandContext(ctx, command, args...)
@ -93,17 +93,18 @@ func CommandContext(ctx context.Context, command string, args ...string) (*StarC
} }
func (starcli *StarCmd) queryStdout(ctx context.Context) { func (starcli *StarCmd) queryStdout(ctx context.Context) {
for starcli.running && starcli.CMD != nil { for starcli.IsRunning() && starcli.CMD != nil {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
default: default:
break
} }
out := make([]byte, 65535) out := make([]byte, 65535)
n, err := starcli.outfile.Read(out) n, err := starcli.outfile.Read(out)
if n != 0 { if n != 0 {
starcli.lock.Lock()
starcli.stdoutBuf.Write(out[:n]) starcli.stdoutBuf.Write(out[:n])
starcli.lock.Unlock()
for _, v := range out[:n] { for _, v := range out[:n] {
starcli.stdout = append(starcli.stdout, v) starcli.stdout = append(starcli.stdout, v)
} }
@ -112,7 +113,9 @@ func (starcli *StarCmd) queryStdout(ctx context.Context) {
if err == io.EOF { if err == io.EOF {
break break
} else { } else {
starcli.runerr = err if !strings.Contains(err.Error(), "file already closed") {
starcli.runerr = err
}
return return
} }
} }
@ -120,17 +123,18 @@ func (starcli *StarCmd) queryStdout(ctx context.Context) {
} }
func (starcli *StarCmd) queryStderr(ctx context.Context) { func (starcli *StarCmd) queryStderr(ctx context.Context) {
for starcli.running && starcli.CMD != nil { for starcli.IsRunning() && starcli.CMD != nil {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
default: default:
break
} }
out := make([]byte, 65535) out := make([]byte, 65535)
n, err := starcli.errfile.Read(out) n, err := starcli.errfile.Read(out)
if n != 0 { if n != 0 {
starcli.lock.Lock()
starcli.stderrBuf.Write(out[:n]) starcli.stderrBuf.Write(out[:n])
starcli.lock.Unlock()
for _, v := range out[:n] { for _, v := range out[:n] {
starcli.errout = append(starcli.errout, v) starcli.errout = append(starcli.errout, v)
} }
@ -139,7 +143,9 @@ func (starcli *StarCmd) queryStderr(ctx context.Context) {
if err == io.EOF { if err == io.EOF {
break break
} else { } else {
starcli.runerr = err if !strings.Contains(err.Error(), "file already closed") {
starcli.runerr = err
}
return return
} }
} }
@ -147,8 +153,10 @@ func (starcli *StarCmd) queryStderr(ctx context.Context) {
return return
} }
func (starcli *StarCmd) NowLineOutput() (string, error) { func (starcli *StarCmd) NowLineOutput() (string, error) {
starcli.lock.Lock()
buf, _ := starcli.stdoutBuf.ReadBytes('\n') buf, _ := starcli.stdoutBuf.ReadBytes('\n')
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n')) buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
starcli.lock.Unlock()
if len(buferr) != 0 { if len(buferr) != 0 {
return string(buf), errors.New(string(buferr)) return string(buf), errors.New(string(buferr))
} }
@ -156,11 +164,15 @@ func (starcli *StarCmd) NowLineOutput() (string, error) {
} }
func (starcli *StarCmd) NowLineStdOut() string { func (starcli *StarCmd) NowLineStdOut() string {
starcli.lock.Lock()
defer starcli.lock.Unlock()
buf, _ := starcli.stdoutBuf.ReadBytes('\n') buf, _ := starcli.stdoutBuf.ReadBytes('\n')
return string(buf) return string(buf)
} }
func (starcli *StarCmd) NowLineStdErr() error { func (starcli *StarCmd) NowLineStdErr() error {
starcli.lock.Lock()
defer starcli.lock.Unlock()
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n')) buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
if len(buferr) != 0 { if len(buferr) != 0 {
return errors.New(string(buferr)) return errors.New(string(buferr))
@ -170,16 +182,20 @@ func (starcli *StarCmd) NowLineStdErr() error {
func (starcli *StarCmd) NowAllOutput() (string, error) { func (starcli *StarCmd) NowAllOutput() (string, error) {
var outstr string var outstr string
starcli.lock.Lock()
buf := make([]byte, starcli.stdoutBuf.Len()) buf := make([]byte, starcli.stdoutBuf.Len())
n, _ := starcli.stdoutBuf.Read(buf) n, _ := starcli.stdoutBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 { if n != 0 {
outstr = string(buf[:n]) outstr = string(buf[:n])
} }
if starcli.runerr != nil { if starcli.runerr != nil {
return outstr, starcli.runerr return outstr, starcli.runerr
} }
starcli.lock.Lock()
buf = make([]byte, starcli.stderrBuf.Len()) buf = make([]byte, starcli.stderrBuf.Len())
n, _ = starcli.stderrBuf.Read(buf) n, _ = starcli.stderrBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 { if n != 0 {
return outstr, errors.New(string(buf[:n])) return outstr, errors.New(string(buf[:n]))
} }
@ -188,8 +204,10 @@ func (starcli *StarCmd) NowAllOutput() (string, error) {
func (starcli *StarCmd) NowStdOut() string { func (starcli *StarCmd) NowStdOut() string {
var outstr string var outstr string
starcli.lock.Lock()
buf := make([]byte, starcli.stdoutBuf.Len()) buf := make([]byte, starcli.stdoutBuf.Len())
n, _ := starcli.stdoutBuf.Read(buf) n, _ := starcli.stdoutBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 { if n != 0 {
outstr = string(buf[:n]) outstr = string(buf[:n])
} }
@ -197,9 +215,10 @@ func (starcli *StarCmd) NowStdOut() string {
} }
func (starcli *StarCmd) NowStdErr() error { func (starcli *StarCmd) NowStdErr() error {
starcli.lock.Lock()
buf := make([]byte, starcli.stderrBuf.Len()) buf := make([]byte, starcli.stderrBuf.Len())
n, _ := starcli.stderrBuf.Read(buf) n, _ := starcli.stderrBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 { if n != 0 {
return errors.New(string(buf[:n])) return errors.New(string(buf[:n]))
} }
@ -226,20 +245,38 @@ func (starcli *StarCmd) AllStdErr() error {
return err return err
} }
func (starcli *StarCmd) setRunning(alive bool) {
if alive {
val := atomic.LoadInt32(&starcli.running)
if val == 0 {
atomic.AddInt32(&starcli.running, 1)
} else {
atomic.AddInt32(&starcli.running, 1-val)
}
return
}
val := atomic.LoadInt32(&starcli.running)
if val == 1 {
atomic.AddInt32(&starcli.running, -1)
} else {
atomic.AddInt32(&starcli.running, -val)
}
}
func (starcli *StarCmd) Start() error { func (starcli *StarCmd) Start() error {
if err := starcli.CMD.Start(); err != nil { if err := starcli.CMD.Start(); err != nil {
return err return err
} }
starcli.running = true starcli.setRunning(true)
go func() { go func() {
err := starcli.CMD.Wait() err := starcli.CMD.Wait()
if err != nil { if err != nil {
starcli.runerr = err starcli.runerr = err
} }
starcli.stopctxfunc() starcli.stopctxfunc()
starcli.running = false starcli.setRunning(false)
starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() if starcli.CMD.ProcessState != nil {
starcli.runningChan <- 1 starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
}
}() }()
go starcli.queryStdout(starcli.stopctx) go starcli.queryStdout(starcli.stopctx)
go starcli.queryStderr(starcli.stopctx) go starcli.queryStderr(starcli.stopctx)
@ -261,11 +298,11 @@ func (starcli *StarCmd) Start() error {
} }
func (starcli *StarCmd) IsRunning() bool { func (starcli *StarCmd) IsRunning() bool {
return starcli.running return 0 != atomic.LoadInt32(&starcli.running)
} }
func (starcli *StarCmd) Stoped() <-chan int { func (starcli *StarCmd) Stoped() <-chan struct{} {
return starcli.runningChan return starcli.stopctx.Done()
} }
func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) { func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) {
@ -292,9 +329,13 @@ func (starcli *StarCmd) ExitCode() int {
return starcli.exitcode return starcli.exitcode
} }
func (starcli *StarCmd) Kill() { func (starcli *StarCmd) Kill() error {
starcli.CMD.Process.Kill() err := starcli.CMD.Process.Kill()
starcli.running = false if err != nil {
return err
}
starcli.setRunning(false)
return nil
} }
func (starcli *StarCmd) GetPid() int { func (starcli *StarCmd) GetPid() int {

@ -30,11 +30,43 @@ func FindProcessByName(name string) (datas []Process, err error) {
func FindProcess(compare func(Process) bool) (datas []Process, err error) { func FindProcess(compare func(Process) bool) (datas []Process, err error) {
var name, main string var name, main string
var mainb []byte var mainb []byte
paths, errs := ioutil.ReadDir("/proc") var netErr error
if errs != nil { var netInfo []NetConn
err = errs paths, err := ioutil.ReadDir("/proc")
if err != nil {
return return
} }
netInfo, netErr = NetConnections(false, "")
appendNetInfo := func(p *Process) {
if netErr != nil {
p.netErr = netErr
return
}
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
p.netErr = err
return
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
if err != nil {
p.netErr = err
return
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
sid := socket[start+1 : len(socket)-1]
for _, v := range netInfo {
if v.Inode == sid {
v.Pid = p.Pid
v.Process = p
p.netConn = append(p.netConn, v)
}
}
}
}
for _, v := range paths { for _, v := range paths {
if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") { if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") {
name, err = readAsString("/proc/" + v.Name() + "/comm") name, err = readAsString("/proc/" + v.Name() + "/comm")
@ -49,68 +81,80 @@ func FindProcess(compare func(Process) bool) (datas []Process, err error) {
tmp.Name = strings.TrimSpace(name) tmp.Name = strings.TrimSpace(name)
main, err = readAsString("/proc/" + v.Name() + "/status") main, err = readAsString("/proc/" + v.Name() + "/status")
if err != nil { if err != nil {
tmp.Err = err
if compare(tmp) { if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp) datas = append(datas, tmp)
continue continue
} }
} else {
data := splitBy(main, ":")
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
uids := splitBySpace(data["Uid"])
gids := splitBySpace(data["Gid"])
tmp.RUID, _ = strconv.Atoi(uids[0])
tmp.EUID, _ = strconv.Atoi(uids[1])
tmp.RGID, _ = strconv.Atoi(gids[0])
tmp.EGID, _ = strconv.Atoi(gids[1])
tmp.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
tmp.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
tmp.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
tmp.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
tmp.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
tmp.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
tmp.VmLck *= 1024
tmp.VmData *= 1024
tmp.VmPeak *= 1024
tmp.VmSize *= 1024
tmp.VmHWM *= 1024
tmp.VmRSS *= 1024
} }
data := splitBy(main, ":")
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
uids := splitBySpace(data["Uid"])
gids := splitBySpace(data["Gid"])
tmp.RUID, _ = strconv.Atoi(uids[0])
tmp.EUID, _ = strconv.Atoi(uids[1])
tmp.RGID, _ = strconv.Atoi(gids[0])
tmp.EGID, _ = strconv.Atoi(gids[1])
tmp.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
tmp.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
tmp.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
tmp.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
tmp.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
tmp.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
tmp.VmLck *= 1024
tmp.VmData *= 1024
tmp.VmPeak *= 1024
tmp.VmSize *= 1024
tmp.VmHWM *= 1024
tmp.VmRSS *= 1024
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline") mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline")
if err != nil { if err != nil {
tmp.Err = err
if compare(tmp) { if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp) datas = append(datas, tmp)
continue continue
} }
} else {
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
tmp.Args = append(tmp.Args, string(v))
}
} }
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
tmp.Args = append(tmp.Args, string(v))
}
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/environ") mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/environ")
if err != nil { if err != nil {
tmp.Err = err
if compare(tmp) { if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp) datas = append(datas, tmp)
continue continue
} }
} } else {
args = bytes.Split(mainb, []byte{0}) args := bytes.Split(mainb, []byte{0})
for _, v := range args { for _, v := range args {
tmp.Env = append(tmp.Env, string(v)) tmp.Env = append(tmp.Env, string(v))
}
} }
main, err = readAsString("/proc/" + v.Name() + "/stat") main, err = readAsString("/proc/" + v.Name() + "/stat")
if err != nil { if err != nil {
tmp.Err = err
if compare(tmp) { if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp) datas = append(datas, tmp)
continue continue
} }
} else {
times := splitBySpace(main)
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
} }
times := splitBySpace(main)
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
if compare(tmp) { if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp) datas = append(datas, tmp)
} }
} }
@ -126,6 +170,38 @@ func FindProcessByPid(pid int64) (datas Process, err error) {
err = errors.New("Not Found") err = errors.New("Not Found")
return return
} }
netInfo, netErr := NetConnections(false, "")
appendNetInfo := func(p *Process) {
if netErr != nil {
p.netErr = netErr
return
}
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
p.netErr = err
return
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
if err != nil {
p.netErr = err
return
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
sid := socket[start+1 : len(socket)-1]
for _, v := range netInfo {
if v.Inode == sid {
v.Pid = p.Pid
v.Process = p
p.netConn = append(p.netConn, v)
}
}
}
}
name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm") name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm")
if err != nil { if err != nil {
return return
@ -157,22 +233,27 @@ func FindProcessByPid(pid int64) (datas Process, err error) {
datas.VmSize *= 1024 datas.VmSize *= 1024
datas.VmHWM *= 1024 datas.VmHWM *= 1024
datas.VmRSS *= 1024 datas.VmRSS *= 1024
appendNetInfo(&datas)
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline") mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline")
if err != nil { if err != nil {
return datas.Err = err
} err = nil
args := bytes.Split(mainb, []byte{0}) } else {
for _, v := range args { args := bytes.Split(mainb, []byte{0})
datas.Args = append(datas.Args, string(v)) for _, v := range args {
datas.Args = append(datas.Args, string(v))
}
} }
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/environ") mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/environ")
if err != nil { if err != nil {
return datas.Err = err
} err = nil
args = bytes.Split(mainb, []byte{0}) } else {
for _, v := range args { args := bytes.Split(mainb, []byte{0})
datas.Env = append(datas.Env, string(v)) for _, v := range args {
datas.Env = append(datas.Env, string(v))
}
} }
datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe") datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe")
@ -202,25 +283,52 @@ func Daemon(path string, args ...string) (int, error) {
return pid, err return pid, err
} }
func (starcli *StarCmd) SetRunUser(uid, gid uint32) { func DaemonWithUser(uid, gid uint32, groups []uint32, path string, args ...string) (int, error) {
cmd := exec.Command(path, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uid,
Gid: gid,
Groups: groups,
},
Setsid: true,
}
if err := cmd.Start(); err != nil {
return -1, err
}
pid := cmd.Process.Pid
err := cmd.Process.Release()
return pid, err
}
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{ starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{ Credential: &syscall.Credential{
Uid: uid, Uid: uid,
Gid: gid, Gid: gid,
Groups: groups,
}, },
Setsid: true, Setsid: true,
} }
} }
func (starcli *StarCmd) Release() error { func (starcli *StarCmd) Release() error {
if err := starcli.CMD.Start(); err != nil { if starcli.CMD.SysProcAttr == nil {
return err starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
} else {
if !starcli.CMD.SysProcAttr.Setsid {
starcli.CMD.SysProcAttr.Setsid = true
}
} }
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{ if !starcli.IsRunning() {
Setsid: true, if err := starcli.CMD.Start(); err != nil {
return err
}
} }
starcli.CMD.Process.Release() time.Sleep(time.Millisecond * 10)
return nil return starcli.CMD.Process.Release()
} }
func (starcli *StarCmd) SetKeepCaps() error { func (starcli *StarCmd) SetKeepCaps() error {
@ -230,3 +338,11 @@ func (starcli *StarCmd) SetKeepCaps() error {
} }
return nil return nil
} }
func SetKeepCaps() error {
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
if 0 != err {
return err
}
return nil
}

@ -59,6 +59,14 @@ func Daemon(path string, args ...string) (int, error) {
return pid, nil return pid, nil
} }
func (starcli *StarCmd) SetRunUser(uid, gid uint32) { func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
} }
func (starcli *StarCmd) Release() error {
if err := starcli.CMD.Start(); err != nil {
return err
}
starcli.CMD.Process.Release()
return nil
}

@ -0,0 +1,261 @@
package sysconf
import (
"bytes"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)
type CSV struct {
header []string
text [][]string
}
type CSVRow struct {
header []string
data []string
}
type CSVValue struct {
key string
value string
}
func ParseCSV(data []byte, hasHeader bool) (csv CSV, err error) {
strData := strings.Split(string(bytes.TrimSpace(data)), "\n")
if len(strData) < 1 {
err = fmt.Errorf("cannot parse data,invalid data format")
}
var header []string
var text [][]string
if hasHeader {
header = csvAnalyse(strData[0])
strData = strData[1:]
} else {
num := len(csvAnalyse(strData[0]))
for i := 0; i < num; i++ {
header = append(header, strconv.Itoa(i))
}
}
for k, v := range strData {
tmpData := csvAnalyse(v)
if len(tmpData) != len(header) {
err = fmt.Errorf("cannot parse data line %d,got %d values but need %d", k, len(tmpData), len(header))
return
}
text = append(text, tmpData)
}
csv.header = header
csv.text = text
return
}
func (csv *CSV) Header() []string {
return csv.header
}
func (csv *CSV) Data() [][]string {
return csv.text
}
func (csv *CSV) Row(row int) *CSVRow {
if row >= len(csv.Data()) {
return nil
}
return &CSVRow{
header: csv.Header(),
data: csv.Data()[row],
}
}
func (csv *CSVRow) Get(key string) *CSVValue {
for k, v := range csv.header {
if v == key {
return &CSVValue{
key: key,
value: csv.data[k],
}
}
}
return nil
}
func (csv *CSVRow) Col(key int) *CSVValue {
if key >= len(csv.header) {
return nil
}
return &CSVValue{
key: csv.header[key],
value: csv.data[key],
}
}
func (csv *CSVRow) Header() []string {
return csv.header
}
func (csv *CSV) MapData() []map[string]string {
var result []map[string]string
for _, v := range csv.text {
tmp := make(map[string]string)
for k, v2 := range csv.header {
tmp[v2] = v[k]
}
result = append(result, tmp)
}
return result
}
func CsvAnalyse(data string) []string {
return csvAnalyse(data)
}
func csvAnalyse(data string) []string {
var segStart bool = false
var segReady bool = false
var segSign string = ""
var dotReady bool = false
data = strings.TrimSpace(data)
var result []string
var seg string
for k, v := range []rune(data) {
if k == 0 && v != []rune(`"`)[0] {
dotReady = true
}
if v != []rune(`,`)[0] && dotReady {
segSign = `,`
segStart = true
dotReady = false
if v == []rune(`"`)[0] {
segSign = `"`
continue
}
}
if dotReady && v == []rune(`,`)[0] {
//dotReady = false
result = append(result, "")
continue
}
if v == []rune(`"`)[0] && segStart {
if !segReady {
segReady = true
continue
}
seg += `"`
segReady = false
continue
}
if segReady && segSign == `"` && segStart {
segReady = false
segStart = false
result = append(result, seg)
segSign = ``
seg = ""
}
if v == []rune(`"`)[0] && !segStart {
segStart = true
segReady = false
segSign = `"`
continue
}
if v == []rune(`,`)[0] && !segStart {
dotReady = true
}
if v == []rune(`,`)[0] && segStart && segSign == "," {
segStart = false
result = append(result, seg)
dotReady = true
segSign = ``
seg = ""
}
if segStart {
seg = string(append([]rune(seg), v))
}
}
if len(data) != 0 && len(result) == 0 && seg == "" {
result = append(result, data)
} else {
result = append(result, seg)
}
return result
}
func MarshalCSV(header []string, ins interface{}) ([]byte, error) {
var result [][]string
t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins)
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, errors.New("not a Slice or Array")
}
if t.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()
}
for i := 0; i < v.Len(); i++ {
subT := reflect.TypeOf(v.Index(i).Interface())
subV := reflect.ValueOf(v.Index(i).Interface())
if subV.Kind() == reflect.Slice || subV.Kind() == reflect.Array {
if subT.Kind() == reflect.Ptr {
subV = subV.Elem()
}
var tmp []string
for j := 0; j < subV.Len(); j++ {
tmp = append(tmp, fmt.Sprint(reflect.ValueOf(subV.Index(j))))
}
result = append(result, tmp)
}
if subV.Kind() == reflect.Struct {
var tmp []string
if subT.Kind() == reflect.Ptr {
subV = subV.Elem()
}
for i := 0; i < subV.NumField(); i++ {
tmp = append(tmp, fmt.Sprint(subV.Field(i)))
}
result = append(result, tmp)
}
}
return buildCSV(header,result)
}
func buildCSV(header []string, data [][]string) ([]byte, error) {
var result []string
var length int
build := func(slc []string) string {
for k, v := range slc {
if strings.Index(v, `"`) >= 0 {
v = strings.ReplaceAll(v, `"`, `""`)
}
if strings.Index(v,"\n")>=0 {
v=strings.ReplaceAll(v,"\n",`\n`)
}
if strings.Index(v,"\r")>=0 {
v=strings.ReplaceAll(v,"\r",`\r`)
}
v = `"` + v + `"`
slc[k] = v
}
return strings.Join(slc, ",")
}
if len(header) != 0 {
result = append(result, build(header))
length = len(header)
} else {
length = len(data[0])
}
for k, v := range data {
if len(v) != length {
return nil, fmt.Errorf("line %d got length %d ,but need %d", k, len(v), length)
}
result = append(result, build(v))
}
return []byte(strings.Join(result, "\n")), nil
}

@ -0,0 +1,38 @@
package sysconf
import (
"fmt"
"testing"
)
func Test_csv(t *testing.T) {
//var test Sqlplus
var text=`
,,,
,"我,不""知道",boy,23
"里斯","哈哈",girl,23
`
fmt.Println(csvAnalyse(`请求权,lkjdshck,dsvdsv,"sdvkjsdv,",=dsvdsv,"=,dsvsdv"`))
a,b:=ParseCSV([]byte(text),true)
fmt.Println(b)
fmt.Println(a.Row(0).Col(3).MustInt())
}
type csvtest struct {
A string
B int
}
func Test_Masharl(t *testing.T) {
//var test Sqlplus
/*
var a []csvtest = []csvtest{
{"lala",1},
{"haha",34},
}
*/
var a [][]string
a=append(a,[]string{"a","b","c"})
a=append(a,[]string{"1",`s"s"d`,"3"})
b,_:=MarshalCSV([]string{},a)
fmt.Println(string(b))
}

@ -0,0 +1,120 @@
package sysconf
import "strconv"
func (csv *CSVValue)Key()string {
return csv.key
}
func (csv *CSVValue)Int()(int,error) {
tmp,err:=strconv.Atoi(csv.value)
return tmp,err
}
func (csv *CSVValue)MustInt()int {
tmp,err:=csv.Int()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Int64()(int64,error) {
tmp,err:=strconv.ParseInt(csv.value,10,64)
return tmp,err
}
func (csv *CSVValue)MustInt64()int64 {
tmp,err:=csv.Int64()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Int32()(int32,error) {
tmp,err:=strconv.ParseInt(csv.value,10,32)
return int32(tmp),err
}
func (csv *CSVValue)MustInt32()int32 {
tmp,err:=csv.Int32()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Uint64()(uint64,error) {
tmp,err:=strconv.ParseUint(csv.value,10,64)
return tmp,err
}
func (csv *CSVValue)MustUint64()uint64 {
tmp,err:=csv.Uint64()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Uint32()(uint32,error) {
tmp,err:=strconv.ParseUint(csv.value,10,32)
return uint32(tmp),err
}
func (csv *CSVValue)MustUint32()uint32 {
tmp,err:=csv.Uint32()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)String()string {
return csv.value
}
func (csv *CSVValue)Byte()[]byte {
return []byte(csv.value)
}
func (csv *CSVValue)Bool()(bool,error) {
tmp,err:=strconv.ParseBool(csv.value)
return tmp,err
}
func (csv *CSVValue)MustBool()bool {
tmp,err:=csv.Bool()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Float64()(float64,error) {
tmp,err:=strconv.ParseFloat(csv.value,64)
return tmp,err
}
func (csv *CSVValue)MustFloat64()float64 {
tmp,err:=csv.Float64()
if err!=nil {
panic(err)
}
return tmp
}
func (csv *CSVValue)Float32()(float32,error) {
tmp,err:=strconv.ParseFloat(csv.value,32)
return float32(tmp),err
}
func (csv *CSVValue)MustFloat32()float32 {
tmp,err:=csv.Float32()
if err!=nil {
panic(err)
}
return tmp
}

@ -9,8 +9,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"b612.me/staros"
) )
type SysConf struct { type SysConf struct {
@ -47,6 +45,18 @@ type SysNode struct {
lock sync.RWMutex lock sync.RWMutex
} }
func NewIni() *SysConf {
ini := NewSysConf("=")
ini.CommentCR = true
ini.CommentFlag = []string{"#", ";"}
ini.HaveSegMent = true
ini.SegStart = "["
ini.SegEnd = "]"
ini.SpaceStr = " "
ini.EscapeFlag = "\\"
return ini
}
func NewSysConf(EqualFlag string) *SysConf { func NewSysConf(EqualFlag string) *SysConf {
syscnf := new(SysConf) syscnf := new(SysConf)
syscnf.EqualFlag = EqualFlag syscnf.EqualFlag = EqualFlag
@ -64,15 +74,11 @@ func NewLinuxConf(EqualFlag string) *SysConf {
} }
func (syscfg *SysConf) ParseFromFile(filepath string) error { func (syscfg *SysConf) ParseFromFile(filepath string) error {
if !staros.Exists(filepath) {
return errors.New(filepath + " 不存在")
}
data, err := ioutil.ReadFile(filepath) data, err := ioutil.ReadFile(filepath)
if err != nil { if err != nil {
return err return err
} }
syscfg.Parse(data) return syscfg.Parse(data)
return nil
} }
// Parse 生成INI文件结构 // Parse 生成INI文件结构
@ -470,7 +476,7 @@ func SliceIn(slice interface{}, data interface{}) bool {
// Unmarshal 输出结果到结构体中 // Unmarshal 输出结果到结构体中
func (cfg *SysConf) Unmarshal(ins interface{}) error { func (cfg *SysConf) Unmarshal(ins interface{}) error {
var structSet func(t reflect.Type, v reflect.Value) error var structSet func(t reflect.Type, v reflect.Value, oriSeg string) error
t := reflect.TypeOf(ins) t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins).Elem() v := reflect.ValueOf(ins).Elem()
if v.Kind() != reflect.Struct { if v.Kind() != reflect.Struct {
@ -480,7 +486,7 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
return errors.New("Cannot Write!") return errors.New("Cannot Write!")
} }
t = t.Elem() t = t.Elem()
structSet = func(t reflect.Type, v reflect.Value) error { structSet = func(t reflect.Type, v reflect.Value, oriSeg string) error {
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
tp := t.Field(i) tp := t.Field(i)
vl := v.Field(i) vl := v.Field(i)
@ -488,11 +494,17 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
continue continue
} }
if vl.Type().Kind() == reflect.Struct { if vl.Type().Kind() == reflect.Struct {
structSet(vl.Type(), vl) structSet(vl.Type(), vl, tp.Tag.Get("seg"))
continue continue
} }
seg := tp.Tag.Get("seg") seg := tp.Tag.Get("seg")
key := tp.Tag.Get("key") key := tp.Tag.Get("key")
if key != "" && seg == "" && cfg.HaveSegMent {
seg = "unnamed"
}
if oriSeg != "" {
seg = oriSeg
}
if seg == "" || key == "" { if seg == "" || key == "" {
continue continue
} }
@ -520,12 +532,12 @@ func (cfg *SysConf) Unmarshal(ins interface{}) error {
} }
return nil return nil
} }
return structSet(t, v) return structSet(t, v, "")
} }
// Marshal 输出结果到结构体中 // Marshal 输出结果到结构体中
func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) { func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
var structSet func(t reflect.Type, v reflect.Value) var structSet func(t reflect.Type, v reflect.Value, oriSeg string)
t := reflect.TypeOf(ins) t := reflect.TypeOf(ins)
v := reflect.ValueOf(ins) v := reflect.ValueOf(ins)
if v.Kind() != reflect.Struct { if v.Kind() != reflect.Struct {
@ -535,18 +547,21 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
t = t.Elem() t = t.Elem()
v = v.Elem() v = v.Elem()
} }
structSet = func(t reflect.Type, v reflect.Value) { structSet = func(t reflect.Type, v reflect.Value, oriSeg string) {
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
var seg, key, comment string = "", "", "" var seg, key, comment string = "", "", ""
tp := t.Field(i) tp := t.Field(i)
vl := v.Field(i) vl := v.Field(i)
if vl.Type().Kind() == reflect.Struct { if vl.Type().Kind() == reflect.Struct {
structSet(vl.Type(), vl) structSet(vl.Type(), vl, tp.Tag.Get("seg"))
continue continue
} }
seg = tp.Tag.Get("seg") seg = tp.Tag.Get("seg")
key = tp.Tag.Get("key") key = tp.Tag.Get("key")
comment = tp.Tag.Get("comment") comment = tp.Tag.Get("comment")
if oriSeg != "" {
seg = oriSeg
}
if seg == "" || key == "" { if seg == "" || key == "" {
continue continue
} }
@ -557,7 +572,7 @@ func (cfg *SysConf) Marshal(ins interface{}) ([]byte, error) {
} }
} }
structSet(t, v) structSet(t, v, "")
return cfg.Build(), nil return cfg.Build(), nil
} }

@ -33,6 +33,35 @@ func Test_Parse(t *testing.T) {
fmt.Println(cfg.Parse([]byte(data))) fmt.Println(cfg.Parse([]byte(data)))
cfg.Reverse() cfg.Reverse()
cfg.Data[0].Delete(`pp.com`) cfg.Data[0].Delete(`pp.com`)
//fmt.Println(cfg.Data[0].Comment) //fmt.Println(cfg.Data[0].comment)
fmt.Println(string(cfg.Build())) fmt.Println(string(cfg.Build()))
} }
type slicetest struct {
A string `seg:"s" key:"a"`
B string `seg:"a" key:"b"`
}
type testme struct {
Love slicetest `seg:"love"`
Star slicetest `seg:"star"`
}
func Test_Marshal(t *testing.T) {
var info string = `
[love]
a=abc
b=123
[star]
a=456
b=789
`
var tmp testme
ini := NewIni()
ini.Parse([]byte(info))
ini.Unmarshal(&tmp)
fmt.Printf("%+v\n", tmp)
b, _ := ini.Marshal(tmp)
fmt.Println(string(b))
}

@ -2,7 +2,9 @@ package staros
import ( import (
"bytes" "bytes"
"errors"
"io/ioutil" "io/ioutil"
"strconv"
"strings" "strings"
) )
@ -42,3 +44,116 @@ func readAsString(path string) (string, error) {
} }
return string(data), nil return string(data), nil
} }
func remainOne(data, old, new string) string {
data = strings.TrimSpace(data)
if !strings.Contains(data, old) {
return data
}
data = strings.ReplaceAll(data, old, new)
return remainOne(data, old, new)
}
func parseHexIpPort(str string) (string, int, error) {
str = strings.TrimSpace(str)
if len(str) != 13 && len(str) != 37 {
return "", 0, errors.New("Not a valid ip:port addr:" + str)
}
ipPort := strings.Split(str, ":")
if len(ipPort) != 2 {
return "", 0, errors.New("Not a valid ip:port addr:" + str)
}
if len(ipPort[0]) == 8 {
ip, err := parseHexIPv4(ipPort[0])
if err != nil {
return "", 0, err
}
port, err := parseHexPort(ipPort[1])
return ip, port, err
}
if len(ipPort[0]) == 32 {
ip, err := parseHexIPv6(ipPort[0])
if err != nil {
return "", 0, err
}
port, err := parseHexPort(ipPort[1])
return ip, port, err
}
return "", 0, errors.New("Invalid ip address:" + str)
}
func parseHexPort(str string) (int, error) {
tmpUint32, err := strconv.ParseUint(str, 16, 32)
return int(tmpUint32), err
}
func parseHexIPv4(str string) (string, error) {
var result string
if len(str) != 8 {
return "", errors.New("Not a vaild ipv4:" + str)
}
tmpUint64, err := strconv.ParseUint(str, 16, 32)
if err != nil {
return "", err
}
numicIp := uint32(tmpUint64)
for i := 0; i < 4; i++ {
result += strconv.FormatUint(uint64(uint8(numicIp>>(8*uint8(i)))), 10) + "."
}
return result[0 : len(result)-1], nil
}
func parseHexIPv6(str string) (string, error) {
var result string
if len(str) != 32 {
return "", errors.New("Not a vaild ipv6:" + str)
}
for i := 0; i < 4; i++ {
part := str[i*8 : (i+1)*8]
tmpUint64, err := strconv.ParseUint(part, 16, 32)
if err != nil {
return "", err
}
tmpUint32 := uint32(tmpUint64)
//07C2022A
for i := 0; i < 4; i++ {
tmp := strconv.FormatUint(uint64(uint8(tmpUint32>>uint8(8*i))), 16)
if len(tmp) == 1 {
tmp = "0" + tmp
}
result += tmp
if (i+1)%2 == 0 {
result += ":"
}
}
}
ipv6 := result[0 : len(result)-1]
ipv6List := strings.Split(ipv6, ":")
prepareZero := false
alreadyZero := false
for k, v := range ipv6List {
if v == "0000" && !alreadyZero {
ipv6List[k] = ""
prepareZero = true
continue
}
if v != "0000" && prepareZero {
alreadyZero = true
}
var nonZero = 0
for i := 0; i < 4; i++ {
sig := v[i : i+1]
if sig != "0" {
nonZero = i
break
}
}
ipv6List[k] = v[nonZero:4]
}
ipv6 = strings.TrimSuffix(remainOne(strings.Join(ipv6List, ":"), ":::", "::"), "::")
if ipv6 == "" {
ipv6 = "::0"
}
return ipv6, nil
}

@ -11,6 +11,22 @@ const (
TB = GB << 10 TB = GB << 10
PB = TB << 10 PB = TB << 10
) )
const (
TCP_UNKNOWN = iota
TCP_ESTABLISHED
TCP_SYN_SENT
TCP_SYN_RECV
TCP_FIN_WAIT1
TCP_FIN_WAIT2
TCP_TIME_WAIT
TCP_CLOSE
TCP_CLOSE_WAIT
TCP_LAST_ACL
TCP_LISTEN
TCP_CLOSING
)
var TCP_STATE = []string{"TCP_UNKNOWN", "TCP_ESTABLISHED", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_FIN_WAIT1", "TCP_FIN_WAIT2", "TCP_TIME_WAIT", "TCP_CLOSE", "TCP_CLOSE_WAIT", "TCP_LAST_ACL", "TCP_LISTEN", "TCP_CLOSING"}
type NetAdapter struct { type NetAdapter struct {
Name string Name string
@ -19,9 +35,11 @@ type NetAdapter struct {
} }
type NetSpeed struct { type NetSpeed struct {
Name string Name string
RecvBytes float64 RecvSpeeds float64
SendBytes float64 SendSpeeds float64
RecvBytes uint64
SendBytes uint64
} }
// Process 定义一个进程的信息 // Process 定义一个进程的信息
@ -46,6 +64,13 @@ type Process struct {
VmHWM int64 VmHWM int64
VmRSS int64 VmRSS int64
VmData int64 VmData int64
netConn []NetConn
netErr error
Err error
}
func (p Process) GetNetConns() ([]NetConn, error) {
return p.netConn, p.netErr
} }
type MemStatus struct { type MemStatus struct {
@ -70,3 +95,22 @@ type DiskStatus struct {
Free uint64 Free uint64
Available uint64 Available uint64
} }
type NetConn struct {
LocalAddr string
LocalPort int
Typed string
RemoteAddr string
RemotePort int
Socket string
Inode string
Status string
TX_Queue int64
RX_Queue int64
TimerActive string
TimerJiffies int64
RtoTimer int64
Pid int64
Uid int64
Process *Process
}

Loading…
Cancel
Save