github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+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 }