github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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/kexec"
    16  	"github.com/u-root/u-root/pkg/uio"
    17  )
    18  
    19  // LinuxImage implements OSImage for a Linux kernel + initramfs.
    20  type LinuxImage struct {
    21  	Kernel  io.ReaderAt
    22  	Initrd  io.ReaderAt
    23  	Cmdline string
    24  }
    25  
    26  var _ OSImage = &LinuxImage{}
    27  
    28  // String prints a human-readable version of this linux image.
    29  func (li *LinuxImage) String() string {
    30  	return fmt.Sprintf("LinuxImage(\n  Kernel: %s\n  Initrd: %s\n  Cmdline: %s\n)\n", li.Kernel, li.Initrd, li.Cmdline)
    31  }
    32  
    33  func copyToFile(r io.Reader) (*os.File, error) {
    34  	f, err := ioutil.TempFile("", "nerf-netboot")
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	defer f.Close()
    39  	if _, err := io.Copy(f, r); err != nil {
    40  		return nil, err
    41  	}
    42  	if err := f.Sync(); err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	readOnlyF, err := os.Open(f.Name())
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	return readOnlyF, nil
    51  }
    52  
    53  // Load implements OSImage.Load and kexec_load's the kernel with its initramfs.
    54  func (li *LinuxImage) Load(verbose bool) error {
    55  	if li.Kernel == nil {
    56  		return errors.New("LinuxImage.Kernel must be non-nil")
    57  	}
    58  
    59  	kernel, initrd := uio.Reader(li.Kernel), uio.Reader(li.Initrd)
    60  	if verbose {
    61  		// In verbose mode, print a dot every 5MiB. It is not pretty,
    62  		// but it at least proves the files are still downloading.
    63  		progress := func(r io.Reader) io.Reader {
    64  			return &uio.ProgressReader{
    65  				R:        r,
    66  				Symbol:   ".",
    67  				Interval: 5 * 1024 * 1024,
    68  				W:        os.Stdout,
    69  			}
    70  		}
    71  		kernel = progress(kernel)
    72  		initrd = progress(initrd)
    73  	}
    74  
    75  	k, err := copyToFile(kernel)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	defer k.Close()
    80  
    81  	var i *os.File
    82  	if li.Initrd != nil {
    83  		i, err = copyToFile(initrd)
    84  		if err != nil {
    85  			return err
    86  		}
    87  		defer i.Close()
    88  	}
    89  
    90  	log.Printf("Kernel: %s", k.Name())
    91  	if i != nil {
    92  		log.Printf("Initrd: %s", i.Name())
    93  	}
    94  	log.Printf("Command line: %s", li.Cmdline)
    95  	return kexec.FileLoad(k, i, li.Cmdline)
    96  }