github.com/iDigitalFlame/xmt@v0.5.4/device/os.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  // Package device contains many function that provide access to Operating System
    18  // functions and resources. Many of these are OS agnostic and might not work
    19  // as intended on some systems.
    20  package device
    21  
    22  import (
    23  	"os"
    24  	"sync"
    25  	"syscall"
    26  	"time"
    27  
    28  	"github.com/iDigitalFlame/xmt/data"
    29  	"github.com/iDigitalFlame/xmt/device/arch"
    30  	"github.com/iDigitalFlame/xmt/util"
    31  )
    32  
    33  // Arch represents the current device Architecture type.
    34  const Arch = arch.Current
    35  
    36  const (
    37  	// Windows represents the Windows family of Operating Systems.
    38  	Windows OSType = 0x0
    39  	// Linux represents the Linux family of Operating Systems
    40  	Linux OSType = 0x1
    41  	// Unix represents the Unix/BSD family of Operating Systems
    42  	Unix OSType = 0x2
    43  	// Mac represents the macOS family of Operating Systems
    44  	Mac OSType = 0x3
    45  	// IOS represents the iOS family of Operating Systems
    46  	// Technically is Mac, but deserves its own type for any special actions.
    47  	IOS OSType = 0x4
    48  	// Android represents the Android family of Operating Systems
    49  	// Technically is Linux, but deserves its own type for any special actions.
    50  	Android OSType = 0x5
    51  	// Plan9 represents the Plan9 family of Operating Systems
    52  	Plan9 OSType = 0x6
    53  	// Unsupported represents a device type that does not have direct support
    54  	// any may not work properly.
    55  	Unsupported OSType = 0xF
    56  )
    57  
    58  var builders = sync.Pool{
    59  	New: func() interface{} {
    60  		return new(util.Builder)
    61  	},
    62  }
    63  
    64  // OSType is a numerical representation of the device Operating System type.
    65  type OSType uint8
    66  
    67  // Login is a struct that represents a current user Session on the device.
    68  type Login struct {
    69  	_         [0]func()
    70  	Login     time.Time
    71  	LastInput time.Time
    72  	User      string
    73  	Host      string
    74  	From      Address
    75  	ID        uint32
    76  	Status    uint8
    77  }
    78  
    79  func init() {
    80  	t := os.TempDir()
    81  	syscall.Setenv("tmp", t)
    82  	syscall.Setenv("temp", t)
    83  }
    84  
    85  // Expand attempts to determine environment variables from the current session
    86  // and translate them from the supplied string.
    87  //
    88  // This function supports both Windows (%var%) and *nix ($var or ${var})
    89  // variable substitutions.
    90  func Expand(s string) string {
    91  	if len(s) == 0 {
    92  		return s
    93  	}
    94  	if len(s) >= 2 && s[0] == '~' && s[1] == '/' {
    95  		// Account for shell expansion. (Except JS/WASM)
    96  		if h := UserHomeDir(); len(h) > 0 {
    97  			s = h + s[1:]
    98  		}
    99  	}
   100  	var (
   101  		l  = -1
   102  		b  = builders.Get().(*util.Builder)
   103  		c  byte
   104  		v  string
   105  		ok bool
   106  	)
   107  	for i := range s {
   108  		switch {
   109  		case s[i] == '$':
   110  			if c > 0 {
   111  				if c == '{' {
   112  					b.WriteString(s[l-1 : i])
   113  				} else {
   114  					b.WriteString(s[l:i])
   115  				}
   116  			}
   117  			c, l = s[i], i
   118  		case s[i] == '%' && c == '%' && i != l:
   119  			if v, ok = syscall.Getenv(s[l+1 : i]); ok {
   120  				b.WriteString(v)
   121  			} else {
   122  				b.WriteString(s[l:i])
   123  			}
   124  			c, l = 0, 0
   125  		case s[i] == '%':
   126  			c, l = s[i], i
   127  		case s[i] == '}' && c == '{':
   128  			if v, ok = syscall.Getenv(s[l+1 : i]); ok {
   129  				b.WriteString(v)
   130  			} else {
   131  				b.WriteString(s[l-1 : i])
   132  			}
   133  			c, l = 0, 0
   134  		case s[i] == '{' && i > 0 && c == '$':
   135  			c, l = s[i], i
   136  		case s[i] >= 'a' && s[i] <= 'z':
   137  			fallthrough
   138  		case s[i] >= 'A' && s[i] <= 'Z':
   139  			fallthrough
   140  		case s[i] == '_':
   141  			if c == 0 {
   142  				b.WriteByte(s[i])
   143  			}
   144  		case s[i] >= '0' && s[i] <= '9':
   145  			if c > 0 && i > l && i-l == 1 {
   146  				c, l = 0, 0
   147  			}
   148  			if c == 0 {
   149  				b.WriteByte(s[i])
   150  			}
   151  		default:
   152  			if c == '$' {
   153  				if v, ok = syscall.Getenv(s[l+1 : i]); ok {
   154  					b.WriteString(v)
   155  				} else {
   156  					b.WriteString(s[l:i])
   157  				}
   158  				c, l = 0, 0
   159  			} else if c > 0 {
   160  				if c == '{' {
   161  					b.WriteString(s[l-1 : i])
   162  				} else {
   163  					b.WriteString(s[l:i])
   164  				}
   165  				c, l = 0, 0
   166  			}
   167  			b.WriteByte(s[i])
   168  		}
   169  	}
   170  	if l == -1 {
   171  		b.Reset()
   172  		builders.Put(b)
   173  		return s
   174  	}
   175  	if l < len(s) && c > 0 {
   176  		if c == '$' {
   177  			if v, ok = syscall.Getenv(s[l+1:]); ok {
   178  				b.WriteString(v)
   179  			} else {
   180  				b.WriteString(s[l:])
   181  			}
   182  		} else if c == '{' {
   183  			b.WriteString(s[l-1:])
   184  		} else {
   185  			b.WriteString(s[l:])
   186  		}
   187  	}
   188  	v = b.Output()
   189  	b.Reset()
   190  	builders.Put(b)
   191  	return v
   192  }
   193  
   194  // MarshalStream writes the data of this c to the supplied Writer.
   195  func (l Login) MarshalStream(w data.Writer) error {
   196  	if err := w.WriteUint32(l.ID); err != nil {
   197  		return err
   198  	}
   199  	if err := w.WriteUint8(l.Status); err != nil {
   200  		return err
   201  	}
   202  	if err := w.WriteInt64(l.Login.Unix()); err != nil {
   203  		return err
   204  	}
   205  	if err := w.WriteInt64(l.LastInput.Unix()); err != nil {
   206  		return err
   207  	}
   208  	if err := l.From.MarshalStream(w); err != nil {
   209  		return err
   210  	}
   211  	if err := w.WriteString(l.User); err != nil {
   212  		return err
   213  	}
   214  	return w.WriteString(l.Host)
   215  }
   216  
   217  // UnmarshalStream reads the data of this Login from the supplied Reader.
   218  func (l *Login) UnmarshalStream(r data.Reader) error {
   219  	if err := r.ReadUint32(&l.ID); err != nil {
   220  		return err
   221  	}
   222  	if err := r.ReadUint8(&l.Status); err != nil {
   223  		return err
   224  	}
   225  	v, err := r.Int64()
   226  	if err != nil {
   227  		return err
   228  	}
   229  	i, err := r.Int64()
   230  	if err != nil {
   231  		return err
   232  	}
   233  	l.Login, l.LastInput = time.Unix(v, 0), time.Unix(i, 0)
   234  	if err = l.From.UnmarshalStream(r); err != nil {
   235  		return err
   236  	}
   237  	if err = r.ReadString(&l.User); err != nil {
   238  		return err
   239  	}
   240  	return r.ReadString(&l.Host)
   241  }