github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/namespace/namespace.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 "fmt" 9 "io" 10 "os" 11 ) 12 13 //go:generate stringer -type mountflag 14 type mountflag int 15 16 //go:generate stringer -type syzcall 17 type syzcall byte 18 19 // File are a collection of namespace modifiers 20 type File []Modifier 21 22 // Namespace is a plan9 namespace. It implmenets the 23 // http://man.cat-v.org/plan_9/2/bind calls. 24 // 25 // Bind and mount modify the file name space of the current 26 // process and other processes in its name space group 27 // (see http://man.cat-v.org/plan_9/2/fork). 28 // For both calls, old is the name of an existing file or directory 29 // in the current name space where the modification is to be made. 30 // The name old is evaluated as described in 31 // http://man.cat-v.org/plan_9/2/intro, 32 // except that no translation of the final path element is done. 33 type Namespace interface { 34 // Bind binds new on old. 35 Bind(new, old string, flag mountflag) error 36 // Mount mounts servename on old. 37 Mount(servername, old, spec string, flag mountflag) error 38 // Unmount unmounts new from old, or everything mounted on old if new is missing. 39 Unmount(new, old string) error 40 // Clear clears the name space with rfork(RFCNAMEG). 41 Clear() error 42 // Chdir changes the working directory to dir. 43 Chdir(dir string) error 44 // Import imports a name space from a remote system 45 Import(host, remotepath, mountpoint string, flag mountflag) error 46 } 47 48 // Modifier repesents an individual command that can be applied 49 // to a plan9 name space which will modify the name space of the process or process group. 50 type Modifier interface { 51 // Modify modifies the namespace 52 Modify(ns Namespace, b *Builder) error 53 String() string 54 } 55 56 // NewNS builds a name space for user. 57 // It opens the file nsfile (/lib/namespace is used if nsfile is ""), 58 // copies the old environment, erases the current name space, 59 // sets the environment variables user and home, and interprets the commands in nsfile. 60 // The format of nsfile is described in namespace(6). 61 func NewNS(nsfile string, user string) error { return buildNS(nil, nsfile, user, true) } 62 63 // AddNS also interprets and executes the commands in nsfile. 64 // Unlike newns it applies the command to the current name 65 // space rather than starting from scratch. 66 func AddNS(nsfile string, user string) error { return buildNS(nil, nsfile, user, false) } 67 68 func buildNS(ns Namespace, nsfile, user string, new bool) error { 69 if err := os.Setenv("user", user); err != nil { 70 return err 71 } 72 if ns == nil { 73 ns = DefaultNamespace 74 } 75 if new { 76 ns.Clear() 77 } 78 r, err := NewBuilder() 79 if err != nil { 80 return err 81 } 82 if err := r.Parse(nsfile); err != nil { 83 return err 84 } 85 return r.buildNS(ns) 86 } 87 88 // OpenFunc opens files for the include or . commands in name space files. 89 // while the default open function is just os.Open for the file:// 90 // one could extend this to other protocols. Potentially we could 91 // even import files from the web.eg 92 // 93 // . https://harvey-os.org/lib/namespace@sha256:deadbeef 94 // 95 // could be interesting. 96 type OpenFunc func(path string) (io.Reader, error) 97 98 // Builder helps building plan9 name spaces. Builder keeps track of directory changes 99 // when another name space file is included, another builder will be created for it's 100 // modifications, and it's final working directory will be set to be the parents working 101 // directroy after it's modifications are complete. 102 type Builder struct { 103 dir string 104 file File 105 106 open OpenFunc 107 } 108 109 func open1(path string) (io.Reader, error) { return os.Open(path) } 110 111 // NewBuilder returns a builder with defaults 112 func NewBuilder() (*Builder, error) { 113 wd, err := os.Getwd() 114 if err != nil { 115 return nil, err 116 } 117 return &Builder{ 118 dir: wd, 119 open: open1, 120 }, nil 121 } 122 123 func newBuilder(wd string, b OpenFunc) (*Builder, error) { 124 return &Builder{ 125 dir: wd, 126 open: b, 127 }, nil 128 } 129 130 // Parse takes a path and parses the namespace file 131 func (b *Builder) Parse(file string) error { 132 f, err := b.open(file) 133 if err != nil { 134 return err 135 } 136 b.file, err = Parse(f) 137 if err != nil { 138 return err 139 } 140 return nil 141 } 142 143 // Run takes a namespace and runs commands defined in the namespace file 144 func (b *Builder) buildNS(ns Namespace) error { 145 for _, c := range b.file { 146 if err := c.Modify(ns, b); err != nil { 147 return fmt.Errorf("newns failed to perform %s failed: %v", c, err) 148 } 149 } 150 return nil 151 }