Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 1 | #include "host/commands/assemble_cvd/data_image.h" |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 2 | |
| 3 | #include <glog/logging.h> |
| 4 | |
| 5 | #include "common/libs/utils/files.h" |
| 6 | #include "common/libs/utils/subprocess.h" |
| 7 | |
| 8 | namespace { |
| 9 | const std::string kDataPolicyUseExisting = "use_existing"; |
| 10 | const std::string kDataPolicyCreateIfMissing = "create_if_missing"; |
| 11 | const std::string kDataPolicyAlwaysCreate = "always_create"; |
| 12 | const std::string kDataPolicyResizeUpTo= "resize_up_to"; |
| 13 | |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 14 | const int FSCK_ERROR_CORRECTED = 1; |
| 15 | const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2; |
| 16 | |
| 17 | bool ForceFsckImage(const char* data_image) { |
A. Cody Schuffelen | 64cb145 | 2020-03-04 15:34:57 -0800 | [diff] [blame] | 18 | auto fsck_path = vsoc::DefaultHostArtifactsPath("bin/fsck.f2fs"); |
| 19 | int fsck_status = cvd::execute({fsck_path, "-y", "-f", data_image}); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 20 | if (fsck_status & ~(FSCK_ERROR_CORRECTED|FSCK_ERROR_CORRECTED_REQUIRES_REBOOT)) { |
Alistair Delva | 4c70e26 | 2019-10-15 14:33:59 -0700 | [diff] [blame] | 21 | LOG(ERROR) << "`fsck.f2fs -y -f " << data_image << "` failed with code " |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 22 | << fsck_status; |
| 23 | return false; |
| 24 | } |
| 25 | return true; |
| 26 | } |
| 27 | |
| 28 | bool ResizeImage(const char* data_image, int data_image_mb) { |
| 29 | auto file_mb = cvd::FileSize(data_image) >> 20; |
| 30 | if (file_mb > data_image_mb) { |
| 31 | LOG(ERROR) << data_image << " is already " << file_mb << " MB, will not " |
| 32 | << "resize down."; |
| 33 | return false; |
| 34 | } else if (file_mb == data_image_mb) { |
| 35 | LOG(INFO) << data_image << " is already the right size"; |
| 36 | return true; |
| 37 | } else { |
| 38 | off_t raw_target = static_cast<off_t>(data_image_mb) << 20; |
A. Cody Schuffelen | 2271e4d | 2020-04-27 21:08:29 -0700 | [diff] [blame] | 39 | auto fd = cvd::SharedFD::Open(data_image, O_RDWR); |
| 40 | if (fd->Truncate(raw_target) != 0) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 41 | LOG(ERROR) << "`truncate --size=" << data_image_mb << "M " |
A. Cody Schuffelen | 2271e4d | 2020-04-27 21:08:29 -0700 | [diff] [blame] | 42 | << data_image << "` failed:" << fd->StrError(); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 43 | return false; |
| 44 | } |
| 45 | bool fsck_success = ForceFsckImage(data_image); |
| 46 | if (!fsck_success) { |
| 47 | return false; |
| 48 | } |
A. Cody Schuffelen | 64cb145 | 2020-03-04 15:34:57 -0800 | [diff] [blame] | 49 | auto resize_path = vsoc::DefaultHostArtifactsPath("bin/resize.f2fs"); |
| 50 | int resize_status = cvd::execute({resize_path, data_image}); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 51 | if (resize_status != 0) { |
Alistair Delva | 4c70e26 | 2019-10-15 14:33:59 -0700 | [diff] [blame] | 52 | LOG(ERROR) << "`resize.f2fs " << data_image << "` failed with code " |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 53 | << resize_status; |
| 54 | return false; |
| 55 | } |
| 56 | fsck_success = ForceFsckImage(data_image); |
| 57 | if (!fsck_success) { |
| 58 | return false; |
| 59 | } |
| 60 | } |
| 61 | return true; |
| 62 | } |
| 63 | } // namespace |
| 64 | |
Paul Trautrim | ba8f8e9 | 2019-03-12 17:55:48 +0900 | [diff] [blame] | 65 | void CreateBlankImage( |
Kenny Root | 1f50ee6 | 2020-01-24 12:06:19 -0800 | [diff] [blame] | 66 | const std::string& image, int block_count, const std::string& image_fmt, |
| 67 | const std::string& block_size) { |
Paul Trautrim | ba8f8e9 | 2019-03-12 17:55:48 +0900 | [diff] [blame] | 68 | LOG(INFO) << "Creating " << image; |
| 69 | std::string of = "of="; |
| 70 | of += image; |
| 71 | std::string count = "count="; |
Kenny Root | 1f50ee6 | 2020-01-24 12:06:19 -0800 | [diff] [blame] | 72 | count += std::to_string(block_count); |
| 73 | std::string bs = "bs=" + block_size; |
| 74 | cvd::execute({"/bin/dd", "if=/dev/zero", of, bs, count}); |
A. Cody Schuffelen | d77ae13 | 2020-03-04 18:47:31 -0800 | [diff] [blame] | 75 | if (image_fmt == "ext4") { |
| 76 | cvd::execute({"/sbin/mkfs.ext4", image}); |
| 77 | } else if (image_fmt != "none") { |
A. Cody Schuffelen | 64cb145 | 2020-03-04 15:34:57 -0800 | [diff] [blame] | 78 | auto make_f2fs_path = vsoc::DefaultHostArtifactsPath("bin/make_f2fs"); |
| 79 | cvd::execute({make_f2fs_path, "-t", image_fmt, image, "-g", "android"}); |
Paul Trautrim | ba8f8e9 | 2019-03-12 17:55:48 +0900 | [diff] [blame] | 80 | } |
| 81 | } |
| 82 | |
Cody Schuffelen | 3c99f5b | 2019-06-14 17:26:01 -0700 | [diff] [blame] | 83 | bool ApplyDataImagePolicy(const vsoc::CuttlefishConfig& config, |
| 84 | const std::string& data_image) { |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 85 | bool data_exists = cvd::FileHasContent(data_image.c_str()); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 86 | bool remove{}; |
| 87 | bool create{}; |
| 88 | bool resize{}; |
| 89 | |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 90 | if (config.data_policy() == kDataPolicyUseExisting) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 91 | if (!data_exists) { |
| 92 | LOG(ERROR) << "Specified data image file does not exists: " << data_image; |
| 93 | return false; |
| 94 | } |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 95 | if (config.blank_data_image_mb() > 0) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 96 | LOG(ERROR) << "You should NOT use -blank_data_image_mb with -data_policy=" |
| 97 | << kDataPolicyUseExisting; |
| 98 | return false; |
| 99 | } |
| 100 | create = false; |
| 101 | remove = false; |
| 102 | resize = false; |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 103 | } else if (config.data_policy() == kDataPolicyAlwaysCreate) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 104 | remove = data_exists; |
| 105 | create = true; |
| 106 | resize = false; |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 107 | } else if (config.data_policy() == kDataPolicyCreateIfMissing) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 108 | create = !data_exists; |
| 109 | remove = false; |
| 110 | resize = false; |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 111 | } else if (config.data_policy() == kDataPolicyResizeUpTo) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 112 | create = false; |
| 113 | remove = false; |
| 114 | resize = true; |
| 115 | } else { |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 116 | LOG(ERROR) << "Invalid data_policy: " << config.data_policy(); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 117 | return false; |
| 118 | } |
| 119 | |
| 120 | if (remove) { |
Jorge E. Moreira | 7b0059a | 2019-03-22 17:38:14 -0700 | [diff] [blame] | 121 | cvd::RemoveFile(data_image.c_str()); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | if (create) { |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 125 | if (config.blank_data_image_mb() <= 0) { |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 126 | LOG(ERROR) << "-blank_data_image_mb is required to create data image"; |
| 127 | return false; |
| 128 | } |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 129 | CreateBlankImage(data_image.c_str(), config.blank_data_image_mb(), |
| 130 | config.blank_data_image_fmt()); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 131 | } else if (resize) { |
| 132 | if (!data_exists) { |
| 133 | LOG(ERROR) << data_image << " does not exist, but resizing was requested"; |
| 134 | return false; |
| 135 | } |
Cody Schuffelen | 2b51bab | 2019-01-29 18:14:48 -0800 | [diff] [blame] | 136 | return ResizeImage(data_image.c_str(), config.blank_data_image_mb()); |
Cody Schuffelen | 3528908 | 2019-01-28 22:25:30 -0800 | [diff] [blame] | 137 | } else { |
| 138 | LOG(INFO) << data_image << " exists. Not creating it."; |
| 139 | } |
| 140 | |
| 141 | return true; |
| 142 | } |
Yifan Hong | 19d713e | 2019-05-01 14:12:07 -0700 | [diff] [blame] | 143 | |
| 144 | bool InitializeMiscImage(const std::string& misc_image) { |
| 145 | bool misc_exists = cvd::FileHasContent(misc_image.c_str()); |
| 146 | |
| 147 | if (misc_exists) { |
| 148 | LOG(INFO) << "misc partition image: use existing"; |
| 149 | return true; |
| 150 | } |
| 151 | |
| 152 | LOG(INFO) << "misc partition image: creating empty"; |
| 153 | CreateBlankImage(misc_image, 1 /* mb */, "none"); |
| 154 | return true; |
| 155 | } |