blob: 40c7e5ee1d7600f7856e474ef3a6d0f34652ec38 [file] [log] [blame]
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +00001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Andrew Walbran3eca16c2021-06-14 11:15:14 +000015//! Functions for creating a composite disk image.
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000016
Andrew Walbran3eca16c2021-06-14 11:15:14 +000017use android_system_virtualizationservice::aidl::android::system::virtualizationservice::Partition::Partition;
Andrew Walbranb31c3f12021-08-03 13:17:00 +000018use anyhow::{anyhow, Context, Error};
19use disk::{create_composite_disk, create_disk_file, ImagePartitionType, PartitionInfo};
Andrew Walbran3eca16c2021-06-14 11:15:14 +000020use std::fs::{File, OpenOptions};
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000021use std::os::unix::io::AsRawFd;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000022use std::path::{Path, PathBuf};
Andrew Walbran3eca16c2021-06-14 11:15:14 +000023
24/// Constructs a composite disk image for the given list of partitions, and opens it ready to use.
25///
Andrew Walbranfbb39d22021-07-28 17:01:25 +000026/// Returns the composite disk image file, and a list of files whose file descriptors must be passed
27/// to any process which wants to use it. This is necessary because the composite image contains
28/// paths of the form `/proc/self/fd/N` for the partition images.
Andrew Walbran3eca16c2021-06-14 11:15:14 +000029pub fn make_composite_image(
30 partitions: &[Partition],
Jooyung Han95884632021-07-06 22:27:54 +090031 zero_filler_path: &Path,
Andrew Walbran3eca16c2021-06-14 11:15:14 +000032 output_path: &Path,
33 header_path: &Path,
34 footer_path: &Path,
35) -> Result<(File, Vec<File>), Error> {
Andrew Walbranfbb39d22021-07-28 17:01:25 +000036 let (partitions, mut files) = convert_partitions(partitions)?;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000037
38 let mut composite_image = OpenOptions::new()
39 .create_new(true)
40 .read(true)
41 .write(true)
42 .open(output_path)
43 .with_context(|| format!("Failed to create composite image {:?}", output_path))?;
44 let mut header_file =
45 OpenOptions::new().create_new(true).read(true).write(true).open(header_path).with_context(
46 || format!("Failed to create composite image header {:?}", header_path),
47 )?;
48 let mut footer_file =
49 OpenOptions::new().create_new(true).read(true).write(true).open(footer_path).with_context(
50 || format!("Failed to create composite image header {:?}", footer_path),
51 )?;
Andrew Walbranfbb39d22021-07-28 17:01:25 +000052 let zero_filler_file = File::open(&zero_filler_path).with_context(|| {
53 format!("Failed to open composite image zero filler {:?}", zero_filler_path)
54 })?;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000055
56 create_composite_disk(
57 &partitions,
Andrew Walbranfbb39d22021-07-28 17:01:25 +000058 &fd_path_for_file(&zero_filler_file),
59 &fd_path_for_file(&header_file),
Andrew Walbran3eca16c2021-06-14 11:15:14 +000060 &mut header_file,
Andrew Walbranfbb39d22021-07-28 17:01:25 +000061 &fd_path_for_file(&footer_file),
Andrew Walbran3eca16c2021-06-14 11:15:14 +000062 &mut footer_file,
63 &mut composite_image,
64 )?;
65
66 // Re-open the composite image as read-only.
67 let composite_image = File::open(&output_path)
68 .with_context(|| format!("Failed to open composite image {:?}", output_path))?;
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000069
Andrew Walbranfbb39d22021-07-28 17:01:25 +000070 files.push(header_file);
71 files.push(footer_file);
72 files.push(zero_filler_file);
73
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000074 Ok((composite_image, files))
75}
76
Jooyung Han631d5882021-07-29 06:34:05 +090077/// Given the AIDL config containing a list of partitions, with a [`ParcelFileDescriptor`] for each
Andrew Walbranfbb39d22021-07-28 17:01:25 +000078/// partition, returns the corresponding list of PartitionInfo and the list of files whose file
79/// descriptors must be passed to any process using the composite image.
Andrew Walbran3eca16c2021-06-14 11:15:14 +000080fn convert_partitions(partitions: &[Partition]) -> Result<(Vec<PartitionInfo>, Vec<File>), Error> {
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000081 // File descriptors to pass to child process.
82 let mut files = vec![];
83
84 let partitions = partitions
85 .iter()
86 .map(|partition| {
Jooyung Han631d5882021-07-29 06:34:05 +090087 // TODO(b/187187765): This shouldn't be an Option.
88 let file = partition
89 .image
90 .as_ref()
91 .context("Invalid partition image file descriptor")?
92 .as_ref()
93 .try_clone()
94 .context("Failed to clone partition image file descriptor")?;
95 let size = get_partition_size(&file)?;
Andrew Walbranfbb39d22021-07-28 17:01:25 +000096 let path = fd_path_for_file(&file);
Jooyung Han631d5882021-07-29 06:34:05 +090097 files.push(file);
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000098
Andrew Walbran3eca16c2021-06-14 11:15:14 +000099 Ok(PartitionInfo {
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000100 label: partition.label.to_owned(),
Andrew Walbranfbb39d22021-07-28 17:01:25 +0000101 path,
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000102 partition_type: ImagePartitionType::LinuxFilesystem,
103 writable: partition.writable,
Jooyung Han631d5882021-07-29 06:34:05 +0900104 size,
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000105 })
106 })
107 .collect::<Result<_, Error>>()?;
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000108
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000109 Ok((partitions, files))
110}
111
Andrew Walbranfbb39d22021-07-28 17:01:25 +0000112fn fd_path_for_file(file: &File) -> PathBuf {
113 let fd = file.as_raw_fd();
114 format!("/proc/self/fd/{}", fd).into()
115}
116
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000117/// Find the size of the partition image in the given file by parsing the header.
118///
119/// This will work for raw, QCOW2, composite and Android sparse images.
120fn get_partition_size(partition: &File) -> Result<u64, Error> {
121 // TODO: Use `context` once disk::Error implements std::error::Error.
122 Ok(create_disk_file(partition.try_clone()?)
123 .map_err(|e| anyhow!("Failed to open partition image: {}", e))?
124 .get_len()?)
125}