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