github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/bzimage/bzimage.go (about)

     1  // Copyright 2012-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  // bzImage is used to modify bzImage files.
     6  // It reads the image in, applies an operator, and writes a new one out.
     7  //
     8  // Synopsis:
     9  //
    10  //	bzImage [copy <in> <out> ] | [diff <image> <image> ] | [dump <file>] | [initramfs input-bzimage initramfs output-bzimage]
    11  //
    12  // Description:
    13  //
    14  //	Read a bzImage in, change it, write it out, or print info.
    15  package main
    16  
    17  import (
    18  	"encoding/json"
    19  	"flag"
    20  	"fmt"
    21  	"io"
    22  	"log"
    23  	"os"
    24  	"strings"
    25  
    26  	"github.com/mvdan/u-root-coreutils/pkg/boot/bzimage"
    27  	"github.com/mvdan/u-root-coreutils/pkg/uroot/util"
    28  )
    29  
    30  var argcounts = map[string]int{
    31  	"copy":      3,
    32  	"diff":      3,
    33  	"dump":      2,
    34  	"initramfs": 4,
    35  	"extract":   3,
    36  	"ver":       2,
    37  	"cfg":       2,
    38  }
    39  
    40  const usage = `bzimage:
    41  bzimage copy <in> <out>
    42  	Create a copy of <in> at <out>, parsing structures.
    43  bzimage diff <image> <image>
    44  	Compare headers of two kernel images.
    45  bzimage extract <file> <elf-file>
    46  	extract parts of the kernel into separate files with self-
    47  	explainatory extensions .boot, .head, .kern, .tail, .ramfs
    48  bzimage dump <file>
    49      Dumps header.
    50  bzimage initramfs <input-bzimage> <new-initramfs> <output-bzimage>
    51  	Replaces initramfs in input-bzimage, creating output-bzimage.
    52  bzimage ver <image>
    53  	Dump version info similar to 'file <image>'.
    54  bzimage cfg <image>
    55  	Dump embedded config.
    56  
    57  flags`
    58  
    59  var (
    60  	debug   = flag.Bool("d", false, "enable debug printing")
    61  	jsonOut = flag.Bool("j", false, "json output ('ver' subcommand only)")
    62  )
    63  
    64  func run(w io.Writer, args ...string) error {
    65  	if *debug {
    66  		bzimage.Debug = log.Printf
    67  	}
    68  	if len(args) < 2 {
    69  		flag.Usage()
    70  		return nil
    71  	}
    72  	n, ok := argcounts[args[0]]
    73  	if !ok || len(args) != n {
    74  		flag.Usage()
    75  		return nil
    76  	}
    77  
    78  	br := &bzimage.BzImage{}
    79  	var image []byte
    80  	switch args[0] {
    81  	case "diff", "dump", "ver":
    82  		br.NoDecompress = true
    83  		fallthrough
    84  	case "copy", "initramfs", "extract", "cfg":
    85  		var err error
    86  		image, err = os.ReadFile(args[1])
    87  		if err != nil {
    88  			return err
    89  		}
    90  		if err = br.UnmarshalBinary(image); err != nil {
    91  			return err
    92  		}
    93  	}
    94  
    95  	switch args[0] {
    96  	case "copy":
    97  		o, err := br.MarshalBinary()
    98  		if err != nil {
    99  			return err
   100  		}
   101  		if len(image) != len(o) {
   102  			log.Printf("copy: input len is %d, output len is %d, they have to match", len(image), len(o))
   103  			var br2 bzimage.BzImage
   104  			if err = br2.UnmarshalBinary(o); err != nil {
   105  				return err
   106  			}
   107  			fmt.Fprintf(w, "Input: %s\n", strings.Join(br.Header.Show(), "\n\t"))
   108  			fmt.Fprintf(w, "Output: %s\n", strings.Join(br2.Header.Show(), "\n\t"))
   109  			log.Printf("%s", br.Header.Diff(&br2.Header))
   110  			return fmt.Errorf("there is no hope")
   111  		}
   112  		if err := os.WriteFile(args[2], o, 0o666); err != nil {
   113  			return fmt.Errorf("writing %v: %v", args[2], err)
   114  		}
   115  	case "diff":
   116  		b2, err := os.ReadFile(args[2])
   117  		if err != nil {
   118  			return err
   119  		}
   120  		br2 := &bzimage.BzImage{}
   121  		if err = br2.UnmarshalBinary(b2); err != nil {
   122  			return err
   123  		}
   124  		fmt.Fprintf(w, "%s", br.Header.Diff(&br2.Header))
   125  	case "dump":
   126  		fmt.Fprintf(w, "%s\n", strings.Join(br.Header.Show(), "\n"))
   127  	case "extract":
   128  		bzimage.Debug = log.Printf
   129  		var i []byte
   130  		s, e, err := br.InitRAMFS()
   131  		if err != nil {
   132  			fmt.Fprintf(w, "Warning: could not extract initramfs: %v", err)
   133  		} else {
   134  			i = br.KernelCode[s:e]
   135  		}
   136  		// Need to add a trailer record to i
   137  		fmt.Fprintf(w, "ramfs is %d bytes", len(i))
   138  
   139  		for _, v := range []struct {
   140  			n string
   141  			b []byte
   142  		}{
   143  			{args[2] + ".boot", br.BootCode},
   144  			{args[2] + ".head", br.HeadCode},
   145  			{args[2] + ".kern", br.KernelCode},
   146  			{args[2] + ".tail", br.TailCode},
   147  			{args[2] + ".ramfs", i},
   148  		} {
   149  			if v.b == nil {
   150  				fmt.Fprintf(w, "Warning: %s is nil", v.n)
   151  				continue
   152  			}
   153  			if err := os.WriteFile(v.n, v.b, 0o666); err != nil {
   154  				return fmt.Errorf("writing %v: %v", v, err)
   155  			}
   156  		}
   157  	case "initramfs":
   158  		if err := br.AddInitRAMFS(args[2]); err != nil {
   159  			return err
   160  		}
   161  
   162  		b, err := br.MarshalBinary()
   163  		if err != nil {
   164  			return err
   165  		}
   166  
   167  		if err := os.WriteFile(args[3], b, 0o644); err != nil {
   168  			return err
   169  		}
   170  	case "ver":
   171  		v, err := br.KVer()
   172  		if err != nil {
   173  			return err
   174  		}
   175  		if *jsonOut {
   176  			info, err := bzimage.ParseDesc(v)
   177  			if err != nil {
   178  				return err
   179  			}
   180  			j, err := json.MarshalIndent(info, "", "    ")
   181  			if err != nil {
   182  				return err
   183  			}
   184  			fmt.Fprintln(w, string(j))
   185  		} else {
   186  			fmt.Fprintln(w, v)
   187  		}
   188  	case "cfg":
   189  		cfg, err := br.ReadConfig()
   190  		if err != nil {
   191  			return err
   192  		}
   193  		fmt.Fprintf(w, "%s\n", cfg)
   194  	}
   195  	return nil
   196  }
   197  
   198  func main() {
   199  	flag.Usage = util.Usage(flag.Usage, usage)
   200  	flag.Parse()
   201  	if err := run(os.Stdout, flag.Args()...); err != nil {
   202  		log.Fatal(err)
   203  	}
   204  }