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 }