github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/libinit/root_linux.go (about) 1 // Copyright 2014-2019 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 libinit creates the environment and root file system for u-root. 6 package libinit 7 8 import ( 9 "fmt" 10 "os" 11 "runtime" 12 "strconv" 13 "syscall" 14 15 "github.com/u-root/u-root/pkg/cmdline" 16 "github.com/u-root/u-root/pkg/ulog" 17 "golang.org/x/sys/unix" 18 ) 19 20 type creator interface { 21 create() error 22 fmt.Stringer 23 } 24 25 type dir struct { 26 Name string 27 Mode os.FileMode 28 } 29 30 func (d dir) create() error { 31 return os.MkdirAll(d.Name, d.Mode) 32 } 33 34 func (d dir) String() string { 35 return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode) 36 } 37 38 type symlink struct { 39 Target string 40 NewPath string 41 } 42 43 func (s symlink) create() error { 44 os.Remove(s.NewPath) 45 return os.Symlink(s.Target, s.NewPath) 46 } 47 48 func (s symlink) String() string { 49 return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target) 50 } 51 52 type dev struct { 53 Name string 54 Mode uint32 55 Dev int 56 } 57 58 func (d dev) create() error { 59 os.Remove(d.Name) 60 return syscall.Mknod(d.Name, d.Mode, d.Dev) 61 } 62 63 func (d dev) String() string { 64 return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev) 65 } 66 67 type mount struct { 68 Source string 69 Target string 70 FSType string 71 Flags uintptr 72 Opts string 73 } 74 75 func (m mount) create() error { 76 return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts) 77 } 78 79 func (m mount) String() string { 80 return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags) 81 } 82 83 var ( 84 // These have to be created / mounted first, so that the logging works correctly. 85 preNamespace = []creator{ 86 dir{Name: "/dev", Mode: 0777}, 87 88 // Kernel must be compiled with CONFIG_DEVTMPFS. 89 mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"}, 90 } 91 namespace = []creator{ 92 dir{Name: "/buildbin", Mode: 0777}, 93 dir{Name: "/ubin", Mode: 0777}, 94 dir{Name: "/tmp", Mode: 0777}, 95 dir{Name: "/env", Mode: 0777}, 96 dir{Name: "/tcz", Mode: 0777}, 97 dir{Name: "/lib", Mode: 0777}, 98 dir{Name: "/usr/lib", Mode: 0777}, 99 dir{Name: "/var/log", Mode: 0777}, 100 dir{Name: "/go/pkg/linux_amd64", Mode: 0777}, 101 102 dir{Name: "/etc", Mode: 0777}, 103 104 dir{Name: "/proc", Mode: 0555}, 105 mount{Source: "proc", Target: "/proc", FSType: "proc"}, 106 mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"}, 107 108 dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500}, 109 dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109}, 110 dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104}, 111 112 dir{Name: "/dev/pts", Mode: 0777}, 113 mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"}, 114 // Note: if we mount /dev/pts with "newinstance", we *must* make "/dev/ptmx" a symlink to "/dev/pts/ptmx" 115 symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"}, 116 // Note: shm is required at least for Chrome. If you don't mount 117 // it chrome throws a bogus "out of memory" error, not the more 118 // useful "I can't open /dev/shm/whatever". SAD! 119 dir{Name: "/dev/shm", Mode: 0777}, 120 mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"}, 121 122 dir{Name: "/sys", Mode: 0555}, 123 mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"}, 124 mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"}, 125 } 126 127 // cgroups are optional for most u-root users, especially 128 // LinuxBoot/NERF. Some users use u-root for container stuff. 129 cgroupsnamespace = []creator{ 130 mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"}, 131 dir{Name: "/sys/fs/cgroup/memory", Mode: 0555}, 132 dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555}, 133 dir{Name: "/sys/fs/cgroup/devices", Mode: 0555}, 134 dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555}, 135 dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555}, 136 dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555}, 137 dir{Name: "/sys/fs/cgroup/pids", Mode: 0555}, 138 dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555}, 139 dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555}, 140 dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555}, 141 symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"}, 142 symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"}, 143 symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"}, 144 symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"}, 145 mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"}, 146 mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"}, 147 mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"}, 148 mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"}, 149 mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"}, 150 mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"}, 151 mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"}, 152 mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"}, 153 mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"}, 154 mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"}, 155 } 156 ) 157 158 func goBin() string { 159 return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH) 160 } 161 162 func create(namespace []creator, optional bool) { 163 // Clear umask bits so that we get stuff like ptmx right. 164 m := unix.Umask(0) 165 defer unix.Umask(m) 166 for _, c := range namespace { 167 if err := c.create(); err != nil { 168 if optional { 169 ulog.KernelLog.Printf("u-root init [optional]: warning creating %s: %v", c, err) 170 } else { 171 ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err) 172 } 173 } 174 } 175 } 176 177 // SetEnv sets the default u-root environment. 178 func SetEnv() { 179 env := map[string]string{ 180 "LD_LIBRARY_PATH": "/usr/local/lib", 181 "GOROOT": "/go", 182 "GOPATH": "/", 183 "GOBIN": "/ubin", 184 "CGO_ENABLED": "0", 185 "USER": "root", 186 } 187 188 // Not all these paths may be populated or even exist but OTOH they might. 189 path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin" 190 191 env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path) 192 for k, v := range env { 193 os.Setenv(k, v) 194 } 195 } 196 197 // CreateRootfs creates the default u-root file system. 198 func CreateRootfs() { 199 // Mount devtmpfs, then open /dev/kmsg with Reinit. 200 create(preNamespace, false) 201 ulog.KernelLog.Reinit() 202 203 create(namespace, false) 204 205 // systemd gets upset when it discovers something has already setup cgroups 206 // We have to do this after the base namespace is created, so we have /proc 207 initFlags := cmdline.GetInitFlagMap() 208 systemd, present := initFlags["systemd"] 209 systemdEnabled, boolErr := strconv.ParseBool(systemd) 210 if !present || boolErr != nil || !systemdEnabled { 211 create(cgroupsnamespace, true) 212 } 213 }