blob: aee84cd86d8bc955ab2fb615c9b3fa58104a6d93 [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};
Jiyong Park2cb63b12021-11-05 14:29:23 +090019use disk::{
20 create_composite_disk, create_disk_file, ImagePartitionType, PartitionInfo, MAX_NESTING_DEPTH,
21};
Andrew Walbran3eca16c2021-06-14 11:15:14 +000022use std::fs::{File, OpenOptions};
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000023use std::os::unix::io::AsRawFd;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000024use std::path::{Path, PathBuf};
Andrew Walbran3eca16c2021-06-14 11:15:14 +000025
26/// Constructs a composite disk image for the given list of partitions, and opens it ready to use.
27///
Andrew Walbranfbb39d22021-07-28 17:01:25 +000028/// Returns the composite disk image file, and a list of files whose file descriptors must be passed
29/// to any process which wants to use it. This is necessary because the composite image contains
30/// paths of the form `/proc/self/fd/N` for the partition images.
Andrew Walbran3eca16c2021-06-14 11:15:14 +000031pub fn make_composite_image(
32 partitions: &[Partition],
Jooyung Han95884632021-07-06 22:27:54 +090033 zero_filler_path: &Path,
Andrew Walbran3eca16c2021-06-14 11:15:14 +000034 output_path: &Path,
35 header_path: &Path,
36 footer_path: &Path,
37) -> Result<(File, Vec<File>), Error> {
Andrew Walbranfbb39d22021-07-28 17:01:25 +000038 let (partitions, mut files) = convert_partitions(partitions)?;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000039
40 let mut composite_image = OpenOptions::new()
41 .create_new(true)
42 .read(true)
43 .write(true)
44 .open(output_path)
45 .with_context(|| format!("Failed to create composite image {:?}", output_path))?;
46 let mut header_file =
47 OpenOptions::new().create_new(true).read(true).write(true).open(header_path).with_context(
48 || format!("Failed to create composite image header {:?}", header_path),
49 )?;
50 let mut footer_file =
51 OpenOptions::new().create_new(true).read(true).write(true).open(footer_path).with_context(
52 || format!("Failed to create composite image header {:?}", footer_path),
53 )?;
Andrew Walbranfbb39d22021-07-28 17:01:25 +000054 let zero_filler_file = File::open(&zero_filler_path).with_context(|| {
55 format!("Failed to open composite image zero filler {:?}", zero_filler_path)
56 })?;
Andrew Walbran3eca16c2021-06-14 11:15:14 +000057
58 create_composite_disk(
59 &partitions,
Andrew Walbranfbb39d22021-07-28 17:01:25 +000060 &fd_path_for_file(&zero_filler_file),
61 &fd_path_for_file(&header_file),
Andrew Walbran3eca16c2021-06-14 11:15:14 +000062 &mut header_file,
Andrew Walbranfbb39d22021-07-28 17:01:25 +000063 &fd_path_for_file(&footer_file),
Andrew Walbran3eca16c2021-06-14 11:15:14 +000064 &mut footer_file,
65 &mut composite_image,
66 )?;
67
68 // Re-open the composite image as read-only.
69 let composite_image = File::open(&output_path)
70 .with_context(|| format!("Failed to open composite image {:?}", output_path))?;
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000071
Andrew Walbranfbb39d22021-07-28 17:01:25 +000072 files.push(header_file);
73 files.push(footer_file);
74 files.push(zero_filler_file);
75
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000076 Ok((composite_image, files))
77}
78
Jooyung Han631d5882021-07-29 06:34:05 +090079/// Given the AIDL config containing a list of partitions, with a [`ParcelFileDescriptor`] for each
Andrew Walbranfbb39d22021-07-28 17:01:25 +000080/// partition, returns the corresponding list of PartitionInfo and the list of files whose file
81/// descriptors must be passed to any process using the composite image.
Andrew Walbran3eca16c2021-06-14 11:15:14 +000082fn convert_partitions(partitions: &[Partition]) -> Result<(Vec<PartitionInfo>, Vec<File>), Error> {
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +000083 // File descriptors to pass to child process.
84 let mut files = vec![];
85
86 let partitions = partitions
87 .iter()
88 .map(|partition| {
Jooyung Han631d5882021-07-29 06:34:05 +090089 // TODO(b/187187765): This shouldn't be an Option.
90 let file = partition
91 .image
92 .as_ref()
93 .context("Invalid partition image file descriptor")?
94 .as_ref()
95 .try_clone()
96 .context("Failed to clone partition image file descriptor")?;
Andrew Walbranfbb39d22021-07-28 17:01:25 +000097 let path = fd_path_for_file(&file);
Richard Fung0383ab92022-03-24 18:16:25 +000098 let size = get_partition_size(&file, &path)?;
Jooyung Han631d5882021-07-29 06:34:05 +090099 files.push(file);
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000100
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000101 Ok(PartitionInfo {
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000102 label: partition.label.to_owned(),
Andrew Walbranfbb39d22021-07-28 17:01:25 +0000103 path,
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000104 partition_type: ImagePartitionType::LinuxFilesystem,
105 writable: partition.writable,
Jooyung Han631d5882021-07-29 06:34:05 +0900106 size,
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000107 })
108 })
109 .collect::<Result<_, Error>>()?;
Andrew Walbranf5fbb7d2021-05-12 17:15:48 +0000110
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000111 Ok((partitions, files))
112}
113
Andrew Walbranfbb39d22021-07-28 17:01:25 +0000114fn fd_path_for_file(file: &File) -> PathBuf {
115 let fd = file.as_raw_fd();
116 format!("/proc/self/fd/{}", fd).into()
117}
118
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000119/// Find the size of the partition image in the given file by parsing the header.
120///
121/// This will work for raw, QCOW2, composite and Android sparse images.
Richard Fung0383ab92022-03-24 18:16:25 +0000122fn get_partition_size(partition: &File, path: &Path) -> Result<u64, Error> {
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000123 // TODO: Use `context` once disk::Error implements std::error::Error.
Richard Fung0383ab92022-03-24 18:16:25 +0000124 Ok(create_disk_file(partition.try_clone()?, MAX_NESTING_DEPTH, path)
Andrew Walbran3eca16c2021-06-14 11:15:14 +0000125 .map_err(|e| anyhow!("Failed to open partition image: {}", e))?
126 .get_len()?)
127}