github.com/iDigitalFlame/xmt@v0.5.4/device/y_nix_util.go (about) 1 //go:build !windows && !js 2 // +build !windows,!js 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package device 21 22 import ( 23 "io" 24 "os" 25 "strconv" 26 "time" 27 "unsafe" 28 ) 29 30 const userSize = 384 31 32 type userEntry struct { 33 Type uint16 34 PID uint32 35 Line [32]byte 36 ID [4]byte 37 User [32]byte 38 Host [256]byte 39 _ uint32 40 Session uint32 41 TimeSec uint32 42 TimeMicro uint32 43 Address [16]byte 44 _ [20]byte 45 } 46 type stringHeader struct { 47 Data uintptr 48 Len int 49 } 50 51 // SetProcessName will attempt to override the process name on *nix systems 52 // by overwriting the argv block. On Windows, this just overrides the command 53 // line arguments. 54 // 55 // Linux support only allows for suppling a command line shorter the current 56 // command line. 57 // 58 // Linux found here: https://stackoverflow.com/questions/14926020/setting-process-name-as-seen-by-ps-in-go 59 // 60 // Always returns an EINVAL on WSAM/JS. 61 func SetProcessName(s string) error { 62 var ( 63 v = (*stringHeader)(unsafe.Pointer(&os.Args[0])) 64 d = (*[1 << 30]byte)(unsafe.Pointer(v.Data))[:v.Len] 65 n = copy(d, s) 66 ) 67 if n < len(d) { 68 d[n] = 0 69 } 70 return nil 71 } 72 func bytesToString(b []byte) string { 73 i := 0 74 for ; i < len(b); i++ { 75 if b[i] == 0 { 76 break 77 } 78 } 79 return string(b[:i]) 80 } 81 func readWhoEntries(b []byte) []Login { 82 if len(b) < userSize { 83 return nil 84 } 85 o := make([]Login, 0, len(b)/userSize) 86 for i := 0; i < cap(o); i++ { 87 if userSize*i >= len(b) || userSize*(i+1) > len(b) { 88 break 89 } 90 p := *(*userEntry)(unsafe.Pointer(&b[userSize*i])) 91 if p.Type != 7 { 92 continue 93 } 94 v := Login{ 95 ID: p.PID, 96 User: bytesToString(p.User[:]), 97 Host: bytesToString(p.Line[:]), 98 Login: time.Unix(int64(p.TimeSec), int64(p.TimeMicro)), 99 } 100 v.From.SetBytes(p.Address) 101 o = append(o, v) 102 } 103 return o 104 } 105 func parseLine(e string, f *os.File, w io.Writer) error { 106 var d, s int 107 for ; d < len(e) && e[d] != '-'; d++ { 108 } 109 for s = d + 1; s < len(e) && e[s] != ' '; s++ { 110 } 111 if d >= len(e) || s-d < 4 { 112 return nil 113 } 114 if len(e) < s+21 || e[s+1] != 'r' { 115 return nil 116 } 117 x := s + 6 118 for ; x < len(e) && e[x] != ' '; x++ { 119 } 120 for x++; x < len(e) && e[x] != ' '; x++ { 121 } 122 if e[x+1] == '0' && (e[x+2] == ' ' || e[x+2] == 9 || e[x+2] == '\t') { 123 return nil 124 } 125 v, err := strconv.ParseUint(e[0:d], 16, 64) 126 if err != nil { 127 return err 128 } 129 g, err := strconv.ParseUint(e[d+1:s], 16, 64) 130 if err != nil { 131 return err 132 } 133 var b [4096]byte 134 for i, k, q := v, uint64(0), 0; i < g; { 135 if k = g - i; k > 4096 { 136 k = 4096 137 } 138 if q, err = f.ReadAt(b[:k], int64(i)); err != nil && err != io.EOF { 139 break 140 } 141 if _, err = w.Write(b[:q]); err != nil { 142 break 143 } 144 if i += uint64(q); q == 0 || i >= g { 145 break 146 } 147 } 148 return err 149 }