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  }