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  }