Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 1 | // Copyright 2020 The Monogon Project Authors. |
| 2 | // |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | // |
| 5 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | // you may not use this file except in compliance with the License. |
| 7 | // You may obtain a copy of the License at |
| 8 | // |
| 9 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | // |
| 11 | // Unless required by applicable law or agreed to in writing, software |
| 12 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | // See the License for the specific language governing permissions and |
| 15 | // limitations under the License. |
| 16 | |
| 17 | package main |
| 18 | |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 19 | // mkimage is a tool to generate a Smalltown disk image containing the given EFI payload, and optionally, a given external |
| 20 | // initramfs image and enrolment credentials. |
| 21 | |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 22 | import ( |
Leopold Schabel | 6549307 | 2019-11-06 13:40:44 +0000 | [diff] [blame] | 23 | "flag" |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 24 | "fmt" |
| 25 | "io/ioutil" |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 26 | "log" |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 27 | "os" |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 28 | |
Hendrik Hofstadt | 8efe51e | 2020-02-28 12:53:41 +0100 | [diff] [blame] | 29 | diskfs "github.com/diskfs/go-diskfs" |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 30 | "github.com/diskfs/go-diskfs/disk" |
| 31 | "github.com/diskfs/go-diskfs/filesystem" |
| 32 | "github.com/diskfs/go-diskfs/partition/gpt" |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 33 | ) |
| 34 | |
| 35 | var SmalltownDataPartition gpt.Type = gpt.Type("9eeec464-6885-414a-b278-4305c51f7966") |
| 36 | |
Leopold Schabel | 6549307 | 2019-11-06 13:40:44 +0000 | [diff] [blame] | 37 | var ( |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 38 | flagEFI string |
| 39 | flagOut string |
| 40 | flagInitramfs string |
| 41 | flagEnrolmentCredentials string |
| 42 | flagDataPartitionSize uint64 |
| 43 | flagESPPartitionSize uint64 |
Leopold Schabel | 6549307 | 2019-11-06 13:40:44 +0000 | [diff] [blame] | 44 | ) |
| 45 | |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 46 | func mibToSectors(size uint64) uint64 { |
| 47 | return (size * 1024 * 1024) / 512 |
| 48 | } |
| 49 | |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 50 | func main() { |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 51 | flag.StringVar(&flagEFI, "efi", "", "UEFI payload") |
| 52 | flag.StringVar(&flagOut, "out", "", "Output disk image") |
| 53 | flag.StringVar(&flagInitramfs, "initramfs", "", "External initramfs [optional]") |
| 54 | flag.StringVar(&flagEnrolmentCredentials, "enrolment_credentials", "", "Enrolment credentials [optional]") |
| 55 | flag.Uint64Var(&flagDataPartitionSize, "data_partition_size", 2048, "Override the data partition size (default 2048 MiB)") |
| 56 | flag.Uint64Var(&flagESPPartitionSize, "esp_partition_size", 512, "Override the ESP partition size (default: 512MiB)") |
Leopold Schabel | 6549307 | 2019-11-06 13:40:44 +0000 | [diff] [blame] | 57 | flag.Parse() |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 58 | |
| 59 | if flagEFI == "" || flagOut == "" { |
| 60 | log.Fatalf("efi and initramfs must be set") |
Lorenz Brun | f95909d | 2019-09-11 19:48:26 +0200 | [diff] [blame] | 61 | } |
Leopold Schabel | 6549307 | 2019-11-06 13:40:44 +0000 | [diff] [blame] | 62 | |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 63 | _ = os.Remove(flagOut) |
| 64 | diskImg, err := diskfs.Create(flagOut, 3*1024*1024*1024, diskfs.Raw) |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 65 | if err != nil { |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 66 | log.Fatalf("diskfs.Create(%q): %v", flagOut, err) |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | table := &gpt.Table{ |
| 70 | // This is appropriate at least for virtio disks. Might need to be adjusted for real ones. |
| 71 | LogicalSectorSize: 512, |
| 72 | PhysicalSectorSize: 512, |
| 73 | ProtectiveMBR: true, |
| 74 | Partitions: []*gpt.Partition{ |
| 75 | { |
| 76 | Type: gpt.EFISystemPartition, |
| 77 | Name: "ESP", |
| 78 | Start: mibToSectors(1), |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 79 | End: mibToSectors(flagESPPartitionSize) - 1, |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 80 | }, |
| 81 | { |
| 82 | Type: SmalltownDataPartition, |
| 83 | Name: "SIGNOS-DATA", |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 84 | Start: mibToSectors(flagESPPartitionSize), |
| 85 | End: mibToSectors(flagESPPartitionSize+flagDataPartitionSize) - 1, |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 86 | }, |
| 87 | }, |
| 88 | } |
| 89 | if err := diskImg.Partition(table); err != nil { |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 90 | log.Fatalf("Failed to apply partition table: %v", err) |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | fs, err := diskImg.CreateFilesystem(disk.FilesystemSpec{Partition: 1, FSType: filesystem.TypeFat32, VolumeLabel: "ESP"}) |
| 94 | if err != nil { |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 95 | log.Fatalf("Failed to create filesystem: %v", err) |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 96 | } |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 97 | |
| 98 | // Create EFI partition structure. |
| 99 | for _, dir := range []string{"/EFI", "/EFI/BOOT", "/EFI/smalltown"} { |
| 100 | if err := fs.Mkdir(dir); err != nil { |
| 101 | log.Fatalf("Mkdir(%q): %v", dir, err) |
Lorenz Brun | 0bcaaee | 2019-11-06 12:42:39 +0100 | [diff] [blame] | 102 | } |
| 103 | } |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 104 | |
| 105 | put(fs, flagEFI, "/EFI/BOOT/BOOTX64.EFI") |
| 106 | |
| 107 | if flagInitramfs != "" { |
| 108 | put(fs, flagInitramfs, "/EFI/smalltown/initramfs.cpio.lz4") |
Lorenz Brun | aa6b734 | 2019-12-12 02:55:02 +0100 | [diff] [blame] | 109 | } |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 110 | |
| 111 | if flagEnrolmentCredentials != "" { |
| 112 | put(fs, flagEnrolmentCredentials, "/EFI/smalltown/enrolment.pb") |
| 113 | } |
| 114 | |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 115 | if err := diskImg.File.Close(); err != nil { |
Serge Bazanski | 032ca18 | 2020-06-09 20:17:13 +0200 | [diff] [blame^] | 116 | log.Fatalf("Failed to finalize image: %v", err) |
| 117 | } |
| 118 | log.Printf("Success! You can now boot %v", flagOut) |
| 119 | } |
| 120 | |
| 121 | // put copies a file from the host filesystem into the target image. |
| 122 | func put(fs filesystem.FileSystem, src, dst string) { |
| 123 | target, err := fs.OpenFile(dst, os.O_CREATE|os.O_RDWR) |
| 124 | if err != nil { |
| 125 | log.Fatalf("fs.OpenFile(%q): %v", dst, err) |
| 126 | } |
| 127 | source, err := os.Open(src) |
| 128 | if err != nil { |
| 129 | log.Fatalf("os.Open(%q): %v", src, err) |
| 130 | } |
| 131 | defer source.Close() |
| 132 | // If this is streamed (e.g. using io.Copy) it exposes a bug in diskfs, so do it in one go. |
| 133 | data, err := ioutil.ReadAll(source) |
| 134 | if err != nil { |
| 135 | log.Fatalf("Reading %q: %v", src, err) |
| 136 | } |
| 137 | if _, err := target.Write(data); err != nil { |
| 138 | fmt.Printf("writing file %q: %v", dst, err) |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 139 | os.Exit(1) |
| 140 | } |
Lorenz Brun | ae0d90d | 2019-09-05 17:53:56 +0200 | [diff] [blame] | 141 | } |