github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+incompatible/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  	noCommands                              *bool
    40  	extraFiles                              multiFlag
    41  )
    42  
    43  func init() {
    44  	fourbins = flag.Bool("fourbins", false, "build installcommand on boot, no ahead of time, so we have only four binares")
    45  	build = flag.String("build", "source", "u-root build format (e.g. bb or source).")
    46  	format = flag.String("format", "cpio", "Archival format.")
    47  
    48  	tmpDir = flag.String("tmpdir", "", "Temporary directory to put binaries in.")
    49  
    50  	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.")
    51  	useExistingInit = flag.Bool("useinit", false, "Use existing init from base archive (only if --base was specified).")
    52  	outputPath = flag.String("o", "", "Path to output initramfs file.")
    53  
    54  	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.")
    55  	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.")
    56  	noCommands = flag.Bool("nocmd", false, "Build no Go commands; initramfs only")
    57  
    58  	flag.Var(&extraFiles, "files", "Additional files, directories, and binaries (with their ldd dependencies) to add to archive. Can be speficified multiple times.")
    59  }
    60  
    61  func main() {
    62  	flag.Parse()
    63  
    64  	// Main is in a separate functions so defers run on return.
    65  	if err := Main(); err != nil {
    66  		log.Fatal(err)
    67  	}
    68  	log.Printf("Successfully wrote initramfs.")
    69  }
    70  
    71  // Main is a separate function so defers are run on return, which they wouldn't
    72  // on exit.
    73  func Main() error {
    74  	env := golang.Default()
    75  	if *fourbins && env.GOROOT == "" {
    76  		log.Fatalf("You have to set GOROOT for fourbins to work")
    77  	}
    78  	if env.CgoEnabled {
    79  		log.Printf("Disabling CGO for u-root...")
    80  		env.CgoEnabled = false
    81  	}
    82  	log.Printf("Build environment: %s", env)
    83  	if env.GOOS != "linux" {
    84  		log.Printf("GOOS is not linux. Did you mean to set GOOS=linux?")
    85  	}
    86  
    87  	archiver, err := initramfs.GetArchiver(*format)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	logger := log.New(os.Stderr, "", log.LstdFlags)
    93  	// Open the target initramfs file.
    94  	w, err := archiver.OpenWriter(logger, *outputPath, env.GOOS, env.GOARCH)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	var baseFile initramfs.Reader
   100  	if *base != "" {
   101  		bf, err := os.Open(*base)
   102  		if err != nil {
   103  			return err
   104  		}
   105  		defer bf.Close()
   106  		baseFile = archiver.Reader(bf)
   107  	} else {
   108  		baseFile = uroot.DefaultRamfs.Reader()
   109  	}
   110  
   111  	tempDir := *tmpDir
   112  	if tempDir == "" {
   113  		var err error
   114  		tempDir, err = ioutil.TempDir("", "u-root")
   115  		if err != nil {
   116  			return err
   117  		}
   118  		defer os.RemoveAll(tempDir)
   119  	} else if _, err := os.Stat(tempDir); os.IsNotExist(err) {
   120  		if err := os.MkdirAll(tempDir, 0755); err != nil {
   121  			return fmt.Errorf("temporary directory %q did not exist; tried to mkdir but failed: %v", tempDir, err)
   122  		}
   123  	}
   124  
   125  	var (
   126  		c           []uroot.Commands
   127  		initCommand = *initCmd
   128  	)
   129  	if !*noCommands {
   130  		var b builder.Builder
   131  		switch *build {
   132  		case "bb":
   133  			b = builder.BBBuilder{}
   134  		case "binary":
   135  			b = builder.BinaryBuilder{}
   136  		case "source":
   137  			b = builder.SourceBuilder{
   138  				FourBins: *fourbins,
   139  			}
   140  		default:
   141  			return fmt.Errorf("could not find builder %q", *build)
   142  		}
   143  
   144  		// Resolve globs into package imports.
   145  		//
   146  		// Currently allowed formats:
   147  		//   Go package imports; e.g. github.com/u-root/u-root/cmds/ls (must be in $GOPATH)
   148  		//   Paths to Go package directories; e.g. $GOPATH/src/github.com/u-root/u-root/cmds/*
   149  		var pkgs []string
   150  		for _, a := range flag.Args() {
   151  			p, ok := templates[a]
   152  			if !ok {
   153  				pkgs = append(pkgs, a)
   154  				continue
   155  			}
   156  			pkgs = append(pkgs, p...)
   157  		}
   158  		if len(pkgs) == 0 {
   159  			pkgs = []string{"github.com/u-root/u-root/cmds/*"}
   160  		}
   161  
   162  		if *fourbins && *build == "source" {
   163  			initCommand = "/go/bin/go"
   164  		}
   165  
   166  		// The command-line tool only allows specifying one build mode
   167  		// right now.
   168  		c = append(c, uroot.Commands{
   169  			Builder:  b,
   170  			Packages: pkgs,
   171  		})
   172  	}
   173  
   174  	opts := uroot.Opts{
   175  		Env:             env,
   176  		Commands:        c,
   177  		TempDir:         tempDir,
   178  		ExtraFiles:      extraFiles,
   179  		OutputFile:      w,
   180  		BaseArchive:     baseFile,
   181  		UseExistingInit: *useExistingInit,
   182  		InitCmd:         initCommand,
   183  		DefaultShell:    *defaultShell,
   184  	}
   185  	return uroot.CreateInitramfs(logger, opts)
   186  }