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