Lorenz Brun | f95909d | 2019-09-11 19:48:26 +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 storage |
| 18 | |
| 19 | import ( |
| 20 | "fmt" |
| 21 | "io/ioutil" |
| 22 | "os" |
| 23 | "path/filepath" |
Lorenz Brun | f95909d | 2019-09-11 19:48:26 +0200 | [diff] [blame] | 24 | "strconv" |
| 25 | |
Hendrik Hofstadt | 8efe51e | 2020-02-28 12:53:41 +0100 | [diff] [blame^] | 26 | "git.monogon.dev/source/nexantic.git/core/pkg/sysfs" |
| 27 | |
Lorenz Brun | f95909d | 2019-09-11 19:48:26 +0200 | [diff] [blame] | 28 | "github.com/rekby/gpt" |
| 29 | "golang.org/x/sys/unix" |
| 30 | ) |
| 31 | |
| 32 | // EFIPartitionType is the standardized partition type value for the EFI ESP partition. The human readable GUID is C12A7328-F81F-11D2-BA4B-00A0C93EC93B. |
| 33 | var EFIPartitionType = gpt.PartType{0x28, 0x73, 0x2a, 0xc1, 0x1f, 0xf8, 0xd2, 0x11, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} |
| 34 | |
| 35 | // SmalltownDataPartitionType is the partition type value for a Smalltown data partition. The human-readable GUID is 9eeec464-6885-414a-b278-4305c51f7966. |
| 36 | var SmalltownDataPartitionType = gpt.PartType{0x64, 0xc4, 0xee, 0x9e, 0x85, 0x68, 0x4a, 0x41, 0xb2, 0x78, 0x43, 0x05, 0xc5, 0x1f, 0x79, 0x66} |
| 37 | |
| 38 | var ESPDevicePath = "/dev/esp" |
| 39 | var SmalltownDataCryptPath = "/dev/data-crypt" |
| 40 | |
| 41 | // FindPartitions looks for the ESP and the Smalltown data partition and maps them to ESPDevicePath and |
| 42 | // SmalltownDataCryptPath respectively. This doesn't fail if it doesn't find the partitions, only if |
| 43 | // something goes catastrophically wrong. |
| 44 | func FindPartitions() error { |
| 45 | blockdevNames, err := ioutil.ReadDir("/sys/class/block") |
| 46 | if err != nil { |
| 47 | return fmt.Errorf("failed to read sysfs block class: %w", err) |
| 48 | } |
| 49 | for _, blockdevName := range blockdevNames { |
| 50 | ueventData, err := sysfs.ReadUevents(filepath.Join("/sys/class/block", blockdevName.Name(), "uevent")) |
| 51 | if err != nil { |
| 52 | return fmt.Errorf("failed to read uevent for block device %v: %w", blockdevName.Name(), err) |
| 53 | } |
| 54 | if ueventData["DEVTYPE"] == "disk" { |
| 55 | majorDev, err := strconv.Atoi(ueventData["MAJOR"]) |
| 56 | if err != nil { |
| 57 | return fmt.Errorf("failed to convert uevent: %w", err) |
| 58 | } |
| 59 | minorDev, err := strconv.Atoi(ueventData["MINOR"]) |
| 60 | if err != nil { |
| 61 | return fmt.Errorf("failed to convert uevent: %w", err) |
| 62 | } |
| 63 | devNodeName := fmt.Sprintf("/dev/%v", ueventData["DEVNAME"]) |
| 64 | if err := unix.Mknod(devNodeName, 0600|unix.S_IFBLK, int(unix.Mkdev(uint32(majorDev), uint32(minorDev)))); err != nil { |
| 65 | return fmt.Errorf("failed to create block device node: %w", err) |
| 66 | } |
| 67 | blkdev, err := os.Open(devNodeName) |
| 68 | if err != nil { |
| 69 | return fmt.Errorf("failed to open block device %v: %w", devNodeName, err) |
| 70 | } |
| 71 | defer blkdev.Close() |
| 72 | blockSize, err := unix.IoctlGetUint32(int(blkdev.Fd()), unix.BLKSSZGET) |
| 73 | if err != nil { |
| 74 | continue // This is not a regular block device |
| 75 | } |
| 76 | blkdev.Seek(int64(blockSize), 0) |
| 77 | table, err := gpt.ReadTable(blkdev, uint64(blockSize)) |
| 78 | if err != nil { |
| 79 | // Probably just not a GPT-partitioned disk |
| 80 | continue |
| 81 | } |
| 82 | for partNumber, part := range table.Partitions { |
| 83 | if part.Type == EFIPartitionType { |
| 84 | if err := unix.Mknod(ESPDevicePath, 0600|unix.S_IFBLK, int(unix.Mkdev(uint32(majorDev), uint32(partNumber+1)))); err != nil { |
| 85 | return fmt.Errorf("failed to create device node for ESP partition: %w", err) |
| 86 | } |
| 87 | } |
| 88 | if part.Type == SmalltownDataPartitionType { |
| 89 | if err := unix.Mknod(SmalltownDataCryptPath, 0600|unix.S_IFBLK, int(unix.Mkdev(uint32(majorDev), uint32(partNumber+1)))); err != nil { |
| 90 | return fmt.Errorf("failed to create device node for Smalltown encrypted data partition: %w", err) |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | return nil |
| 97 | } |