github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+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 "runtime" 14 "strings" 15 16 "github.com/u-root/u-root/pkg/golang" 17 "github.com/u-root/u-root/pkg/uroot" 18 "github.com/u-root/u-root/pkg/uroot/builder" 19 "github.com/u-root/u-root/pkg/uroot/initramfs" 20 ) 21 22 // multiFlag is used for flags that support multiple invocations, e.g. -files 23 type multiFlag []string 24 25 func (m *multiFlag) String() string { 26 return fmt.Sprint(*m) 27 } 28 29 func (m *multiFlag) Set(value string) error { 30 *m = append(*m, value) 31 return nil 32 } 33 34 // Flags for u-root builder. 35 var ( 36 build, format, tmpDir, base, outputPath *string 37 initCmd *string 38 defaultShell *string 39 useExistingInit *bool 40 fourbins *bool 41 noCommands *bool 42 extraFiles multiFlag 43 ) 44 45 func init() { 46 fourbins = flag.Bool("fourbins", false, "build installcommand on boot, no ahead of time, so we have only four binares") 47 build = flag.String("build", "source", "u-root build format (e.g. bb or source).") 48 format = flag.String("format", "cpio", "Archival format.") 49 50 tmpDir = flag.String("tmpdir", "", "Temporary directory to put binaries in.") 51 52 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.") 53 useExistingInit = flag.Bool("useinit", false, "Use existing init from base archive (only if --base was specified).") 54 outputPath = flag.String("o", "", "Path to output initramfs file.") 55 56 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.") 57 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.") 58 noCommands = flag.Bool("nocmd", false, "Build no Go commands; initramfs only") 59 60 flag.Var(&extraFiles, "files", "Additional files, directories, and binaries (with their ldd dependencies) to add to archive. Can be speficified multiple times.") 61 } 62 63 func main() { 64 flag.Parse() 65 66 // Main is in a separate functions so defers run on return. 67 if err := Main(); err != nil { 68 log.Fatal(err) 69 } 70 log.Printf("Successfully wrote initramfs.") 71 } 72 73 var recommendedVersions = []string{ 74 "go1.12", 75 "go1.13", 76 } 77 78 func isRecommendedVersion(v string) bool { 79 for _, r := range recommendedVersions { 80 if strings.HasPrefix(v, r) { 81 return true 82 } 83 } 84 return false 85 } 86 87 // Main is a separate function so defers are run on return, which they wouldn't 88 // on exit. 89 func Main() error { 90 env := golang.Default() 91 if *fourbins && env.GOROOT == "" { 92 log.Fatalf("You have to set GOROOT for fourbins to work") 93 } 94 if env.CgoEnabled { 95 log.Printf("Disabling CGO for u-root...") 96 env.CgoEnabled = false 97 } 98 log.Printf("Build environment: %s", env) 99 if env.GOOS != "linux" { 100 log.Printf("GOOS is not linux. Did you mean to set GOOS=linux?") 101 } 102 103 v, err := env.Version() 104 if err != nil { 105 log.Printf("Could not get environment's Go version, using runtime's version: %v", err) 106 v = runtime.Version() 107 } 108 if !isRecommendedVersion(v) { 109 log.Printf(`WARNING: You are not using one of the recommended Go versions (have = %s, recommended = %v). 110 Some packages may not compile. 111 Go to https://golang.org/doc/install to find out how to install a newer version of Go, 112 or use https://godoc.org/golang.org/dl/%s to install an additional version of Go.`, 113 v, recommendedVersions, recommendedVersions[0]) 114 } 115 116 archiver, err := initramfs.GetArchiver(*format) 117 if err != nil { 118 return err 119 } 120 121 logger := log.New(os.Stderr, "", log.LstdFlags) 122 // Open the target initramfs file. 123 w, err := archiver.OpenWriter(logger, *outputPath, env.GOOS, env.GOARCH) 124 if err != nil { 125 return err 126 } 127 128 var baseFile initramfs.Reader 129 if *base != "" { 130 bf, err := os.Open(*base) 131 if err != nil { 132 return err 133 } 134 defer bf.Close() 135 baseFile = archiver.Reader(bf) 136 } else { 137 baseFile = uroot.DefaultRamfs.Reader() 138 } 139 140 tempDir := *tmpDir 141 if tempDir == "" { 142 var err error 143 tempDir, err = ioutil.TempDir("", "u-root") 144 if err != nil { 145 return err 146 } 147 defer os.RemoveAll(tempDir) 148 } else if _, err := os.Stat(tempDir); os.IsNotExist(err) { 149 if err := os.MkdirAll(tempDir, 0755); err != nil { 150 return fmt.Errorf("temporary directory %q did not exist; tried to mkdir but failed: %v", tempDir, err) 151 } 152 } 153 154 var ( 155 c []uroot.Commands 156 initCommand = *initCmd 157 ) 158 if !*noCommands { 159 var b builder.Builder 160 switch *build { 161 case "bb": 162 b = builder.BBBuilder{} 163 case "binary": 164 b = builder.BinaryBuilder{} 165 case "source": 166 b = builder.SourceBuilder{ 167 FourBins: *fourbins, 168 } 169 default: 170 return fmt.Errorf("could not find builder %q", *build) 171 } 172 173 // Resolve globs into package imports. 174 // 175 // Currently allowed formats: 176 // Go package imports; e.g. github.com/u-root/u-root/cmds/ls (must be in $GOPATH) 177 // Paths to Go package directories; e.g. $GOPATH/src/github.com/u-root/u-root/cmds/* 178 var pkgs []string 179 for _, a := range flag.Args() { 180 p, ok := templates[a] 181 if !ok { 182 pkgs = append(pkgs, a) 183 continue 184 } 185 pkgs = append(pkgs, p...) 186 } 187 if len(pkgs) == 0 { 188 pkgs = []string{"github.com/u-root/u-root/cmds/core/*"} 189 } 190 191 if *fourbins && *build == "source" { 192 initCommand = "/go/bin/go" 193 } 194 195 // The command-line tool only allows specifying one build mode 196 // right now. 197 c = append(c, uroot.Commands{ 198 Builder: b, 199 Packages: pkgs, 200 }) 201 } 202 203 opts := uroot.Opts{ 204 Env: env, 205 Commands: c, 206 TempDir: tempDir, 207 ExtraFiles: extraFiles, 208 OutputFile: w, 209 BaseArchive: baseFile, 210 UseExistingInit: *useExistingInit, 211 InitCmd: initCommand, 212 DefaultShell: *defaultShell, 213 } 214 return uroot.CreateInitramfs(logger, opts) 215 }