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  }