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  //go:nosplit
    29  func goenvs() {
    30  	buf := make([]byte, envBufSize)
    31  	copy(buf, envDir)
    32  	dirfd := open(&buf[0], _OREAD, 0)
    33  	if dirfd < 0 {
    34  		return
    35  	}
    36  	defer closefd(dirfd)
    37  	dofiles(dirfd, func(name []byte) {
    38  		name = append(name, 0)
    39  		buf = buf[:len(envDir)]
    40  		copy(buf, envDir)
    41  		buf = append(buf, name...)
    42  		fd := open(&buf[0], _OREAD, 0)
    43  		if fd < 0 {
    44  			return
    45  		}
    46  		defer closefd(fd)
    47  		n := len(buf)
    48  		r := 0
    49  		for {
    50  			r = int(pread(fd, unsafe.Pointer(&buf[0]), int32(n), 0))
    51  			if r < n {
    52  				break
    53  			}
    54  			n = int(seek(fd, 0, 2)) + 1
    55  			if len(buf) < n {
    56  				buf = make([]byte, n)
    57  			}
    58  		}
    59  		if r <= 0 {
    60  			r = 0
    61  		} else if buf[r-1] == 0 {
    62  			r--
    63  		}
    64  		name[len(name)-1] = '='
    65  		env := make([]byte, len(name)+r)
    66  		copy(env, name)
    67  		copy(env[len(name):], buf[:r])
    68  		envs = append(envs, string(env))
    69  	})
    70  }
    71  
    72  // Dofiles reads the directory opened with file descriptor fd, applying function f
    73  // to each filename in it.
    74  //go:nosplit
    75  func dofiles(dirfd int32, f func([]byte)) {
    76  	dirbuf := new([dirBufSize]byte)
    77  
    78  	var off int64 = 0
    79  	for {
    80  		n := pread(dirfd, unsafe.Pointer(&dirbuf[0]), int32(dirBufSize), off)
    81  		if n <= 0 {
    82  			return
    83  		}
    84  		for b := dirbuf[:n]; len(b) > 0; {
    85  			var name []byte
    86  			name, b = gdirname(b)
    87  			if name == nil {
    88  				return
    89  			}
    90  			f(name)
    91  		}
    92  		off += int64(n)
    93  	}
    94  }
    95  
    96  // Gdirname returns the first filename from a buffer of directory entries,
    97  // and a slice containing the remaining directory entries.
    98  // If the buffer doesn't start with a valid directory entry, the returned name is nil.
    99  //go:nosplit
   100  func gdirname(buf []byte) (name []byte, rest []byte) {
   101  	if 2+nameOffset+2 > len(buf) {
   102  		return
   103  	}
   104  	entryLen, buf := gbit16(buf)
   105  	if entryLen > len(buf) {
   106  		return
   107  	}
   108  	n, b := gbit16(buf[nameOffset:])
   109  	if n > len(b) {
   110  		return
   111  	}
   112  	name = b[:n]
   113  	rest = buf[entryLen:]
   114  	return
   115  }
   116  
   117  // Gbit16 reads a 16-bit little-endian binary number from b and returns it
   118  // with the remaining slice of b.
   119  //go:nosplit
   120  func gbit16(b []byte) (int, []byte) {
   121  	return int(b[0]) | int(b[1])<<8, b[2:]
   122  }
   123  

View as plain text