github.com/jlowellwofford/u-root@v1.0.0/pkg/boot/linux.go (about)

     1  // Copyright 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 boot
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"log"
    13  	"os"
    14  
    15  	"github.com/u-root/u-root/pkg/cpio"
    16  	"github.com/u-root/u-root/pkg/kexec"
    17  	"github.com/u-root/u-root/pkg/uio"
    18  )
    19  
    20  // ErrKernelMissing is returned by LinuxImage.Pack if no kernel is given.
    21  var ErrKernelMissing = errors.New("must have non-nil kernel")
    22  
    23  // LinuxImage implements OSImage for a Linux kernel + initramfs.
    24  type LinuxImage struct {
    25  	Kernel  io.ReaderAt
    26  	Initrd  io.ReaderAt
    27  	Cmdline string
    28  }
    29  
    30  var _ OSImage = &LinuxImage{}
    31  
    32  // NewLinuxImageFromArchive reads a netboot21 Linux OSImage from a CPIO file
    33  // archive.
    34  func NewLinuxImageFromArchive(a *cpio.Archive) (*LinuxImage, error) {
    35  	kernel, ok := a.Files["modules/kernel/content"]
    36  	if !ok {
    37  		return nil, fmt.Errorf("kernel missing from archive")
    38  	}
    39  
    40  	li := &LinuxImage{}
    41  	li.Kernel = kernel
    42  
    43  	if params, ok := a.Files["modules/kernel/params"]; ok {
    44  		b, err := uio.ReadAll(params)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		li.Cmdline = string(b)
    49  	}
    50  
    51  	if initrd, ok := a.Files["modules/initrd/content"]; ok {
    52  		li.Initrd = initrd
    53  	}
    54  	return li, nil
    55  }
    56  
    57  // Pack implements OSImage.Pack and writes all necessary files to the modules
    58  // directory of `sw`.
    59  func (li *LinuxImage) Pack(sw cpio.RecordWriter) error {
    60  	if err := sw.WriteRecord(cpio.Directory("modules", 0700)); err != nil {
    61  		return err
    62  	}
    63  	if err := sw.WriteRecord(cpio.Directory("modules/kernel", 0700)); err != nil {
    64  		return err
    65  	}
    66  	if li.Kernel == nil {
    67  		return ErrKernelMissing
    68  	}
    69  	kernel, err := uio.ReadAll(li.Kernel)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	if err := sw.WriteRecord(cpio.StaticFile("modules/kernel/content", string(kernel), 0700)); err != nil {
    74  		return err
    75  	}
    76  	if err := sw.WriteRecord(cpio.StaticFile("modules/kernel/params", li.Cmdline, 0700)); err != nil {
    77  		return err
    78  	}
    79  
    80  	if li.Initrd != nil {
    81  		if err := sw.WriteRecord(cpio.Directory("modules/initrd", 0700)); err != nil {
    82  			return err
    83  		}
    84  		initrd, err := uio.ReadAll(li.Initrd)
    85  		if err != nil {
    86  			return err
    87  		}
    88  		if err := sw.WriteRecord(cpio.StaticFile("modules/initrd/content", string(initrd), 0700)); err != nil {
    89  			return err
    90  		}
    91  	}
    92  
    93  	return sw.WriteRecord(cpio.StaticFile("package_type", "linux", 0700))
    94  }
    95  
    96  func copyToFile(r io.Reader) (*os.File, error) {
    97  	f, err := ioutil.TempFile("", "nerf-netboot")
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	defer f.Close()
   102  	if _, err := io.Copy(f, r); err != nil {
   103  		return nil, err
   104  	}
   105  	if err := f.Sync(); err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	readOnlyF, err := os.Open(f.Name())
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	return readOnlyF, nil
   114  }
   115  
   116  // ExecutionInfo implements OSImage.ExecutionInfo.
   117  func (li *LinuxImage) ExecutionInfo(l *log.Logger) {
   118  	k, err := copyToFile(uio.Reader(li.Kernel))
   119  	if err != nil {
   120  		l.Printf("Copying kernel to file: %v", err)
   121  	}
   122  	defer k.Close()
   123  
   124  	var i *os.File
   125  	if li.Initrd != nil {
   126  		i, err = copyToFile(uio.Reader(li.Initrd))
   127  		if err != nil {
   128  			l.Printf("Copying initrd to file: %v", err)
   129  		}
   130  		defer i.Close()
   131  	}
   132  
   133  	l.Printf("Kernel: %s", k.Name())
   134  	if i != nil {
   135  		l.Printf("Initrd: %s", i.Name())
   136  	}
   137  	l.Printf("Command line: %s", li.Cmdline)
   138  }
   139  
   140  // Execute implements OSImage.Execute and kexec's the kernel with its initramfs.
   141  func (li *LinuxImage) Execute() error {
   142  	k, err := copyToFile(uio.Reader(li.Kernel))
   143  	if err != nil {
   144  		return err
   145  	}
   146  	defer k.Close()
   147  
   148  	var i *os.File
   149  	if li.Initrd != nil {
   150  		i, err = copyToFile(uio.Reader(li.Initrd))
   151  		if err != nil {
   152  			return err
   153  		}
   154  		defer i.Close()
   155  	}
   156  
   157  	if err := kexec.FileLoad(k, i, li.Cmdline); err != nil {
   158  		return err
   159  	}
   160  	return kexec.Reboot()
   161  }