github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/u-root.go (about)

     1  // Copyright 2015-2018 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 main
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  
    14  	"github.com/u-root/u-root/pkg/golang"
    15  	"github.com/u-root/u-root/pkg/uroot"
    16  	"github.com/u-root/u-root/pkg/uroot/builder"
    17  	"github.com/u-root/u-root/pkg/uroot/initramfs"
    18  )
    19  
    20  // multiFlag is used for flags that support multiple invocations, e.g. -files
    21  type multiFlag []string
    22  
    23  func (m *multiFlag) String() string {
    24  	return fmt.Sprint(*m)
    25  }
    26  
    27  func (m *multiFlag) Set(value string) error {
    28  	*m = append(*m, value)
    29  	return nil
    30  }
    31  
    32  // Flags for u-root builder.
    33  var (
    34  	build, format, tmpDir, base, outputPath *string
    35  	initCmd                                 *string
    36  	defaultShell                            *string
    37  	useExistingInit                         *bool
    38  	fourbins                                *bool
    39  	extraFiles                              multiFlag
    40  	templates                               = map[string][]string{
    41  		"all": {
    42  			"github.com/u-root/u-root/cmds/*",
    43  		},
    44  		// Core should be things you don't want to live without.
    45  		"core": {
    46  			"github.com/u-root/u-root/cmds/ansi",
    47  			"github.com/u-root/u-root/cmds/boot",
    48  			"github.com/u-root/u-root/cmds/cat",
    49  			"github.com/u-root/u-root/cmds/cbmem",
    50  			"github.com/u-root/u-root/cmds/chmod",
    51  			"github.com/u-root/u-root/cmds/chroot",
    52  			"github.com/u-root/u-root/cmds/cmp",
    53  			"github.com/u-root/u-root/cmds/console",
    54  			"github.com/u-root/u-root/cmds/cp",
    55  			"github.com/u-root/u-root/cmds/cpio",
    56  			"github.com/u-root/u-root/cmds/date",
    57  			"github.com/u-root/u-root/cmds/dd",
    58  			"github.com/u-root/u-root/cmds/df",
    59  			"github.com/u-root/u-root/cmds/dhclient",
    60  			"github.com/u-root/u-root/cmds/dirname",
    61  			"github.com/u-root/u-root/cmds/dmesg",
    62  			"github.com/u-root/u-root/cmds/echo",
    63  			"github.com/u-root/u-root/cmds/elvish",
    64  			"github.com/u-root/u-root/cmds/false",
    65  			"github.com/u-root/u-root/cmds/field",
    66  			"github.com/u-root/u-root/cmds/find",
    67  			"github.com/u-root/u-root/cmds/free",
    68  			"github.com/u-root/u-root/cmds/freq",
    69  			"github.com/u-root/u-root/cmds/gpgv",
    70  			"github.com/u-root/u-root/cmds/gpt",
    71  			"github.com/u-root/u-root/cmds/grep",
    72  			"github.com/u-root/u-root/cmds/gzip",
    73  			"github.com/u-root/u-root/cmds/hexdump",
    74  			"github.com/u-root/u-root/cmds/hostname",
    75  			"github.com/u-root/u-root/cmds/id",
    76  			"github.com/u-root/u-root/cmds/init",
    77  			"github.com/u-root/u-root/cmds/insmod",
    78  			"github.com/u-root/u-root/cmds/installcommand",
    79  			"github.com/u-root/u-root/cmds/io",
    80  			"github.com/u-root/u-root/cmds/ip",
    81  			"github.com/u-root/u-root/cmds/kexec",
    82  			"github.com/u-root/u-root/cmds/kill",
    83  			"github.com/u-root/u-root/cmds/lddfiles",
    84  			"github.com/u-root/u-root/cmds/ln",
    85  			"github.com/u-root/u-root/cmds/losetup",
    86  			"github.com/u-root/u-root/cmds/ls",
    87  			"github.com/u-root/u-root/cmds/lsmod",
    88  			"github.com/u-root/u-root/cmds/mkdir",
    89  			"github.com/u-root/u-root/cmds/mkfifo",
    90  			"github.com/u-root/u-root/cmds/mknod",
    91  			"github.com/u-root/u-root/cmds/modprobe",
    92  			"github.com/u-root/u-root/cmds/mount",
    93  			"github.com/u-root/u-root/cmds/msr",
    94  			"github.com/u-root/u-root/cmds/mv",
    95  			"github.com/u-root/u-root/cmds/netcat",
    96  			"github.com/u-root/u-root/cmds/ntpdate",
    97  			"github.com/u-root/u-root/cmds/pci",
    98  			"github.com/u-root/u-root/cmds/ping",
    99  			"github.com/u-root/u-root/cmds/printenv",
   100  			"github.com/u-root/u-root/cmds/ps",
   101  			"github.com/u-root/u-root/cmds/pwd",
   102  			"github.com/u-root/u-root/cmds/pxeboot",
   103  			"github.com/u-root/u-root/cmds/readlink",
   104  			"github.com/u-root/u-root/cmds/rm",
   105  			"github.com/u-root/u-root/cmds/rmmod",
   106  			"github.com/u-root/u-root/cmds/rsdp",
   107  			"github.com/u-root/u-root/cmds/seq",
   108  			"github.com/u-root/u-root/cmds/shutdown",
   109  			"github.com/u-root/u-root/cmds/sleep",
   110  			"github.com/u-root/u-root/cmds/sort",
   111  			"github.com/u-root/u-root/cmds/stty",
   112  			"github.com/u-root/u-root/cmds/switch_root",
   113  			"github.com/u-root/u-root/cmds/sync",
   114  			"github.com/u-root/u-root/cmds/tail",
   115  			"github.com/u-root/u-root/cmds/tee",
   116  			"github.com/u-root/u-root/cmds/true",
   117  			"github.com/u-root/u-root/cmds/truncate",
   118  			"github.com/u-root/u-root/cmds/umount",
   119  			"github.com/u-root/u-root/cmds/uname",
   120  			"github.com/u-root/u-root/cmds/uniq",
   121  			"github.com/u-root/u-root/cmds/unshare",
   122  			"github.com/u-root/u-root/cmds/validate",
   123  			"github.com/u-root/u-root/cmds/vboot",
   124  			"github.com/u-root/u-root/cmds/wc",
   125  			"github.com/u-root/u-root/cmds/wget",
   126  			"github.com/u-root/u-root/cmds/which",
   127  		},
   128  		// Minimal should be things you can't live without.
   129  		"minimal": {
   130  			"github.com/u-root/u-root/cmds/cat",
   131  			"github.com/u-root/u-root/cmds/chmod",
   132  			"github.com/u-root/u-root/cmds/cmp",
   133  			"github.com/u-root/u-root/cmds/console",
   134  			"github.com/u-root/u-root/cmds/cp",
   135  			"github.com/u-root/u-root/cmds/date",
   136  			"github.com/u-root/u-root/cmds/dd",
   137  			"github.com/u-root/u-root/cmds/df",
   138  			"github.com/u-root/u-root/cmds/dhclient",
   139  			"github.com/u-root/u-root/cmds/dmesg",
   140  			"github.com/u-root/u-root/cmds/echo",
   141  			"github.com/u-root/u-root/cmds/elvish",
   142  			"github.com/u-root/u-root/cmds/find",
   143  			"github.com/u-root/u-root/cmds/free",
   144  			"github.com/u-root/u-root/cmds/gpgv",
   145  			"github.com/u-root/u-root/cmds/grep",
   146  			"github.com/u-root/u-root/cmds/gzip",
   147  			"github.com/u-root/u-root/cmds/hostname",
   148  			"github.com/u-root/u-root/cmds/id",
   149  			"github.com/u-root/u-root/cmds/init",
   150  			"github.com/u-root/u-root/cmds/insmod",
   151  			"github.com/u-root/u-root/cmds/io",
   152  			"github.com/u-root/u-root/cmds/ip",
   153  			"github.com/u-root/u-root/cmds/kexec",
   154  			"github.com/u-root/u-root/cmds/kill",
   155  			"github.com/u-root/u-root/cmds/ln",
   156  			"github.com/u-root/u-root/cmds/losetup",
   157  			"github.com/u-root/u-root/cmds/ls",
   158  			"github.com/u-root/u-root/cmds/lsmod",
   159  			"github.com/u-root/u-root/cmds/mkdir",
   160  			"github.com/u-root/u-root/cmds/mknod",
   161  			"github.com/u-root/u-root/cmds/modprobe",
   162  			"github.com/u-root/u-root/cmds/mount",
   163  			"github.com/u-root/u-root/cmds/msr",
   164  			"github.com/u-root/u-root/cmds/mv",
   165  			"github.com/u-root/u-root/cmds/pci",
   166  			"github.com/u-root/u-root/cmds/ping",
   167  			"github.com/u-root/u-root/cmds/printenv",
   168  			"github.com/u-root/u-root/cmds/ps",
   169  			"github.com/u-root/u-root/cmds/pwd",
   170  			"github.com/u-root/u-root/cmds/readlink",
   171  			"github.com/u-root/u-root/cmds/rm",
   172  			"github.com/u-root/u-root/cmds/rmmod",
   173  			"github.com/u-root/u-root/cmds/seq",
   174  			"github.com/u-root/u-root/cmds/shutdown",
   175  			"github.com/u-root/u-root/cmds/sleep",
   176  			"github.com/u-root/u-root/cmds/sync",
   177  			"github.com/u-root/u-root/cmds/tail",
   178  			"github.com/u-root/u-root/cmds/tee",
   179  			"github.com/u-root/u-root/cmds/truncate",
   180  			"github.com/u-root/u-root/cmds/umount",
   181  			"github.com/u-root/u-root/cmds/uname",
   182  			"github.com/u-root/u-root/cmds/unshare",
   183  			"github.com/u-root/u-root/cmds/wc",
   184  			"github.com/u-root/u-root/cmds/wget",
   185  			"github.com/u-root/u-root/cmds/which",
   186  		},
   187  		// coreboot-app minimal environment
   188  		"coreboot-app": {
   189  			"github.com/u-root/u-root/cmds/cat",
   190  			"github.com/u-root/u-root/cmds/cbmem",
   191  			"github.com/u-root/u-root/cmds/chroot",
   192  			"github.com/u-root/u-root/cmds/console",
   193  			"github.com/u-root/u-root/cmds/cp",
   194  			"github.com/u-root/u-root/cmds/dd",
   195  			"github.com/u-root/u-root/cmds/dhclient",
   196  			"github.com/u-root/u-root/cmds/dmesg",
   197  			"github.com/u-root/u-root/cmds/elvish",
   198  			"github.com/u-root/u-root/cmds/find",
   199  			"github.com/u-root/u-root/cmds/grep",
   200  			"github.com/u-root/u-root/cmds/id",
   201  			"github.com/u-root/u-root/cmds/init",
   202  			"github.com/u-root/u-root/cmds/insmod",
   203  			"github.com/u-root/u-root/cmds/ip",
   204  			"github.com/u-root/u-root/cmds/kill",
   205  			"github.com/u-root/u-root/cmds/ls",
   206  			"github.com/u-root/u-root/cmds/modprobe",
   207  			"github.com/u-root/u-root/cmds/mount",
   208  			"github.com/u-root/u-root/cmds/pci",
   209  			"github.com/u-root/u-root/cmds/ping",
   210  			"github.com/u-root/u-root/cmds/ps",
   211  			"github.com/u-root/u-root/cmds/pwd",
   212  			"github.com/u-root/u-root/cmds/rm",
   213  			"github.com/u-root/u-root/cmds/rmmod",
   214  			"github.com/u-root/u-root/cmds/shutdown",
   215  			"github.com/u-root/u-root/cmds/sshd",
   216  			"github.com/u-root/u-root/cmds/switch_root",
   217  			"github.com/u-root/u-root/cmds/tail",
   218  			"github.com/u-root/u-root/cmds/tee",
   219  			"github.com/u-root/u-root/cmds/uname",
   220  			"github.com/u-root/u-root/cmds/wget",
   221  		},
   222  	}
   223  )
   224  
   225  func init() {
   226  	fourbins = flag.Bool("fourbins", false, "build installcommand on boot, no ahead of time, so we have only four binares")
   227  	build = flag.String("build", "source", "u-root build format (e.g. bb or source).")
   228  	format = flag.String("format", "cpio", "Archival format.")
   229  
   230  	tmpDir = flag.String("tmpdir", "", "Temporary directory to put binaries in.")
   231  
   232  	base = flag.String("base", "", "Base archive to add files to. By default, this is a couple of directories like /bin, /etc, etc. u-root has a default internally supplied set of files; use base=/dev/null if you don't want any base files.")
   233  	useExistingInit = flag.Bool("useinit", false, "Use existing init from base archive (only if --base was specified).")
   234  	outputPath = flag.String("o", "", "Path to output initramfs file.")
   235  
   236  	initCmd = flag.String("initcmd", "init", "Symlink target for /init. Can be an absolute path or a u-root command name. Use initcmd=\"\" if you don't want the symlink.")
   237  	defaultShell = flag.String("defaultsh", "elvish", "Default shell. Can be an absolute path or a u-root command name. Use defaultsh=\"\" if you don't want the symlink.")
   238  
   239  	flag.Var(&extraFiles, "files", "Additional files, directories, and binaries (with their ldd dependencies) to add to archive. Can be speficified multiple times.")
   240  }
   241  
   242  func main() {
   243  	flag.Parse()
   244  
   245  	// Main is in a separate functions so defers run on return.
   246  	if err := Main(); err != nil {
   247  		log.Fatal(err)
   248  	}
   249  	log.Printf("Successfully wrote initramfs.")
   250  }
   251  
   252  // Main is a separate function so defers are run on return, which they wouldn't
   253  // on exit.
   254  func Main() error {
   255  	env := golang.Default()
   256  	if *fourbins && env.GOROOT == "" {
   257  		log.Fatalf("You have to set GOROOT for fourbins to work")
   258  	}
   259  	if env.CgoEnabled {
   260  		log.Printf("Disabling CGO for u-root...")
   261  		env.CgoEnabled = false
   262  	}
   263  	log.Printf("Build environment: %s", env)
   264  	if env.GOOS != "linux" {
   265  		log.Printf("GOOS is not linux. Did you mean to set GOOS=linux?")
   266  	}
   267  
   268  	var b builder.Builder
   269  	switch *build {
   270  	case "bb":
   271  		b = builder.BBBuilder{}
   272  	case "binary":
   273  		b = builder.BinaryBuilder{}
   274  	case "source":
   275  		b = builder.SourceBuilder{
   276  			FourBins: *fourbins,
   277  		}
   278  	default:
   279  		return fmt.Errorf("could not find builder %q", *build)
   280  	}
   281  
   282  	archiver, err := initramfs.GetArchiver(*format)
   283  	if err != nil {
   284  		return err
   285  	}
   286  
   287  	tempDir := *tmpDir
   288  	if tempDir == "" {
   289  		var err error
   290  		tempDir, err = ioutil.TempDir("", "u-root")
   291  		if err != nil {
   292  			return err
   293  		}
   294  		defer os.RemoveAll(tempDir)
   295  	} else if _, err := os.Stat(tempDir); os.IsNotExist(err) {
   296  		if err := os.MkdirAll(tempDir, 0755); err != nil {
   297  			return fmt.Errorf("temporary directory %q did not exist; tried to mkdir but failed: %v", tempDir, err)
   298  		}
   299  	}
   300  
   301  	// Resolve globs into package imports.
   302  	//
   303  	// Currently allowed formats:
   304  	//   Go package imports; e.g. github.com/u-root/u-root/cmds/ls (must be in $GOPATH)
   305  	//   Paths to Go package directories; e.g. $GOPATH/src/github.com/u-root/u-root/cmds/*
   306  	var pkgs []string
   307  	for _, a := range flag.Args() {
   308  		p, ok := templates[a]
   309  		if !ok {
   310  			pkgs = append(pkgs, a)
   311  			continue
   312  		}
   313  		pkgs = append(pkgs, p...)
   314  	}
   315  	if len(pkgs) == 0 {
   316  		pkgs = []string{"github.com/u-root/u-root/cmds/*"}
   317  	}
   318  
   319  	logger := log.New(os.Stderr, "", log.LstdFlags)
   320  	// Open the target initramfs file.
   321  	w, err := archiver.OpenWriter(logger, *outputPath, env.GOOS, env.GOARCH)
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	var baseFile initramfs.Reader
   327  	if *base != "" {
   328  		bf, err := os.Open(*base)
   329  		if err != nil {
   330  			return err
   331  		}
   332  		defer bf.Close()
   333  		baseFile = archiver.Reader(bf)
   334  	} else {
   335  		baseFile = uroot.DefaultRamfs.Reader()
   336  	}
   337  
   338  	initCommand := *initCmd
   339  	if *fourbins && *build == "source" {
   340  		initCommand = "/go/bin/go"
   341  	}
   342  
   343  	opts := uroot.Opts{
   344  		Env: env,
   345  		// The command-line tool only allows specifying one build mode
   346  		// right now.
   347  		Commands: []uroot.Commands{
   348  			{
   349  				Builder:  b,
   350  				Packages: pkgs,
   351  			},
   352  		},
   353  		TempDir:         tempDir,
   354  		ExtraFiles:      extraFiles,
   355  		OutputFile:      w,
   356  		BaseArchive:     baseFile,
   357  		UseExistingInit: *useExistingInit,
   358  		InitCmd:         initCommand,
   359  		DefaultShell:    *defaultShell,
   360  	}
   361  	return uroot.CreateInitramfs(logger, opts)
   362  }