diff --git a/.circleci/config.yml b/.circleci/config.yml index 47e6dff76c..3d69fa3e96 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,18 +67,11 @@ jobs: name: Ensure that every template builds for a variety of options. command: | go build . - goruncmd="./u-root -stats-output-path=/tmp/stats.json" + goruncmd="./u-root" $goruncmd minimal $goruncmd core $goruncmd coreboot-app $goruncmd all $goruncmd world - # Fails because of dups. Is this supposed to work? - #$goruncmd all core - #$goruncmd all core + $goruncmd all core GOOS=plan9 $goruncmd -defaultsh=/bbin/rush plan9 - cat /tmp/stats.json - - store_artifacts: - name: Store build stats - path: /tmp/stats.json - destination: stats.json diff --git a/templates.go b/templates.go deleted file mode 100644 index a517e67097..0000000000 --- a/templates.go +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2015-2020 the u-root Authors. All rights reserved -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -// TODO: make templates able to include other templates. -// e.g. "all" below should just say "core" and "boot". Use it to replace -// the old 'systemboot' template. -// Or just call it a day, now that we have the new directory structure, and dump the templates -// completely; that may be our best bet. -var templates = map[string][]string{ - "all": { - "github.com/u-root/u-root/cmds/core/*", - "github.com/u-root/u-root/cmds/boot/*boot*", - }, - "boot": { - "github.com/u-root/u-root/cmds/boot/*boot*", - }, - // Absolutely everything, including experimental commands. - "world": { - "github.com/u-root/u-root/cmds/*/*", - }, - // Core should be things you don't want to live without. - "core": { - "github.com/u-root/u-root/cmds/core/*", - }, - // Minimal should be things you can't live without. - "minimal": { - "github.com/u-root/u-root/cmds/core/blkid", - "github.com/u-root/u-root/cmds/core/cat", - "github.com/u-root/u-root/cmds/core/chmod", - "github.com/u-root/u-root/cmds/core/cmp", - "github.com/u-root/u-root/cmds/core/cp", - "github.com/u-root/u-root/cmds/core/date", - "github.com/u-root/u-root/cmds/core/dd", - "github.com/u-root/u-root/cmds/core/df", - "github.com/u-root/u-root/cmds/core/dhclient", - "github.com/u-root/u-root/cmds/core/dmesg", - "github.com/u-root/u-root/cmds/core/echo", - "github.com/u-root/u-root/cmds/core/find", - "github.com/u-root/u-root/cmds/core/free", - "github.com/u-root/u-root/cmds/core/gosh", - "github.com/u-root/u-root/cmds/core/gpgv", - "github.com/u-root/u-root/cmds/core/grep", - "github.com/u-root/u-root/cmds/core/gzip", - "github.com/u-root/u-root/cmds/core/hostname", - "github.com/u-root/u-root/cmds/core/id", - "github.com/u-root/u-root/cmds/core/init", - "github.com/u-root/u-root/cmds/core/insmod", - "github.com/u-root/u-root/cmds/core/io", - "github.com/u-root/u-root/cmds/core/ip", - "github.com/u-root/u-root/cmds/core/kexec", - "github.com/u-root/u-root/cmds/core/kill", - "github.com/u-root/u-root/cmds/core/ln", - "github.com/u-root/u-root/cmds/core/losetup", - "github.com/u-root/u-root/cmds/core/ls", - "github.com/u-root/u-root/cmds/core/lsmod", - "github.com/u-root/u-root/cmds/core/mkdir", - "github.com/u-root/u-root/cmds/core/mknod", - "github.com/u-root/u-root/cmds/core/mount", - "github.com/u-root/u-root/cmds/core/msr", - "github.com/u-root/u-root/cmds/core/mv", - "github.com/u-root/u-root/cmds/core/pci", - "github.com/u-root/u-root/cmds/core/ping", - "github.com/u-root/u-root/cmds/core/printenv", - "github.com/u-root/u-root/cmds/core/ps", - "github.com/u-root/u-root/cmds/core/pwd", - "github.com/u-root/u-root/cmds/core/readlink", - "github.com/u-root/u-root/cmds/core/rm", - "github.com/u-root/u-root/cmds/core/rmmod", - "github.com/u-root/u-root/cmds/core/seq", - "github.com/u-root/u-root/cmds/core/shutdown", - "github.com/u-root/u-root/cmds/core/sleep", - "github.com/u-root/u-root/cmds/core/sync", - "github.com/u-root/u-root/cmds/core/tail", - "github.com/u-root/u-root/cmds/core/tee", - "github.com/u-root/u-root/cmds/core/truncate", - "github.com/u-root/u-root/cmds/core/umount", - "github.com/u-root/u-root/cmds/core/uname", - "github.com/u-root/u-root/cmds/core/unshare", - "github.com/u-root/u-root/cmds/core/wc", - "github.com/u-root/u-root/cmds/core/wget", - "github.com/u-root/u-root/cmds/core/which", - }, - // embedded systems, like ARM based gadgets and SBCs - "embedded": { - "github.com/u-root/u-root/cmds/core/cat", - "github.com/u-root/u-root/cmds/core/cp", - "github.com/u-root/u-root/cmds/core/dd", - "github.com/u-root/u-root/cmds/core/dhclient", - "github.com/u-root/u-root/cmds/core/dmesg", - "github.com/u-root/u-root/cmds/core/echo", - "github.com/u-root/u-root/cmds/core/free", - "github.com/u-root/u-root/cmds/core/gosh", - "github.com/u-root/u-root/cmds/core/grep", - "github.com/u-root/u-root/cmds/core/init", - "github.com/u-root/u-root/cmds/core/insmod", - "github.com/u-root/u-root/cmds/core/ip", - "github.com/u-root/u-root/cmds/core/kexec", - "github.com/u-root/u-root/cmds/core/ln", - "github.com/u-root/u-root/cmds/core/ls", - "github.com/u-root/u-root/cmds/core/mkdir", - "github.com/u-root/u-root/cmds/core/mount", - "github.com/u-root/u-root/cmds/core/netcat", - "github.com/u-root/u-root/cmds/core/ping", - "github.com/u-root/u-root/cmds/core/rm", - "github.com/u-root/u-root/cmds/core/rmmod", - "github.com/u-root/u-root/cmds/core/shutdown", - "github.com/u-root/u-root/cmds/core/tail", - "github.com/u-root/u-root/cmds/core/tee", - "github.com/u-root/u-root/cmds/core/uname", - "github.com/u-root/u-root/cmds/core/wget", - }, - // coreboot-app minimal environment - "coreboot-app": { - "github.com/u-root/u-root/cmds/core/cat", - "github.com/u-root/u-root/cmds/exp/cbmem", - "github.com/u-root/u-root/cmds/core/chroot", - "github.com/u-root/u-root/cmds/core/cp", - "github.com/u-root/u-root/cmds/core/dd", - "github.com/u-root/u-root/cmds/core/dhclient", - "github.com/u-root/u-root/cmds/core/dmesg", - "github.com/u-root/u-root/cmds/core/find", - "github.com/u-root/u-root/cmds/core/gosh", - "github.com/u-root/u-root/cmds/core/grep", - "github.com/u-root/u-root/cmds/core/id", - "github.com/u-root/u-root/cmds/core/init", - "github.com/u-root/u-root/cmds/core/insmod", - "github.com/u-root/u-root/cmds/core/ip", - "github.com/u-root/u-root/cmds/core/kill", - "github.com/u-root/u-root/cmds/core/ls", - "github.com/u-root/u-root/cmds/core/mount", - "github.com/u-root/u-root/cmds/core/pci", - "github.com/u-root/u-root/cmds/core/ping", - "github.com/u-root/u-root/cmds/core/ps", - "github.com/u-root/u-root/cmds/core/pwd", - "github.com/u-root/u-root/cmds/core/rm", - "github.com/u-root/u-root/cmds/core/rmmod", - "github.com/u-root/u-root/cmds/core/shutdown", - "github.com/u-root/u-root/cmds/core/sshd", - "github.com/u-root/u-root/cmds/core/switch_root", - "github.com/u-root/u-root/cmds/core/tail", - "github.com/u-root/u-root/cmds/core/tee", - "github.com/u-root/u-root/cmds/core/uname", - "github.com/u-root/u-root/cmds/core/wget", - }, - "plan9": { - "github.com/u-root/u-root/cmds/core/*", - }, - // For a command to be uncommented, - // tinygo test should work on linux and darwin. - "tinygo": { - "github.com/u-root/u-root/cmds/core/backoff", - "github.com/u-root/u-root/cmds/core/base64", - "github.com/u-root/u-root/cmds/core/basename", - ////"github.com/u-root/u-root/cmds/core/bind", - //"github.com/u-root/u-root/cmds/core/blkid", - "github.com/u-root/u-root/cmds/core/cat", - "github.com/u-root/u-root/cmds/core/chmod", - //"github.com/u-root/u-root/cmds/core/chroot", credentials problem - "github.com/u-root/u-root/cmds/core/cmp", - "github.com/u-root/u-root/cmds/core/comm", - "github.com/u-root/u-root/cmds/core/cp", - //////"github.com/u-root/u-root/cmds/core/cpio", build constraints problem - "github.com/u-root/u-root/cmds/core/date", - "github.com/u-root/u-root/cmds/core/dd", - //////"github.com/u-root/u-root/cmds/core/df", - //////"github.com/u-root/u-root/cmds/core/dhclient", - "github.com/u-root/u-root/cmds/core/dirname", - //////"github.com/u-root/u-root/cmds/core/dmesg", - "github.com/u-root/u-root/cmds/core/echo", - //////"github.com/u-root/u-root/cmds/core/elvish", - "github.com/u-root/u-root/cmds/core/false", - //"github.com/u-root/u-root/cmds/core/find", - "github.com/u-root/u-root/cmds/core/free", - //"github.com/u-root/u-root/cmds/core/fusermount", - //////"github.com/u-root/u-root/cmds/core/gosh", - //"github.com/u-root/u-root/cmds/core/gpgv", - "github.com/u-root/u-root/cmds/core/gpt", - "github.com/u-root/u-root/cmds/core/grep", - //"github.com/u-root/u-root/cmds/core/gzip", - "github.com/u-root/u-root/cmds/core/hexdump", - //////"github.com/u-root/u-root/cmds/core/hostname", - //"github.com/u-root/u-root/cmds/core/hwclock", - //"github.com/u-root/u-root/cmds/core/id", - //////"github.com/u-root/u-root/cmds/core/init", - //"github.com/u-root/u-root/cmds/core/insmod", - //////"github.com/u-root/u-root/cmds/core/io", - //"github.com/u-root/u-root/cmds/core/ip", - //"github.com/u-root/u-root/cmds/core/kexec", - "github.com/u-root/u-root/cmds/core/kill", - //"github.com/u-root/u-root/cmds/core/lddfiles", - //"github.com/u-root/u-root/cmds/core/ln", - //"github.com/u-root/u-root/cmds/core/lockmsrs", - //"github.com/u-root/u-root/cmds/core/losetup", - "github.com/u-root/u-root/cmds/core/ls", - //"github.com/u-root/u-root/cmds/core/lsdrivers", - //"github.com/u-root/u-root/cmds/core/lsmod", - //"github.com/u-root/u-root/cmds/core/man", - //"github.com/u-root/u-root/cmds/core/md5sum", - "github.com/u-root/u-root/cmds/core/mkdir", - //////"github.com/u-root/u-root/cmds/core/mkfifo", - //////"github.com/u-root/u-root/cmds/core/mknod", - //"github.com/u-root/u-root/cmds/core/mktemp", - "github.com/u-root/u-root/cmds/core/more", - //"github.com/u-root/u-root/cmds/core/mount", - //"github.com/u-root/u-root/cmds/core/msr", - "github.com/u-root/u-root/cmds/core/mv", - //"github.com/u-root/u-root/cmds/core/netcat", - //////"github.com/u-root/u-root/cmds/core/ntpdate", - //"github.com/u-root/u-root/cmds/core/pci", - //"github.com/u-root/u-root/cmds/core/ping", - //"github.com/u-root/u-root/cmds/core/poweroff", - //"github.com/u-root/u-root/cmds/core/printenv", - "github.com/u-root/u-root/cmds/core/ps", - "github.com/u-root/u-root/cmds/core/pwd", - //"github.com/u-root/u-root/cmds/core/readlink", - "github.com/u-root/u-root/cmds/core/rm", - //"github.com/u-root/u-root/cmds/core/rmmod", - //"github.com/u-root/u-root/cmds/core/rsdp", - //"github.com/u-root/u-root/cmds/core/scp", - //"github.com/u-root/u-root/cmds/core/seq", - //"github.com/u-root/u-root/cmds/core/shasum", - //"github.com/u-root/u-root/cmds/core/shutdown", - //"github.com/u-root/u-root/cmds/core/sleep", - //"github.com/u-root/u-root/cmds/core/sluinit", - "github.com/u-root/u-root/cmds/core/sort", - //////"github.com/u-root/u-root/cmds/core/sshd", - //////"github.com/u-root/u-root/cmds/core/strace", - //"github.com/u-root/u-root/cmds/core/strings", - //////"github.com/u-root/u-root/cmds/core/stty", - //////"github.com/u-root/u-root/cmds/core/switch_root", - //"github.com/u-root/u-root/cmds/core/sync", - //"github.com/u-root/u-root/cmds/core/tail", - //"github.com/u-root/u-root/cmds/core/tar", - //"github.com/u-root/u-root/cmds/core/tee", - //"github.com/u-root/u-root/cmds/core/time", - //"github.com/u-root/u-root/cmds/core/timeout", - "github.com/u-root/u-root/cmds/core/tr", - "github.com/u-root/u-root/cmds/core/true", - //"github.com/u-root/u-root/cmds/core/truncate", - //"github.com/u-root/u-root/cmds/core/ts", - //"github.com/u-root/u-root/cmds/core/umount", - //////"github.com/u-root/u-root/cmds/core/uname", - "github.com/u-root/u-root/cmds/core/uniq", - //"github.com/u-root/u-root/cmds/core/unmount", - //"github.com/u-root/u-root/cmds/core/unshare", - //"github.com/u-root/u-root/cmds/core/uptime", - //"github.com/u-root/u-root/cmds/core/watchdog", - //"github.com/u-root/u-root/cmds/core/watchdogd", - "github.com/u-root/u-root/cmds/core/wc", - //"github.com/u-root/u-root/cmds/core/wget", - //////"github.com/u-root/u-root/cmds/core/which", - "github.com/u-root/u-root/cmds/core/yes", - //// One of these commands in exp tickles a busybox bug. - ////"github.com/u-root/u-root/cmds/exp/acpicat", - ////"github.com/u-root/u-root/cmds/exp/acpigrep", - ////"github.com/u-root/u-root/cmds/exp/ansi", - ////"github.com/u-root/u-root/cmds/exp/bootvars", - ////"github.com/u-root/u-root/cmds/exp/bzimage", - ////"github.com/u-root/u-root/cmds/exp/cbmem", - ////"github.com/u-root/u-root/cmds/exp/console", - ////"github.com/u-root/u-root/cmds/exp/crc", - ////"github.com/u-root/u-root/cmds/exp/disk_unlock", - ////"github.com/u-root/u-root/cmds/exp/dmidecode", - ////"github.com/u-root/u-root/cmds/exp/dumpebda", - ////"github.com/u-root/u-root/cmds/exp/ectool", - ////"github.com/u-root/u-root/cmds/exp/ed", - ////"github.com/u-root/u-root/cmds/exp/efivarfs", - ////"github.com/u-root/u-root/cmds/exp/esxiboot", - ////"github.com/u-root/u-root/cmds/exp/fbsplash", - ////"github.com/u-root/u-root/cmds/exp/fdtdump", - ////"github.com/u-root/u-root/cmds/exp/field", - ////"github.com/u-root/u-root/cmds/exp/fixrsdp", - ////"github.com/u-root/u-root/cmds/exp/forth", - ////"github.com/u-root/u-root/cmds/exp/freq", - ////"github.com/u-root/u-root/cmds/exp/getty", - ////"github.com/u-root/u-root/cmds/exp/gosh", - ////"github.com/u-root/u-root/cmds/exp/hdparm", - ////"github.com/u-root/u-root/cmds/exp/ipmidump", - ////"github.com/u-root/u-root/cmds/exp/kconf", - ////"github.com/u-root/u-root/cmds/exp/lsfabric", - ////"github.com/u-root/u-root/cmds/exp/madeye", - ////"github.com/u-root/u-root/cmds/exp/modprobe", - ////"github.com/u-root/u-root/cmds/exp/netbootxyz", - ////"github.com/u-root/u-root/cmds/exp/newsshd", - ////"github.com/u-root/u-root/cmds/exp/nvme_unlock", - ////"github.com/u-root/u-root/cmds/exp/page", - ////"github.com/u-root/u-root/cmds/exp/partprobe", - ////"github.com/u-root/u-root/cmds/exp/pflask", - ////"github.com/u-root/u-root/cmds/exp/pox", - ////"github.com/u-root/u-root/cmds/exp/pxeserver", - ////"github.com/u-root/u-root/cmds/exp/readpe", - ////"github.com/u-root/u-root/cmds/exp/run", - ////"github.com/u-root/u-root/cmds/exp/rush", - ////"github.com/u-root/u-root/cmds/exp/smbios_transfer", - ////"github.com/u-root/u-root/cmds/exp/smn", - ////"github.com/u-root/u-root/cmds/exp/srvfiles", - ////"github.com/u-root/u-root/cmds/exp/ssh", - //////"github.com/u-root/u-root/cmds/exp/syscallfilter", - ////"github.com/u-root/u-root/cmds/exp/tac", - ////"github.com/u-root/u-root/cmds/exp/tcz", - ////"github.com/u-root/u-root/cmds/exp/uefiboot", - ////"github.com/u-root/u-root/cmds/exp/vboot", - ////"github.com/u-root/u-root/cmds/exp/watch", - ////"github.com/u-root/u-root/cmds/exp/zbi", - ////"github.com/u-root/u-root/cmds/exp/zimage", - }, -} diff --git a/u-root.go b/u-root.go index 7b5d38e3c0..ea6934b16a 100644 --- a/u-root.go +++ b/u-root.go @@ -2,154 +2,28 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Command u-root builds CPIO archives with the given files and Go commands. package main import ( - "encoding/json" "errors" "flag" "fmt" "log" + "log/slog" "os" - "path" - "path/filepath" - "runtime" - "sort" - "strings" - "time" + "github.com/dustin/go-humanize" "github.com/u-root/gobusybox/src/pkg/golang" - "github.com/u-root/gobusybox/src/pkg/uflag" - "github.com/u-root/u-root/pkg/shlex" - "github.com/u-root/u-root/pkg/ulog" - "github.com/u-root/u-root/pkg/uroot" - "github.com/u-root/u-root/pkg/uroot/builder" - "github.com/u-root/u-root/pkg/uroot/initramfs" + "github.com/u-root/mkuimage/uimage" + "github.com/u-root/mkuimage/uimage/mkuimage" + "github.com/u-root/uio/llog" ) -// multiFlag is used for flags that support multiple invocations, e.g. -files -type multiFlag []string - -func (m *multiFlag) String() string { - return fmt.Sprint(*m) -} - -func (m *multiFlag) Set(value string) error { - *m = append(*m, value) - return nil -} - -// errors from the u-root command var ( - ErrEmptyFilesArg = errors.New("empty argument to -files") + errEmptyFilesArg = errors.New("empty argument to -files") ) -// Flags for u-root builder. -var ( - build, format, tmpDir, base, outputPath *string - uinitCmd, initCmd *string - defaultShell *string - useExistingInit *bool - noCommands *bool - extraFiles multiFlag - statsOutputPath *string - statsLabel *string - shellbang *bool - // For the new gobusybox support - usegobusybox *bool - genDir *string - // For the new "filepath only" logic - urootSourceDir *string -) - -func init() { - var sh string - switch golang.Default().GOOS { - case "plan9": - sh = "" - default: - sh = "gosh" - } - - build = flag.String("build", "gbb", "u-root build format (e.g. bb/gbb or binary).") - format = flag.String("format", "cpio", "Archival format.") - - tmpDir = flag.String("tmpdir", "", "Temporary directory to put binaries in.") - - 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.") - useExistingInit = flag.Bool("useinit", false, "Use existing init from base archive (only if --base was specified).") - outputPath = flag.String("o", "", "Path to output initramfs file.") - - 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.") - uinitCmd = flag.String("uinitcmd", "", "Symlink target and arguments for /bin/uinit. Can be an absolute path or a u-root command name. Use uinitcmd=\"\" if you don't want the symlink. E.g. -uinitcmd=\"echo foobar\"") - defaultShell = flag.String("defaultsh", sh, "Default shell. Can be an absolute path or a u-root command name. Use defaultsh=\"\" if you don't want the symlink.") - - noCommands = flag.Bool("nocmd", false, "Build no Go commands; initramfs only") - - flag.Var(&extraFiles, "files", "Additional files, directories, and binaries (with their ldd dependencies) to add to archive. Can be specified multiple times.") - - shellbang = flag.Bool("shellbang", false, "Use #! instead of symlinks for busybox") - - statsOutputPath = flag.String("stats-output-path", "", "Write build stats to this file (JSON)") - statsLabel = flag.String("stats-label", "", "Use this statsLabel when writing stats") - - // Flags for the gobusybox, which we hope to move to, since it works with modules. - genDir = flag.String("gen-dir", "", "Directory to generate source in") - - // Flag for the new filepath only mode. This will be required to find the u-root commands and make templates work - // In almost every case, "." is fine. - urootSourceDir = flag.String("uroot-source", ".", "Path to the locally checked out u-root source tree in case commands from there are desired.") -} - -type buildStats struct { - Label string `json:"label,omitempty"` - Time int64 `json:"time"` - Duration float64 `json:"duration"` - OutputSize int64 `json:"output_size"` -} - -func writeBuildStats(stats buildStats, path string) error { - var allStats []buildStats - if data, err := os.ReadFile(*statsOutputPath); err == nil { - json.Unmarshal(data, &allStats) - } - found := false - for i, s := range allStats { - if s.Label == stats.Label { - allStats[i] = stats - found = true - break - } - } - if !found { - allStats = append(allStats, stats) - sort.Slice(allStats, func(i, j int) bool { - return strings.Compare(allStats[i].Label, allStats[j].Label) == -1 - }) - } - data, err := json.MarshalIndent(allStats, "", " ") - if err != nil { - return err - } - if err := os.WriteFile(*statsOutputPath, data, 0o644); err != nil { - return err - } - return nil -} - -func generateLabel(env *golang.Environ) string { - var baseCmds []string - if len(flag.Args()) > 0 { - // Use the last component of the name to keep the label short - for _, e := range flag.Args() { - baseCmds = append(baseCmds, path.Base(e)) - } - } else { - baseCmds = []string{"core"} - } - return fmt.Sprintf("%s-%s-%s-%s", *build, env.GOOS, env.GOARCH, strings.Join(baseCmds, "_")) -} - // checkArgs checks for common mistakes that cause confusion. // 1. -files as the last argument // 2. -files followed by any switch, indicating a shell expansion problem @@ -166,14 +40,14 @@ func checkArgs(args ...string) error { } if args[len(args)-1] == "-files" { - return fmt.Errorf("last argument is -files:%w", ErrEmptyFilesArg) + return fmt.Errorf("last argument is -files:%w", errEmptyFilesArg) } // We know the last arg is not -files; scan the arguments for -files // followed by a switch. for i := 0; i < len(args)-1; i++ { if args[i] == "-files" && args[i+1][0] == '-' { - return fmt.Errorf("-files argument %d is followed by a switch: %w", i, ErrEmptyFilesArg) + return fmt.Errorf("-files argument %d is followed by a switch: %w", i, errEmptyFilesArg) } } @@ -181,249 +55,58 @@ func checkArgs(args ...string) error { } func main() { + log.SetFlags(log.Ltime) if err := checkArgs(os.Args...); err != nil { log.Fatal(err) } - gbbOpts := &golang.BuildOpts{} - gbbOpts.RegisterFlags(flag.CommandLine) - // Register an alias for -go-no-strip for backwards compatibility. - flag.CommandLine.BoolVar(&gbbOpts.NoStrip, "no-strip", false, "Build unstripped binaries") - - env := golang.Default() - env.RegisterFlags(flag.CommandLine) - tags := (*uflag.Strings)(&env.BuildTags) - flag.CommandLine.Var(tags, "tags", "Go build tags -- repeat the flag for multiple values") - - flag.Parse() - - l := log.New(os.Stderr, "", log.Ltime) - - if usrc := os.Getenv("UROOT_SOURCE"); usrc != "" && *urootSourceDir == "" { - *urootSourceDir = usrc - } - - if env.CgoEnabled { - l.Printf("Disabling CGO for u-root...") - env.CgoEnabled = false - } - l.Printf("Build environment: %s", env) - if env.GOOS != "linux" { - l.Printf("GOOS is not linux. Did you mean to set GOOS=linux?") - } - - start := time.Now() - - // Main is in a separate functions so defers run on return. - if err := Main(l, env, gbbOpts); err != nil { - l.Fatalf("Build error: %v", err) - } - - elapsed := time.Now().Sub(start) - - stats := buildStats{ - Label: *statsLabel, - Time: start.Unix(), - Duration: float64(elapsed.Milliseconds()) / 1000, - } - if stats.Label == "" { - stats.Label = generateLabel(env) - } - if stat, err := os.Stat(*outputPath); err == nil && stat.ModTime().After(start) { - l.Printf("Successfully built %q (size %d).", *outputPath, stat.Size()) - stats.OutputSize = stat.Size() - if *statsOutputPath != "" { - if err := writeBuildStats(stats, *statsOutputPath); err == nil { - l.Printf("Wrote stats to %q (label %q)", *statsOutputPath, stats.Label) - } else { - l.Printf("Failed to write stats to %s: %v", *statsOutputPath, err) - } - } - } -} - -var recommendedVersions = []string{ - "go1.20", - "go1.21", -} - -func isRecommendedVersion(v string) bool { - for _, r := range recommendedVersions { - if strings.HasPrefix(v, r) { - return true - } - } - return false -} - -func canFindSource(dir string) error { - d := filepath.Join(dir, "cmds", "core") - if _, err := os.Stat(d); err != nil { - return fmt.Errorf("can not build u-root in %q:%w (-uroot-source may be incorrect or not set)", *urootSourceDir, os.ErrNotExist) - } - return nil -} - -// Main is a separate function so defers are run on return, which they wouldn't -// on exit. -func Main(l ulog.Logger, env *golang.Environ, buildOpts *golang.BuildOpts) error { - v, err := env.Version() - if err != nil { - l.Printf("Could not get environment's Go version, using runtime's version: %v", err) - v = runtime.Version() - } - if !isRecommendedVersion(v) { - l.Printf(`WARNING: You are not using one of the recommended Go versions (have = %s, recommended = %v). - Some packages may not compile. - Go to https://golang.org/doc/install to find out how to install a newer version of Go, - or use https://godoc.org/golang.org/dl/%s to install an additional version of Go.`, - v, recommendedVersions, recommendedVersions[0]) - } - - archiver, err := initramfs.GetArchiver(*format) - if err != nil { - return err + env := golang.Default(golang.DisableCGO()) + f := &mkuimage.Flags{ + Commands: mkuimage.CommandFlags{Builder: "bb"}, + ArchiveFormat: "cpio", + OutputFile: defaultFile(env), } + f.RegisterFlags(flag.CommandLine) - // Open the target initramfs file. - if *outputPath == "" { - if len(env.GOOS) == 0 && len(env.GOARCH) == 0 { - return fmt.Errorf("passed no path, GOOS, and GOARCH to CPIOArchiver.OpenWriter") - } - *outputPath = fmt.Sprintf("/tmp/initramfs.%s_%s.cpio", env.GOOS, env.GOARCH) - } - w, err := archiver.OpenWriter(l, *outputPath) - if err != nil { - return err - } + l := llog.Default() + l.RegisterVerboseFlag(flag.CommandLine, "v", slog.LevelDebug) - var baseFile initramfs.Reader - if *base != "" { - bf, err := os.Open(*base) - if err != nil { - return err - } - defer bf.Close() - baseFile = archiver.Reader(bf) - } else { - baseFile = uroot.DefaultRamfs().Reader() - } + tf := &mkuimage.TemplateFlags{} + tf.RegisterFlags(flag.CommandLine) + flag.Parse() - tempDir := *tmpDir - if tempDir == "" { - var err error - tempDir, err = os.MkdirTemp("", "u-root") - if err != nil { - return err - } - defer os.RemoveAll(tempDir) - } else if _, err := os.Stat(tempDir); os.IsNotExist(err) { - if err := os.MkdirAll(tempDir, 0o755); err != nil { - return fmt.Errorf("temporary directory %q did not exist; tried to mkdir but failed: %v", tempDir, err) - } + // Set defaults. + m := []uimage.Modifier{ + uimage.WithReplaceEnv(env), + uimage.WithBaseArchive(uimage.DefaultRamfs()), + uimage.WithCPIOOutput(defaultFile(env)), + uimage.WithInit("init"), } - - var ( - c []uroot.Commands - initCommand = *initCmd - ) - if !*noCommands { - var b builder.Builder - switch *build { - case "bb", "gbb": - l.Printf("NOTE: building with the new gobusybox; to get the old behavior check out commit 8b790de") - b = builder.GBBBuilder{ShellBang: *shellbang} - case "binary": - b = builder.BinaryBuilder{} - case "source": - return fmt.Errorf("source mode has been deprecated") - default: - return fmt.Errorf("could not find builder %q", *build) - } - - // Resolve globs into package imports. - // - // Currently allowed format: - // Paths to Go package directories; e.g. $GOPATH/src/github.com/u-root/u-root/cmds/* - // u-root templates; e.g. all, core, minimal (requires uroot-source be valid) - // Import paths of u-root commands; e.g. github.com/u-root/u-root/cmds/* (requires uroot-source) - var pkgs []string - for _, a := range flag.Args() { - p, ok := templates[a] - if !ok { - if !validateArg(a) { - l.Printf("%q is not a valid path, allowed are only existing relative or absolute file paths!", a) - continue - } - pkgs = append(pkgs, a) - continue - } - pkgs = append(pkgs, p...) - } - if len(pkgs) == 0 { - pkgs = []string{"github.com/u-root/u-root/cmds/core/*"} - } - - // The command-line tool only allows specifying one build mode - // right now. - c = append(c, uroot.Commands{ - Builder: b, - Packages: pkgs, - }) + if golang.Default().GOOS != "plan9" { + m = append(m, uimage.WithShell("gosh")) } - opts := uroot.Opts{ - Env: env, - Commands: c, - UrootSource: *urootSourceDir, - TempDir: tempDir, - ExtraFiles: extraFiles, - OutputFile: w, - BaseArchive: baseFile, - UseExistingInit: *useExistingInit, - InitCmd: initCommand, - DefaultShell: *defaultShell, - BuildOpts: buildOpts, + pkgs := flag.Args() + // Only add default packages if no config template was given. + // + // Otherwise, the template can't erase the default packages and all + // templates would be forced to use cmds/core/*. + if len(pkgs) == 0 && tf.Config == "" { + pkgs = []string{"github.com/u-root/u-root/cmds/core/*"} } - uinitArgs := shlex.Argv(*uinitCmd) - if len(uinitArgs) > 0 { - opts.UinitCmd = uinitArgs[0] + if err := mkuimage.CreateUimage(l, m, tf, f, pkgs); err != nil { + l.Errorf("mkuimage error: %v", err) + os.Exit(1) } - if len(uinitArgs) > 1 { - opts.UinitArgs = uinitArgs[1:] - } - return uroot.CreateInitramfs(l, opts) -} -func validateArg(arg string) bool { - // Do the simple thing first: stat the path. - // This saves incorrect diagnostics when the - // path is a perfectly valid relative path. - if _, err := os.Stat(arg); err == nil { - return true + if stat, err := os.Stat(f.OutputFile); err == nil && f.ArchiveFormat == "cpio" { + l.Infof("Successfully built %q (size %d bytes -- %s).", f.OutputFile, stat.Size(), humanize.IBytes(uint64(stat.Size()))) } - if !checkPrefix(arg) { - paths, err := filepath.Glob(arg) - if err != nil { - return false - } - for _, path := range paths { - if !checkPrefix(path) { - return false - } - } - } - - return true } -func checkPrefix(arg string) bool { - prefixes := []string{".", "/", "-", "cmds", "github.com/u-root/u-root"} - for _, prefix := range prefixes { - if strings.HasPrefix(arg, prefix) { - return true - } +func defaultFile(env *golang.Environ) string { + if len(env.GOOS) == 0 || len(env.GOARCH) == 0 { + return "/tmp/initramfs.cpio" } - - return false + return fmt.Sprintf("/tmp/initramfs.%s_%s.cpio", env.GOOS, env.GOARCH) } diff --git a/uroot_test.go b/uroot_test.go index cadc8fc546..95a3698552 100644 --- a/uroot_test.go +++ b/uroot_test.go @@ -357,9 +357,9 @@ func TestCheckArgs(t *testing.T) { args []string err error }{ - {"-files is only arg", []string{"-files"}, ErrEmptyFilesArg}, - {"-files followed by -files", []string{"-files", "-files"}, ErrEmptyFilesArg}, - {"-files followed by any other switch", []string{"-files", "-abc"}, ErrEmptyFilesArg}, + {"-files is only arg", []string{"-files"}, errEmptyFilesArg}, + {"-files followed by -files", []string{"-files", "-files"}, errEmptyFilesArg}, + {"-files followed by any other switch", []string{"-files", "-abc"}, errEmptyFilesArg}, {"no args", []string{}, nil}, {"u-root alone", []string{"u-root"}, nil}, {"u-root with -files and other args", []string{"u-root", "-files", "/bin/bash", "core"}, nil},