gopkg.in/hugelgupf/u-root.v4@v4.0.0-20180831060141-1d761fb73d50/pkg/uroot/util/root.go (about) 1 // Copyright 2014-2017 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 // +build linux 6 7 // Package util contains various u-root utility functions. 8 package util 9 10 import ( 11 "fmt" 12 "io/ioutil" 13 "log" 14 "os" 15 "runtime" 16 "strconv" 17 "syscall" 18 19 "github.com/u-root/u-root/pkg/cmdline" 20 "golang.org/x/sys/unix" 21 ) 22 23 const ( 24 // Not all these paths may be populated or even exist but OTOH they might. 25 PATHHEAD = "/ubin" 26 PATHMID = "/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin" 27 PATHTAIL = "/buildbin:/bbin" 28 ) 29 30 type Creator interface { 31 Create() error 32 fmt.Stringer 33 } 34 35 type Dir struct { 36 Name string 37 Mode os.FileMode 38 } 39 40 func (d Dir) Create() error { 41 return os.MkdirAll(d.Name, d.Mode) 42 } 43 44 func (d Dir) String() string { 45 return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode) 46 } 47 48 type File struct { 49 Name string 50 Contents string 51 Mode os.FileMode 52 } 53 54 func (f File) Create() error { 55 return ioutil.WriteFile(f.Name, []byte(f.Contents), f.Mode) 56 } 57 58 func (f File) String() string { 59 return fmt.Sprintf("file %q (mode %#o)", f.Name, f.Mode) 60 } 61 62 type Symlink struct { 63 Target string 64 NewPath string 65 } 66 67 func (s Symlink) Create() error { 68 os.Remove(s.NewPath) 69 return os.Symlink(s.Target, s.NewPath) 70 } 71 72 func (s Symlink) String() string { 73 return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target) 74 } 75 76 type Link struct { 77 OldPath string 78 NewPath string 79 } 80 81 func (s Link) Create() error { 82 os.Remove(s.NewPath) 83 return os.Link(s.OldPath, s.NewPath) 84 } 85 86 func (s Link) String() string { 87 return fmt.Sprintf("link %q -> %q", s.NewPath, s.OldPath) 88 } 89 90 type Dev struct { 91 Name string 92 Mode uint32 93 Dev int 94 } 95 96 func (d Dev) Create() error { 97 os.Remove(d.Name) 98 return syscall.Mknod(d.Name, d.Mode, d.Dev) 99 } 100 101 func (d Dev) String() string { 102 return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev) 103 } 104 105 type Mount struct { 106 Source string 107 Target string 108 FSType string 109 Flags uintptr 110 Opts string 111 } 112 113 func (m Mount) Create() error { 114 return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts) 115 } 116 117 func (m Mount) String() string { 118 return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags) 119 } 120 121 var ( 122 namespace = []Creator{ 123 Dir{Name: "/buildbin", Mode: 0777}, 124 Dir{Name: "/ubin", Mode: 0777}, 125 Dir{Name: "/tmp", Mode: 0777}, 126 Dir{Name: "/env", Mode: 0777}, 127 Dir{Name: "/tcz", Mode: 0777}, 128 Dir{Name: "/lib", Mode: 0777}, 129 Dir{Name: "/usr/lib", Mode: 0777}, 130 Dir{Name: "/var/log", Mode: 0777}, 131 Dir{Name: "/go/pkg/linux_amd64", Mode: 0777}, 132 133 Dir{Name: "/etc", Mode: 0777}, 134 135 Dir{Name: "/proc", Mode: 0555}, 136 Mount{Source: "proc", Target: "/proc", FSType: "proc"}, 137 Mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"}, 138 139 Dir{Name: "/dev", Mode: 0777}, 140 Dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500}, 141 Dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109}, 142 Dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104}, 143 144 // Kernel must be compiled with CONFIG_DEVTMPFS. 145 // Note that things kind of work even if this mount fails. 146 // TODO: move the Dir commands above below this line? 147 Mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"}, 148 149 Dir{Name: "/dev/pts", Mode: 0777}, 150 Mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"}, 151 Dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502}, 152 // Note: shm is required at least for Chrome. If you don't mount 153 // it chrome throws a bogus "out of memory" error, not the more 154 // useful "I can't open /dev/shm/whatever". SAD! 155 Dir{Name: "/dev/shm", Mode: 0777}, 156 Mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"}, 157 158 Dir{Name: "/sys", Mode: 0555}, 159 Mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"}, 160 } 161 cgroupsnamespace = []Creator{ 162 Mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"}, 163 Dir{Name: "/sys/fs/cgroup/memory", Mode: 0555}, 164 Dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555}, 165 Dir{Name: "/sys/fs/cgroup/devices", Mode: 0555}, 166 Dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555}, 167 Dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555}, 168 Dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555}, 169 Dir{Name: "/sys/fs/cgroup/pids", Mode: 0555}, 170 Dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555}, 171 Dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555}, 172 Dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555}, 173 Symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"}, 174 Symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"}, 175 Symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"}, 176 Symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"}, 177 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"}, 178 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"}, 179 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"}, 180 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"}, 181 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"}, 182 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"}, 183 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"}, 184 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"}, 185 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"}, 186 Mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"}, 187 } 188 189 Env = map[string]string{ 190 "LD_LIBRARY_PATH": "/usr/local/lib", 191 "GOROOT": "/go", 192 "GOPATH": "/", 193 "GOBIN": "/ubin", 194 "CGO_ENABLED": "0", 195 } 196 ) 197 198 func GoBin() string { 199 return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH) 200 } 201 202 func create(namespace []Creator) { 203 // Clear umask bits so that we get stuff like ptmx right. 204 m := unix.Umask(0) 205 defer unix.Umask(m) 206 for _, c := range namespace { 207 if err := c.Create(); err != nil { 208 log.Printf("Error creating %s: %v", c, err) 209 } else { 210 log.Printf("Created %v", c) 211 } 212 } 213 } 214 215 // build the root file system. 216 func Rootfs() { 217 Env["PATH"] = fmt.Sprintf("%v:%v:%v:%v", GoBin(), PATHHEAD, PATHMID, PATHTAIL) 218 for k, v := range Env { 219 os.Setenv(k, v) 220 } 221 create(namespace) 222 223 // systemd gets upset when it discovers something has already setup cgroups 224 // We have to do this after the base namespace is created, so we have /proc 225 initFlags := cmdline.GetInitFlagMap() 226 systemd, present := initFlags["systemd"] 227 systemdEnabled, boolErr := strconv.ParseBool(systemd) 228 if !present || boolErr != nil || systemdEnabled == false { 229 create(cgroupsnamespace) 230 } 231 232 }