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  }