github.com/rminnich/u-root@v7.0.0+incompatible/pkg/namespace/namespace_plan9.go (about)

     1  // Copyright 2020 the u-root 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 namespace
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  const (
    15  	// REPL Replace the old file by the new one.
    16  	// Henceforth, an evaluation of old will be translated to the new file.
    17  	// If they are directories (for mount, this condition is true by definition),
    18  	// old becomes a union directory consisting of one directory (the new file).
    19  	REPL mountflag = syscall.MREPL
    20  	// BEFORE Both the old and new files must be directories.
    21  	// Add the constituent files of the new directory to the
    22  	// union directory at old so its contents appear first in the union.
    23  	// After an BEFORE bind or mount, the new directory will be
    24  	// searched first when evaluating file names in the union directory.
    25  	BEFORE mountflag = syscall.MBEFORE
    26  	// AFTER Like MBEFORE but the new directory goes at the end of the union.
    27  	AFTER mountflag = syscall.MAFTER
    28  	// CREATE flag that can be OR'd with any of the above.
    29  	// When a create system call (see open(2)) attempts to create in a union directory,
    30  	// and the file does not exist, the elements of the union are searched in order until
    31  	// one is found with CREATE set. The file is created in that directory;
    32  	// if that attempt fails, the create fails.
    33  	CREATE mountflag = syscall.MCREATE
    34  	// CACHE flag, valid for mount only, turns on caching for files made available by the mount.
    35  	// By default, file contents are always retrieved from the server.
    36  	// With caching enabled, the kernel may instead use a local cache
    37  	// to satisfy read(5) requests for files accessible through this mount point.
    38  	CACHE mountflag = syscall.MCACHE
    39  )
    40  
    41  const (
    42  	// These are copied over from the syscall pkg for plan9 https://go.plan9.io/pkg/syscall/
    43  
    44  	// BIND is the plan9 bind syscall. https://9p.io/magic/man2html/2/bind
    45  	BIND syzcall = syscall.SYS_BIND
    46  	// CHDIR is the plan9 bind syscall. https://9p.io/magic/man2html/2/chdir
    47  	CHDIR syzcall = syscall.SYS_CHDIR
    48  	// UNMOUNT is the plan9 unmount syscall. https://9p.io/magic/man2html/2/bind
    49  	UNMOUNT syzcall = syscall.SYS_UNMOUNT
    50  	// MOUNT is the plan9 MOUNT syscall. https://9p.io/magic/man2html/2/bind
    51  	MOUNT syzcall = syscall.SYS_MOUNT
    52  	// RFORK is the plan9 rfork() syscall. https://9p.io/magic/man2html/2/fork
    53  	// used to perform clear
    54  	RFORK syzcall = syscall.SYS_RFORK
    55  	// IMPORT is not a syscall. https://9p.io/magic/man2html/4/import
    56  	IMPORT syzcall = syscall.SYS_EXEC // this is kinda handvavy cause this isn't an actual syscall
    57  	// but right now it shells out to actual import.
    58  	// TODO(sevki): implement the actual import
    59  	// INCLUDE is not a syscall
    60  	INCLUDE syzcall = syscall.SYS_OPEN // this is also handvavy
    61  )
    62  
    63  var DefaultNamespace = &namespace{}
    64  
    65  type namespace struct{}
    66  
    67  func (n *namespace) Bind(new string, old string, flag mountflag) error {
    68  	return syscall.Bind(new, old, int(flag))
    69  }
    70  func (n *namespace) Chdir(dir string) error { return syscall.Chdir(dir) }
    71  
    72  // Unmount unmounts
    73  func (n *namespace) Unmount(new string, old string) error { return syscall.Unmount(new, old) }
    74  
    75  // Clear clears the name space with rfork(RFCNAMEG).
    76  func (n *namespace) Clear() error {
    77  	r1, _, _ := syscall.RawSyscall(syscall.SYS_RFORK, uintptr(syscall.RFCNAMEG), 0, 0)
    78  	if r1 != 0 {
    79  		if int32(r1) == -1 {
    80  			return errors.New(errstr())
    81  		}
    82  		// parent; return PID
    83  		return nil
    84  	}
    85  	return nil
    86  }
    87  
    88  // Import imports a name space from a remote system
    89  // This currently shells out to import.
    90  //
    91  // TODO(sevki): implement native import in cmds
    92  // https://github.com/Harvey-OS/harvey/blob/master/sys/src/cmd/import.c
    93  func (n *namespace) Import(host string, remotepath string, mountpoint string, f mountflag) error {
    94  	flag := mountflag(f)
    95  	args := []string{host}
    96  	if remotepath != "" {
    97  		args = append(args, remotepath)
    98  	}
    99  	args = append(args, mountpoint)
   100  	flg := ""
   101  	if flag&AFTER != 0 {
   102  		flg += "a"
   103  	}
   104  	if flag&BEFORE != 0 {
   105  		flg += "b"
   106  	}
   107  	if flag&CREATE != 0 {
   108  		flg += "c"
   109  	}
   110  	if len(flg) > 0 {
   111  		args = append([]string{flg}, args...)
   112  	}
   113  	return syscall.Exec("import", args, nil)
   114  }
   115  
   116  // Mount opens a fd with the server name and mounts the open fd to
   117  // old
   118  func (n *namespace) Mount(servername string, old, spec string, flag mountflag) error {
   119  	fd, err := syscall.Open(servername, syscall.O_RDWR)
   120  	if err != nil {
   121  		return fmt.Errorf("open failed: %v", err)
   122  	}
   123  	return syscall.Mount(fd, -1, old, int(flag), spec)
   124  }
   125  
   126  func errstr() string {
   127  	var buf [syscall.ERRMAX]byte
   128  
   129  	syscall.RawSyscall(syscall.SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
   130  
   131  	buf[len(buf)-1] = 0
   132  	return cstring(buf[:])
   133  }
   134  
   135  func cstring(s []byte) string {
   136  	for i := range s {
   137  		if s[i] == 0 {
   138  			return string(s[0:i])
   139  		}
   140  	}
   141  	return string(s)
   142  }