payload_generation_config.cc revision a4073ef63482fd08c3678982f7d153360b088094
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 == false && path.empty() && filesystem_type.empty();
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  }
94  if (!found_postinstall) {
95    LOG(ERROR) << "No valid postinstall config found.";
96    return false;
97  }
98  return true;
99}
100
101bool ImageConfig::ImageInfoIsEmpty() const {
102  return image_info.board().empty()
103    && image_info.key().empty()
104    && image_info.channel().empty()
105    && image_info.version().empty()
106    && image_info.build_channel().empty()
107    && image_info.build_version().empty();
108}
109
110PayloadVersion::PayloadVersion(uint64_t major_version, uint32_t minor_version) {
111  major = major_version;
112  minor = minor_version;
113}
114
115bool PayloadVersion::Validate() const {
116  TEST_AND_RETURN_FALSE(major == kChromeOSMajorPayloadVersion ||
117                        major == kBrilloMajorPayloadVersion);
118  TEST_AND_RETURN_FALSE(minor == kFullPayloadMinorVersion ||
119                        minor == kInPlaceMinorPayloadVersion ||
120                        minor == kSourceMinorPayloadVersion ||
121                        minor == kOpSrcHashMinorPayloadVersion ||
122                        minor == kImgdiffMinorPayloadVersion);
123  return true;
124}
125
126bool PayloadVersion::OperationAllowed(InstallOperation_Type operation) const {
127  switch (operation) {
128    // Full operations:
129    case InstallOperation::REPLACE:
130    case InstallOperation::REPLACE_BZ:
131      // These operations were included in the original payload format.
132      return true;
133
134    case InstallOperation::ZERO:
135    case InstallOperation::DISCARD:
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    // Delta operations:
143    case InstallOperation::MOVE:
144    case InstallOperation::BSDIFF:
145      // MOVE and BSDIFF were replaced by SOURCE_COPY and SOURCE_BSDIFF and
146      // should not be used in newer delta versions, since the idempotent checks
147      // were removed.
148      return minor == kInPlaceMinorPayloadVersion;
149
150    case InstallOperation::SOURCE_COPY:
151    case InstallOperation::SOURCE_BSDIFF:
152      return minor >= kSourceMinorPayloadVersion;
153
154    case InstallOperation::IMGDIFF:
155      return minor >= kImgdiffMinorPayloadVersion && imgdiff_allowed;
156  }
157  return false;
158}
159
160bool PayloadVersion::IsDelta() const {
161  return minor != kFullPayloadMinorVersion;
162}
163
164bool PayloadVersion::InplaceUpdate() const {
165  return minor == kInPlaceMinorPayloadVersion;
166}
167
168bool PayloadGenerationConfig::Validate() const {
169  TEST_AND_RETURN_FALSE(version.Validate());
170  TEST_AND_RETURN_FALSE(version.IsDelta() == is_delta);
171  if (is_delta) {
172    for (const PartitionConfig& part : source.partitions) {
173      if (!part.path.empty()) {
174        TEST_AND_RETURN_FALSE(part.ValidateExists());
175        TEST_AND_RETURN_FALSE(part.size % block_size == 0);
176      }
177      // Source partition should not have postinstall.
178      TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
179    }
180
181    // If new_image_info is present, old_image_info must be present.
182    TEST_AND_RETURN_FALSE(source.ImageInfoIsEmpty() ==
183                          target.ImageInfoIsEmpty());
184  } else {
185    // All the "source" image fields must be empty for full payloads.
186    TEST_AND_RETURN_FALSE(source.ValidateIsEmpty());
187  }
188
189  // In all cases, the target image must exists.
190  for (const PartitionConfig& part : target.partitions) {
191    TEST_AND_RETURN_FALSE(part.ValidateExists());
192    TEST_AND_RETURN_FALSE(part.size % block_size == 0);
193    if (version.minor == kInPlaceMinorPayloadVersion &&
194        part.name == kLegacyPartitionNameRoot)
195      TEST_AND_RETURN_FALSE(rootfs_partition_size >= part.size);
196    if (version.major == kChromeOSMajorPayloadVersion)
197      TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
198  }
199
200  TEST_AND_RETURN_FALSE(hard_chunk_size == -1 ||
201                        hard_chunk_size % block_size == 0);
202  TEST_AND_RETURN_FALSE(soft_chunk_size % block_size == 0);
203
204  TEST_AND_RETURN_FALSE(rootfs_partition_size % block_size == 0);
205
206  return true;
207}
208
209}  // namespace chromeos_update_engine
210