github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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  		dev{Name: "/dev/ptmx", Mode: syscall.S_IFCHR | 0666, Dev: 0x0502},
   115  		// Note: shm is required at least for Chrome. If you don't mount
   116  		// it chrome throws a bogus "out of memory" error, not the more
   117  		// useful "I can't open /dev/shm/whatever". SAD!
   118  		dir{Name: "/dev/shm", Mode: 0777},
   119  		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},
   120  
   121  		dir{Name: "/sys", Mode: 0555},
   122  		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
   123  		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
   124  	}
   125  	cgroupsnamespace = []creator{
   126  		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
   127  		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
   128  		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
   129  		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
   130  		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
   131  		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
   132  		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
   133  		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
   134  		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
   135  		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
   136  		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
   137  		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
   138  		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
   139  		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
   140  		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
   141  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
   142  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
   143  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
   144  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
   145  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
   146  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
   147  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
   148  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
   149  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
   150  		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
   151  	}
   152  )
   153  
   154  func goBin() string {
   155  	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
   156  }
   157  
   158  func create(namespace []creator) {
   159  	// Clear umask bits so that we get stuff like ptmx right.
   160  	m := unix.Umask(0)
   161  	defer unix.Umask(m)
   162  	for _, c := range namespace {
   163  		if err := c.create(); err != nil {
   164  			ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
   165  		}
   166  	}
   167  }
   168  
   169  // SetEnv sets the default u-root environment.
   170  func SetEnv() {
   171  	env := map[string]string{
   172  		"LD_LIBRARY_PATH": "/usr/local/lib",
   173  		"GOROOT":          "/go",
   174  		"GOPATH":          "/",
   175  		"GOBIN":           "/ubin",
   176  		"CGO_ENABLED":     "0",
   177  	}
   178  
   179  	// Not all these paths may be populated or even exist but OTOH they might.
   180  	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"
   181  
   182  	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
   183  	for k, v := range env {
   184  		os.Setenv(k, v)
   185  	}
   186  }
   187  
   188  // CreateRootfs creates the default u-root file system.
   189  func CreateRootfs() {
   190  	// Mount devtmpfs, then open /dev/kmsg with Reinit.
   191  	create(preNamespace)
   192  	ulog.KernelLog.Reinit()
   193  
   194  	create(namespace)
   195  
   196  	// systemd gets upset when it discovers something has already setup cgroups
   197  	// We have to do this after the base namespace is created, so we have /proc
   198  	initFlags := cmdline.GetInitFlagMap()
   199  	systemd, present := initFlags["systemd"]
   200  	systemdEnabled, boolErr := strconv.ParseBool(systemd)
   201  	if !present || boolErr != nil || !systemdEnabled {
   202  		create(cgroupsnamespace)
   203  	}
   204  }