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