1 #include "host/commands/launch/data_image.h"
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
14 const int FSCK_ERROR_CORRECTED = 1;
15 const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2;
16
ForceFsckImage(const char * data_image)17 bool ForceFsckImage(const char* data_image) {
18 int fsck_status = cvd::execute({"/sbin/e2fsck", "-y", "-f", data_image});
19 if (fsck_status & ~(FSCK_ERROR_CORRECTED|FSCK_ERROR_CORRECTED_REQUIRES_REBOOT)) {
20 LOG(ERROR) << "`e2fsck -y -f " << data_image << "` failed with code "
21 << fsck_status;
22 return false;
23 }
24 return true;
25 }
26
ResizeImage(const char * data_image,int data_image_mb)27 bool ResizeImage(const char* data_image, int data_image_mb) {
28 auto file_mb = cvd::FileSize(data_image) >> 20;
29 if (file_mb > data_image_mb) {
30 LOG(ERROR) << data_image << " is already " << file_mb << " MB, will not "
31 << "resize down.";
32 return false;
33 } else if (file_mb == data_image_mb) {
34 LOG(INFO) << data_image << " is already the right size";
35 return true;
36 } else {
37 off_t raw_target = static_cast<off_t>(data_image_mb) << 20;
38 int truncate_status =
39 cvd::SharedFD::Open(data_image, O_RDWR)->Truncate(raw_target);
40 if (truncate_status != 0) {
41 LOG(ERROR) << "`truncate --size=" << data_image_mb << "M "
42 << data_image << "` failed with code " << truncate_status;
43 return false;
44 }
45 bool fsck_success = ForceFsckImage(data_image);
46 if (!fsck_success) {
47 return false;
48 }
49 int resize_status = cvd::execute({"/sbin/resize2fs", data_image});
50 if (resize_status != 0) {
51 LOG(ERROR) << "`resize2fs " << data_image << "` failed with code "
52 << resize_status;
53 return false;
54 }
55 fsck_success = ForceFsckImage(data_image);
56 if (!fsck_success) {
57 return false;
58 }
59 }
60 return true;
61 }
62 } // namespace
63
CreateBlankImage(const std::string & image,int image_mb,const std::string & image_fmt)64 void CreateBlankImage(
65 const std::string& image, int image_mb, const std::string& image_fmt) {
66 LOG(INFO) << "Creating " << image;
67 std::string of = "of=";
68 of += image;
69 std::string count = "count=";
70 count += std::to_string(image_mb);
71 cvd::execute({"/bin/dd", "if=/dev/zero", of, "bs=1M", count});
72 if (image_fmt != "none") {
73 cvd::execute({"/sbin/mkfs", "-t", image_fmt, image}, {"PATH=/sbin"});
74 }
75 }
76
ApplyDataImagePolicy(const vsoc::CuttlefishConfig & config)77 bool ApplyDataImagePolicy(const vsoc::CuttlefishConfig& config) {
78 std::string data_image = config.data_image_path();
79 bool data_exists = cvd::FileHasContent(data_image.c_str());
80 bool remove{};
81 bool create{};
82 bool resize{};
83
84 if (config.data_policy() == kDataPolicyUseExisting) {
85 if (!data_exists) {
86 LOG(ERROR) << "Specified data image file does not exists: " << data_image;
87 return false;
88 }
89 if (config.blank_data_image_mb() > 0) {
90 LOG(ERROR) << "You should NOT use -blank_data_image_mb with -data_policy="
91 << kDataPolicyUseExisting;
92 return false;
93 }
94 create = false;
95 remove = false;
96 resize = false;
97 } else if (config.data_policy() == kDataPolicyAlwaysCreate) {
98 remove = data_exists;
99 create = true;
100 resize = false;
101 } else if (config.data_policy() == kDataPolicyCreateIfMissing) {
102 create = !data_exists;
103 remove = false;
104 resize = false;
105 } else if (config.data_policy() == kDataPolicyResizeUpTo) {
106 create = false;
107 remove = false;
108 resize = true;
109 } else {
110 LOG(ERROR) << "Invalid data_policy: " << config.data_policy();
111 return false;
112 }
113
114 if (remove) {
115 cvd::RemoveFile(data_image.c_str());
116 }
117
118 if (create) {
119 if (config.blank_data_image_mb() <= 0) {
120 LOG(ERROR) << "-blank_data_image_mb is required to create data image";
121 return false;
122 }
123 CreateBlankImage(data_image.c_str(), config.blank_data_image_mb(),
124 config.blank_data_image_fmt());
125 } else if (resize) {
126 if (!data_exists) {
127 LOG(ERROR) << data_image << " does not exist, but resizing was requested";
128 return false;
129 }
130 return ResizeImage(data_image.c_str(), config.blank_data_image_mb());
131 } else {
132 LOG(INFO) << data_image << " exists. Not creating it.";
133 }
134
135 return true;
136 }
137