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