payload_generation_config.cc revision aea4c1cea20dda7ae7e85fc8924a2d784f70d806
1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/payload_generator/payload_generation_config.h"
18
19#include <base/logging.h>
20
21#include "update_engine/delta_performer.h"
22#include "update_engine/payload_generator/delta_diff_generator.h"
23#include "update_engine/payload_generator/ext2_filesystem.h"
24#include "update_engine/payload_generator/raw_filesystem.h"
25#include "update_engine/payload_generator/verity_utils.h"
26#include "update_engine/utils.h"
27
28namespace chromeos_update_engine {
29
30std::string PartitionNameString(PartitionName name) {
31  switch (name) {
32    case PartitionName::kKernel:
33      return "kernel";
34    case PartitionName::kRootfs:
35      return "rootfs";
36  }
37  return "other";
38}
39
40bool PartitionConfig::ValidateExists() const {
41  TEST_AND_RETURN_FALSE(!path.empty());
42  TEST_AND_RETURN_FALSE(utils::FileExists(path.c_str()));
43  TEST_AND_RETURN_FALSE(size > 0);
44  // The requested size is within the limits of the file.
45  TEST_AND_RETURN_FALSE(static_cast<off_t>(size) <=
46                        utils::FileSize(path.c_str()));
47  return true;
48}
49
50bool PartitionConfig::OpenFilesystem() {
51  if (path.empty())
52    return true;
53  fs_interface.reset();
54  if (name == PartitionName::kRootfs) {
55    fs_interface = Ext2Filesystem::CreateFromFile(path);
56  }
57
58  if (!fs_interface) {
59    // Fall back to a RAW filesystem.
60    TEST_AND_RETURN_FALSE(size % kBlockSize == 0);
61    fs_interface = RawFilesystem::Create(
62      "<" + PartitionNameString(name) + "-partition>",
63      kBlockSize,
64      size / kBlockSize);
65  }
66  return true;
67}
68
69bool ImageConfig::ValidateIsEmpty() const {
70  TEST_AND_RETURN_FALSE(ImageInfoIsEmpty());
71
72  TEST_AND_RETURN_FALSE(rootfs.path.empty());
73  TEST_AND_RETURN_FALSE(rootfs.size == 0);
74  TEST_AND_RETURN_FALSE(kernel.path.empty());
75  TEST_AND_RETURN_FALSE(kernel.size == 0);
76  return true;
77}
78
79bool ImageConfig::LoadImageSize() {
80  TEST_AND_RETURN_FALSE(!rootfs.path.empty());
81  int rootfs_block_count, rootfs_block_size;
82  TEST_AND_RETURN_FALSE(utils::GetFilesystemSize(rootfs.path,
83                                                 &rootfs_block_count,
84                                                 &rootfs_block_size));
85  rootfs.size = static_cast<uint64_t>(rootfs_block_count) * rootfs_block_size;
86  if (!kernel.path.empty())
87    kernel.size = utils::FileSize(kernel.path);
88
89  // TODO(deymo): The delta generator algorithm doesn't support a block size
90  // different than 4 KiB. Remove this check once that's fixed. crbug.com/455045
91  if (rootfs_block_size != 4096) {
92    LOG(ERROR) << "The filesystem provided in " << rootfs.path
93               << " has a block size of " << rootfs_block_size
94               << " but delta_generator only supports 4096.";
95    return false;
96  }
97  return true;
98}
99
100bool ImageConfig::LoadVerityRootfsSize() {
101  if (kernel.path.empty())
102    return false;
103  uint64_t verity_rootfs_size = 0;
104  if (!GetVerityRootfsSize(kernel.path, &verity_rootfs_size)) {
105    LOG(INFO) << "Couldn't find verity options in source kernel config, will "
106              << "use the rootfs filesystem size instead: " << rootfs.size;
107    return false;
108  }
109  if (rootfs.size != verity_rootfs_size) {
110    LOG(WARNING) << "Using the rootfs size found in the kernel config ("
111                 << verity_rootfs_size << ") instead of the rootfs filesystem "
112                 << " size (" << rootfs.size << ").";
113    rootfs.size = verity_rootfs_size;
114  }
115  return true;
116}
117
118bool ImageConfig::ImageInfoIsEmpty() const {
119  return image_info.board().empty()
120    && image_info.key().empty()
121    && image_info.channel().empty()
122    && image_info.version().empty()
123    && image_info.build_channel().empty()
124    && image_info.build_version().empty();
125}
126
127bool PayloadGenerationConfig::Validate() const {
128  if (is_delta) {
129    TEST_AND_RETURN_FALSE(source.rootfs.ValidateExists());
130    TEST_AND_RETURN_FALSE(source.rootfs.size % block_size == 0);
131
132    if (!source.kernel.path.empty()) {
133      TEST_AND_RETURN_FALSE(source.kernel.ValidateExists());
134      TEST_AND_RETURN_FALSE(source.kernel.size % block_size == 0);
135    }
136
137    // Check for the supported minor_version values.
138    TEST_AND_RETURN_FALSE(minor_version == kInPlaceMinorPayloadVersion ||
139                          minor_version == kSourceMinorPayloadVersion);
140
141    // If new_image_info is present, old_image_info must be present.
142    TEST_AND_RETURN_FALSE(source.ImageInfoIsEmpty() ==
143                          target.ImageInfoIsEmpty());
144  } else {
145    // All the "source" image fields must be empty for full payloads.
146    TEST_AND_RETURN_FALSE(source.ValidateIsEmpty());
147    TEST_AND_RETURN_FALSE(minor_version ==
148                          DeltaPerformer::kFullPayloadMinorVersion);
149  }
150
151  // In all cases, the target image must exists.
152  TEST_AND_RETURN_FALSE(target.rootfs.ValidateExists());
153  TEST_AND_RETURN_FALSE(target.kernel.ValidateExists());
154  TEST_AND_RETURN_FALSE(target.rootfs.size % block_size == 0);
155  TEST_AND_RETURN_FALSE(target.kernel.size % block_size == 0);
156
157  TEST_AND_RETURN_FALSE(hard_chunk_size == -1 ||
158                        hard_chunk_size % block_size == 0);
159  TEST_AND_RETURN_FALSE(soft_chunk_size % block_size == 0);
160
161  TEST_AND_RETURN_FALSE(rootfs_partition_size % block_size == 0);
162  TEST_AND_RETURN_FALSE(rootfs_partition_size >= target.rootfs.size);
163
164  return true;
165}
166
167}  // namespace chromeos_update_engine
168