payload_generation_config.cc revision 5b91c6b141970c2b0095775a61e3f941417aa1ff
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/common/utils.h" 22#include "update_engine/payload_consumer/delta_performer.h" 23#include "update_engine/payload_generator/delta_diff_generator.h" 24#include "update_engine/payload_generator/delta_diff_utils.h" 25#include "update_engine/payload_generator/ext2_filesystem.h" 26#include "update_engine/payload_generator/raw_filesystem.h" 27 28namespace chromeos_update_engine { 29 30bool PostInstallConfig::IsEmpty() const { 31 return !run && path.empty() && filesystem_type.empty() && !optional; 32} 33 34bool PartitionConfig::ValidateExists() const { 35 TEST_AND_RETURN_FALSE(!path.empty()); 36 TEST_AND_RETURN_FALSE(utils::FileExists(path.c_str())); 37 TEST_AND_RETURN_FALSE(size > 0); 38 // The requested size is within the limits of the file. 39 TEST_AND_RETURN_FALSE(static_cast<off_t>(size) <= 40 utils::FileSize(path.c_str())); 41 return true; 42} 43 44bool PartitionConfig::OpenFilesystem() { 45 if (path.empty()) 46 return true; 47 fs_interface.reset(); 48 if (diff_utils::IsExtFilesystem(path)) { 49 fs_interface = Ext2Filesystem::CreateFromFile(path); 50 // TODO(deymo): The delta generator algorithm doesn't support a block size 51 // different than 4 KiB. Remove this check once that's fixed. b/26972455 52 if (fs_interface) 53 TEST_AND_RETURN_FALSE(fs_interface->GetBlockSize() == kBlockSize); 54 } 55 56 if (!fs_interface) { 57 // Fall back to a RAW filesystem. 58 TEST_AND_RETURN_FALSE(size % kBlockSize == 0); 59 fs_interface = RawFilesystem::Create( 60 "<" + name + "-partition>", 61 kBlockSize, 62 size / kBlockSize); 63 } 64 return true; 65} 66 67bool ImageConfig::ValidateIsEmpty() const { 68 TEST_AND_RETURN_FALSE(ImageInfoIsEmpty()); 69 return partitions.empty(); 70} 71 72bool ImageConfig::LoadImageSize() { 73 for (PartitionConfig& part : partitions) { 74 if (part.path.empty()) 75 continue; 76 part.size = utils::FileSize(part.path); 77 } 78 return true; 79} 80 81bool ImageConfig::LoadPostInstallConfig(const brillo::KeyValueStore& store) { 82 bool found_postinstall = false; 83 for (PartitionConfig& part : partitions) { 84 bool run_postinstall; 85 if (!store.GetBoolean("RUN_POSTINSTALL_" + part.name, &run_postinstall) || 86 !run_postinstall) 87 continue; 88 found_postinstall = true; 89 part.postinstall.run = true; 90 store.GetString("POSTINSTALL_PATH_" + part.name, &part.postinstall.path); 91 store.GetString("FILESYSTEM_TYPE_" + part.name, 92 &part.postinstall.filesystem_type); 93 store.GetBoolean("POSTINSTALL_OPTIONAL_" + part.name, 94 &part.postinstall.optional); 95 } 96 if (!found_postinstall) { 97 LOG(ERROR) << "No valid postinstall config found."; 98 return false; 99 } 100 return true; 101} 102 103bool ImageConfig::ImageInfoIsEmpty() const { 104 return image_info.board().empty() 105 && image_info.key().empty() 106 && image_info.channel().empty() 107 && image_info.version().empty() 108 && image_info.build_channel().empty() 109 && image_info.build_version().empty(); 110} 111 112PayloadVersion::PayloadVersion(uint64_t major_version, uint32_t minor_version) { 113 major = major_version; 114 minor = minor_version; 115} 116 117bool PayloadVersion::Validate() const { 118 TEST_AND_RETURN_FALSE(major == kChromeOSMajorPayloadVersion || 119 major == kBrilloMajorPayloadVersion); 120 TEST_AND_RETURN_FALSE(minor == kFullPayloadMinorVersion || 121 minor == kInPlaceMinorPayloadVersion || 122 minor == kSourceMinorPayloadVersion || 123 minor == kOpSrcHashMinorPayloadVersion || 124 minor == kImgdiffMinorPayloadVersion); 125 return true; 126} 127 128bool PayloadVersion::OperationAllowed(InstallOperation_Type operation) const { 129 switch (operation) { 130 // Full operations: 131 case InstallOperation::REPLACE: 132 case InstallOperation::REPLACE_BZ: 133 // These operations were included in the original payload format. 134 return true; 135 136 case InstallOperation::REPLACE_XZ: 137 // These operations are included in the major version used in Brillo, but 138 // can also be used with minor version 3 or newer. 139 return major == kBrilloMajorPayloadVersion || 140 minor >= kOpSrcHashMinorPayloadVersion; 141 142 case InstallOperation::ZERO: 143 case InstallOperation::DISCARD: 144 // The implementation of these operations had a bug in earlier versions 145 // that prevents them from being used in any payload. We will enable 146 // them for delta payloads for now. 147 return minor >= kImgdiffMinorPayloadVersion; 148 149 // Delta operations: 150 case InstallOperation::MOVE: 151 case InstallOperation::BSDIFF: 152 // MOVE and BSDIFF were replaced by SOURCE_COPY and SOURCE_BSDIFF and 153 // should not be used in newer delta versions, since the idempotent checks 154 // were removed. 155 return minor == kInPlaceMinorPayloadVersion; 156 157 case InstallOperation::SOURCE_COPY: 158 case InstallOperation::SOURCE_BSDIFF: 159 return minor >= kSourceMinorPayloadVersion; 160 161 case InstallOperation::IMGDIFF: 162 return minor >= kImgdiffMinorPayloadVersion && imgdiff_allowed; 163 } 164 return false; 165} 166 167bool PayloadVersion::IsDelta() const { 168 return minor != kFullPayloadMinorVersion; 169} 170 171bool PayloadVersion::InplaceUpdate() const { 172 return minor == kInPlaceMinorPayloadVersion; 173} 174 175bool PayloadGenerationConfig::Validate() const { 176 TEST_AND_RETURN_FALSE(version.Validate()); 177 TEST_AND_RETURN_FALSE(version.IsDelta() == is_delta); 178 if (is_delta) { 179 for (const PartitionConfig& part : source.partitions) { 180 if (!part.path.empty()) { 181 TEST_AND_RETURN_FALSE(part.ValidateExists()); 182 TEST_AND_RETURN_FALSE(part.size % block_size == 0); 183 } 184 // Source partition should not have postinstall. 185 TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty()); 186 } 187 188 // If new_image_info is present, old_image_info must be present. 189 TEST_AND_RETURN_FALSE(source.ImageInfoIsEmpty() == 190 target.ImageInfoIsEmpty()); 191 } else { 192 // All the "source" image fields must be empty for full payloads. 193 TEST_AND_RETURN_FALSE(source.ValidateIsEmpty()); 194 } 195 196 // In all cases, the target image must exists. 197 for (const PartitionConfig& part : target.partitions) { 198 TEST_AND_RETURN_FALSE(part.ValidateExists()); 199 TEST_AND_RETURN_FALSE(part.size % block_size == 0); 200 if (version.minor == kInPlaceMinorPayloadVersion && 201 part.name == kLegacyPartitionNameRoot) 202 TEST_AND_RETURN_FALSE(rootfs_partition_size >= part.size); 203 if (version.major == kChromeOSMajorPayloadVersion) 204 TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty()); 205 } 206 207 TEST_AND_RETURN_FALSE(hard_chunk_size == -1 || 208 hard_chunk_size % block_size == 0); 209 TEST_AND_RETURN_FALSE(soft_chunk_size % block_size == 0); 210 211 TEST_AND_RETURN_FALSE(rootfs_partition_size % block_size == 0); 212 213 return true; 214} 215 216} // namespace chromeos_update_engine 217