Source file src/runtime/env_plan9.go

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import "unsafe"
     8  
     9  const (
    10  	// Plan 9 environment device
    11  	envDir = "/env/"
    12  	// size of buffer to read from a directory
    13  	dirBufSize = 4096
    14  	// size of buffer to read an environment variable (may grow)
    15  	envBufSize = 128
    16  	// offset of the name field in a 9P directory entry - see syscall.UnmarshalDir()
    17  	nameOffset = 39
    18  )
    19  
    20  // goenvs caches the Plan 9 environment variables at start of execution into
    21  // string array envs, to supply the initial contents for os.Environ.
    22  // Subsequent calls to os.Setenv will change this cache, without writing back
    23  // to the (possibly shared) Plan 9 environment, so that Setenv and Getenv
    24  // conform to the same Posix semantics as on other operating systems.
    25  // For Plan 9 shared environment semantics, instead of Getenv(key) and
    26  // Setenv(key, value), one can use os.ReadFile("/env/" + key) and
    27  // os.WriteFile("/env/" + key, value, 0666) respectively.
    28  //
    29  //go:nosplit
    30  func goenvs() {
    31  	buf := make([]byte, envBufSize)
    32  	copy(buf, envDir)
    33  	dirfd := open(&buf[0], _OREAD, 0)
    34  	if dirfd < 0 {
    35  		return
    36  	}
    37  	defer closefd(dirfd)
    38  	dofiles(dirfd, func(name []byte) {
    39  		name = append(name, 0)
    40  		buf = buf[:len(envDir)]
    41  		copy(buf, envDir)
    42  		buf = append(buf, name...)
    43  		fd := open(&buf[0], _OREAD, 0)
    44  		if fd < 0 {
    45  			return
    46  		}
    47  		defer closefd(fd)
    48  		n := len(buf)
    49  		r := 0
    50  		for {
    51  			r = int(pread(fd, unsafe.Pointer(&buf[0]), int32(n), 0))
    52  			if r < n {
    53  				break
    54  			}
    55  			n = int(seek(fd, 0, 2)) + 1
    56  			if len(buf) < n {
    57  				buf = make([]byte, n)
    58  			}
    59  		}
    60  		if r <= 0 {
    61  			r = 0
    62  		} else if buf[r-1] == 0 {
    63  			r--
    64  		}
    65  		name[len(name)-1] = '='
    66  		env := make([]byte, len(name)+r)
    67  		copy(env, name)
    68  		copy(env[len(name):], buf[:r])
    69  		envs = append(envs, string(env))
    70  	})
    71  }
    72  
    73  // dofiles reads the directory opened with file descriptor fd, applying function f
    74  // to each filename in it.
    75  //
    76  //go:nosplit
    77  func dofiles(dirfd int32, f func([]byte)) {
    78  	dirbuf := new([dirBufSize]byte)
    79  
    80  	var off int64 = 0
    81  	for {
    82  		n := pread(dirfd, unsafe.Pointer(&dirbuf[0]), int32(dirBufSize), off)
    83  		if n <= 0 {
    84  			return
    85  		}
    86  		for b := dirbuf[:n]; len(b) > 0; {
    87  			var name []byte
    88  			name, b = gdirname(b)
    89  			if name == nil {
    90  				return
    91  			}
    92  			f(name)
    93  		}
    94  		off += int64(n)
    95  	}
    96  }
    97  
    98  // gdirname returns the first filename from a buffer of directory entries,
    99  // and a slice containing the remaining directory entries.
   100  // If the buffer doesn't start with a valid directory entry, the returned name is nil.
   101  //
   102  //go:nosplit
   103  func gdirname(buf []byte) (name []byte, rest []byte) {
   104  	if 2+nameOffset+2 > len(buf) {
   105  		return
   106  	}
   107  	entryLen, buf := gbit16(buf)
   108  	if entryLen > len(buf) {
   109  		return
   110  	}
   111  	n, b := gbit16(buf[nameOffset:])
   112  	if n > len(b) {
   113  		return
   114  	}
   115  	name = b[:n]
   116  	rest = buf[entryLen:]
   117  	return
   118  }
   119  
   120  // gbit16 reads a 16-bit little-endian binary number from b and returns it
   121  // with the remaining slice of b.
   122  //
   123  //go:nosplit
   124  func gbit16(b []byte) (int, []byte) {
   125  	return int(b[0]) | int(b[1])<<8, b[2:]
   126  }
   127  

View as plain text