github.com/rck/u-root@v0.0.0-20180106144920-7eb602e381bb/pkg/ramfs/ramfs.go (about) 1 // Copyright 2015-2017 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 ramfs 6 7 import ( 8 "os" 9 "path/filepath" 10 "syscall" 11 12 "github.com/u-root/u-root/pkg/cpio" 13 _ "github.com/u-root/u-root/pkg/cpio/newc" 14 ) 15 16 const ( 17 d = syscall.S_IFDIR 18 c = syscall.S_IFCHR 19 b = syscall.S_IFBLK 20 f = syscall.S_IFREG 21 22 // This is the literal timezone file for GMT-0. Given that we have no idea 23 // where we will be running, GMT seems a reasonable guess. If it matters, 24 // setup code should download and change this to something else. 25 gmt0 = "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00GMT\x00\x00\x00\nGMT0\n" 26 nameserver = "nameserver 8.8.8.8\n" 27 ) 28 29 // devCPIOrecords are cpio records as defined in the uroot cpio package. 30 // Most of the bits can be left unspecified: these all have one link, 31 // they are mostly root:root, for example. 32 var DevCPIO = []cpio.Record{ 33 {Info: cpio.Info{Name: "tcz", Mode: d | 0755}}, 34 {Info: cpio.Info{Name: "etc", Mode: d | 0755}}, 35 {Info: cpio.Info{Name: "dev", Mode: d | 0755}}, 36 {Info: cpio.Info{Name: "ubin", Mode: d | 0755}}, 37 {Info: cpio.Info{Name: "usr", Mode: d | 0755}}, 38 {Info: cpio.Info{Name: "usr/lib", Mode: d | 0755}}, 39 {Info: cpio.Info{Name: "lib64", Mode: d | 0755}}, 40 {Info: cpio.Info{Name: "bin", Mode: d | 0755}}, 41 {Info: cpio.Info{Name: "dev/console", Mode: c | 0600, Rmajor: 5, Rminor: 1}}, 42 {Info: cpio.Info{Name: "dev/tty", Mode: c | 0666, Rmajor: 5, Rminor: 0}}, 43 {Info: cpio.Info{Name: "dev/null", Mode: c | 0666, Rmajor: 1, Rminor: 3}}, 44 {Info: cpio.Info{Name: "dev/port", Mode: c | 0640, Rmajor: 1, Rminor: 4}}, 45 {Info: cpio.Info{Name: "dev/urandom", Mode: c | 0666, Rmajor: 1, Rminor: 9}}, 46 {Info: cpio.Info{Name: "etc/resolv.conf", Mode: f | 0644, FileSize: uint64(len(nameserver))}, ReadCloser: cpio.NewBytesReadCloser([]byte(nameserver))}, 47 {Info: cpio.Info{Name: "etc/localtime", Mode: f | 0644, FileSize: uint64(len(gmt0))}, ReadCloser: cpio.NewBytesReadCloser([]byte(gmt0))}, 48 } 49 50 type Initramfs struct { 51 cpio.Writer 52 files map[string]struct{} 53 } 54 55 func NewInitramfs(w cpio.Writer) (*Initramfs, error) { 56 // Write devtmpfs records. 57 dcpio := DevCPIO[:] 58 cpio.MakeAllReproducible(dcpio) 59 if err := w.WriteRecords(dcpio); err != nil { 60 return nil, err 61 } 62 63 return &Initramfs{ 64 Writer: w, 65 files: make(map[string]struct{}), 66 }, nil 67 } 68 69 func (i *Initramfs) WriteRecord(r cpio.Record) error { 70 if r.Name == "." || r.Name == "/" { 71 return nil 72 } 73 74 // Create record for parent directory if needed. 75 dir := filepath.Dir(r.Name) 76 if _, ok := i.files[dir]; dir != "/" && dir != "." && !ok { 77 if err := i.WriteRecord(cpio.Record{ 78 Info: cpio.Info{ 79 Name: dir, 80 Mode: syscall.S_IFDIR | 0755, 81 }, 82 }); err != nil { 83 return err 84 } 85 } 86 87 i.files[r.Name] = struct{}{} 88 return i.Writer.WriteRecord(r) 89 } 90 91 func (i *Initramfs) WriteFile(src string, dest string) error { 92 record, err := cpio.GetRecord(src) 93 if err != nil { 94 return err 95 } 96 97 if record.Info.Mode&^0777 == syscall.S_IFDIR { 98 return children(src, func(name string) error { 99 return i.WriteFile(filepath.Join(src, name), filepath.Join(dest, name)) 100 }) 101 } else { 102 // Fix the name. 103 record.Name = dest 104 return i.WriteRecord(cpio.MakeReproducible(record)) 105 } 106 } 107 108 func children(dir string, fn func(name string) error) error { 109 f, err := os.Open(dir) 110 if err != nil { 111 return err 112 } 113 names, err := f.Readdirnames(-1) 114 f.Close() 115 if err != nil { 116 return err 117 } 118 119 for _, name := range names { 120 if err := fn(name); os.IsNotExist(err) { 121 // File was deleted in the meantime. 122 continue 123 } else if err != nil { 124 return err 125 } 126 } 127 return nil 128 } 129 130 // Copy all files relative to `srcDir` to `destDir` in the cpio archive. 131 func (i *Initramfs) WriteFiles(srcDir string, destDir string, files []string) error { 132 for _, file := range files { 133 srcPath := filepath.Join(srcDir, file) 134 destPath := filepath.Join(destDir, file) 135 if err := i.WriteFile(srcPath, destPath); err != nil { 136 return err 137 } 138 } 139 return nil 140 }