mtd_file_descriptor.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //
  2. // Copyright (C) 2014 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. #include "update_engine/payload_consumer/mtd_file_descriptor.h"
  17. #include <fcntl.h>
  18. #include <mtd/ubi-user.h>
  19. #include <sys/ioctl.h>
  20. #include <sys/stat.h>
  21. #include <sys/types.h>
  22. #include <memory>
  23. #include <string>
  24. #include <base/files/file_path.h>
  25. #include <base/strings/string_number_conversions.h>
  26. #include <base/strings/string_util.h>
  27. #include <base/strings/stringprintf.h>
  28. #include "update_engine/common/subprocess.h"
  29. #include "update_engine/common/utils.h"
  30. using std::string;
  31. namespace {
  32. static const char kSysfsClassUbi[] = "/sys/class/ubi/";
  33. static const char kUsableEbSize[] = "/usable_eb_size";
  34. static const char kReservedEbs[] = "/reserved_ebs";
  35. using chromeos_update_engine::UbiVolumeInfo;
  36. using chromeos_update_engine::utils::ReadFile;
  37. // Return a UbiVolumeInfo pointer if |path| is a UBI volume. Otherwise, return
  38. // a null unique pointer.
  39. std::unique_ptr<UbiVolumeInfo> GetUbiVolumeInfo(const string& path) {
  40. base::FilePath device_node(path);
  41. base::FilePath ubi_name(device_node.BaseName());
  42. string sysfs_node(kSysfsClassUbi);
  43. sysfs_node.append(ubi_name.MaybeAsASCII());
  44. std::unique_ptr<UbiVolumeInfo> ret;
  45. // Obtain volume info from sysfs.
  46. string s_reserved_ebs;
  47. if (!ReadFile(sysfs_node + kReservedEbs, &s_reserved_ebs)) {
  48. LOG(ERROR) << "Cannot read " << sysfs_node + kReservedEbs;
  49. return ret;
  50. }
  51. string s_eb_size;
  52. if (!ReadFile(sysfs_node + kUsableEbSize, &s_eb_size)) {
  53. LOG(ERROR) << "Cannot read " << sysfs_node + kUsableEbSize;
  54. return ret;
  55. }
  56. base::TrimWhitespaceASCII(
  57. s_reserved_ebs, base::TRIM_TRAILING, &s_reserved_ebs);
  58. base::TrimWhitespaceASCII(s_eb_size, base::TRIM_TRAILING, &s_eb_size);
  59. uint64_t reserved_ebs, eb_size;
  60. if (!base::StringToUint64(s_reserved_ebs, &reserved_ebs)) {
  61. LOG(ERROR) << "Cannot parse reserved_ebs: " << s_reserved_ebs;
  62. return ret;
  63. }
  64. if (!base::StringToUint64(s_eb_size, &eb_size)) {
  65. LOG(ERROR) << "Cannot parse usable_eb_size: " << s_eb_size;
  66. return ret;
  67. }
  68. ret.reset(new UbiVolumeInfo);
  69. ret->reserved_ebs = reserved_ebs;
  70. ret->eraseblock_size = eb_size;
  71. return ret;
  72. }
  73. } // namespace
  74. namespace chromeos_update_engine {
  75. MtdFileDescriptor::MtdFileDescriptor()
  76. : read_ctx_(nullptr, &mtd_read_close),
  77. write_ctx_(nullptr, &mtd_write_close) {}
  78. bool MtdFileDescriptor::IsMtd(const char* path) {
  79. uint64_t size;
  80. return mtd_node_info(path, &size, nullptr, nullptr) == 0;
  81. }
  82. bool MtdFileDescriptor::Open(const char* path, int flags, mode_t mode) {
  83. // This File Descriptor does not support read and write.
  84. TEST_AND_RETURN_FALSE((flags & O_ACCMODE) != O_RDWR);
  85. // But we need to open the underlying file descriptor in O_RDWR mode because
  86. // during write, we need to read back to verify the write actually sticks or
  87. // we have to skip the block. That job is done by mtdutils library.
  88. if ((flags & O_ACCMODE) == O_WRONLY) {
  89. flags &= ~O_ACCMODE;
  90. flags |= O_RDWR;
  91. }
  92. TEST_AND_RETURN_FALSE(
  93. EintrSafeFileDescriptor::Open(path, flags | O_CLOEXEC, mode));
  94. if ((flags & O_ACCMODE) == O_RDWR) {
  95. write_ctx_.reset(mtd_write_descriptor(fd_, path));
  96. nr_written_ = 0;
  97. } else {
  98. read_ctx_.reset(mtd_read_descriptor(fd_, path));
  99. }
  100. if (!read_ctx_ && !write_ctx_) {
  101. Close();
  102. return false;
  103. }
  104. return true;
  105. }
  106. bool MtdFileDescriptor::Open(const char* path, int flags) {
  107. mode_t cur = umask(022);
  108. umask(cur);
  109. return Open(path, flags, 0777 & ~cur);
  110. }
  111. ssize_t MtdFileDescriptor::Read(void* buf, size_t count) {
  112. CHECK(read_ctx_);
  113. return mtd_read_data(read_ctx_.get(), static_cast<char*>(buf), count);
  114. }
  115. ssize_t MtdFileDescriptor::Write(const void* buf, size_t count) {
  116. CHECK(write_ctx_);
  117. ssize_t result =
  118. mtd_write_data(write_ctx_.get(), static_cast<const char*>(buf), count);
  119. if (result > 0) {
  120. nr_written_ += result;
  121. }
  122. return result;
  123. }
  124. off64_t MtdFileDescriptor::Seek(off64_t offset, int whence) {
  125. if (write_ctx_) {
  126. // Ignore seek in write mode.
  127. return nr_written_;
  128. }
  129. return EintrSafeFileDescriptor::Seek(offset, whence);
  130. }
  131. bool MtdFileDescriptor::Close() {
  132. read_ctx_.reset();
  133. write_ctx_.reset();
  134. return EintrSafeFileDescriptor::Close();
  135. }
  136. bool UbiFileDescriptor::IsUbi(const char* path) {
  137. base::FilePath device_node(path);
  138. base::FilePath ubi_name(device_node.BaseName());
  139. TEST_AND_RETURN_FALSE(base::StartsWith(
  140. ubi_name.MaybeAsASCII(), "ubi", base::CompareCase::SENSITIVE));
  141. return static_cast<bool>(GetUbiVolumeInfo(path));
  142. }
  143. bool UbiFileDescriptor::Open(const char* path, int flags, mode_t mode) {
  144. std::unique_ptr<UbiVolumeInfo> info = GetUbiVolumeInfo(path);
  145. if (!info) {
  146. return false;
  147. }
  148. // This File Descriptor does not support read and write.
  149. TEST_AND_RETURN_FALSE((flags & O_ACCMODE) != O_RDWR);
  150. TEST_AND_RETURN_FALSE(
  151. EintrSafeFileDescriptor::Open(path, flags | O_CLOEXEC, mode));
  152. usable_eb_blocks_ = info->reserved_ebs;
  153. eraseblock_size_ = info->eraseblock_size;
  154. volume_size_ = usable_eb_blocks_ * eraseblock_size_;
  155. if ((flags & O_ACCMODE) == O_WRONLY) {
  156. // It's best to use volume update ioctl so that UBI layer will mark the
  157. // volume as being updated, and only clear that mark if the update is
  158. // successful. We will need to pad to the whole volume size at close.
  159. uint64_t vsize = volume_size_;
  160. if (ioctl(fd_, UBI_IOCVOLUP, &vsize) != 0) {
  161. PLOG(ERROR) << "Cannot issue volume update ioctl";
  162. EintrSafeFileDescriptor::Close();
  163. return false;
  164. }
  165. mode_ = kWriteOnly;
  166. nr_written_ = 0;
  167. } else {
  168. mode_ = kReadOnly;
  169. }
  170. return true;
  171. }
  172. bool UbiFileDescriptor::Open(const char* path, int flags) {
  173. mode_t cur = umask(022);
  174. umask(cur);
  175. return Open(path, flags, 0777 & ~cur);
  176. }
  177. ssize_t UbiFileDescriptor::Read(void* buf, size_t count) {
  178. CHECK(mode_ == kReadOnly);
  179. return EintrSafeFileDescriptor::Read(buf, count);
  180. }
  181. ssize_t UbiFileDescriptor::Write(const void* buf, size_t count) {
  182. CHECK(mode_ == kWriteOnly);
  183. ssize_t nr_chunk = EintrSafeFileDescriptor::Write(buf, count);
  184. if (nr_chunk >= 0) {
  185. nr_written_ += nr_chunk;
  186. }
  187. return nr_chunk;
  188. }
  189. off64_t UbiFileDescriptor::Seek(off64_t offset, int whence) {
  190. if (mode_ == kWriteOnly) {
  191. // Ignore seek in write mode.
  192. return nr_written_;
  193. }
  194. return EintrSafeFileDescriptor::Seek(offset, whence);
  195. }
  196. bool UbiFileDescriptor::Close() {
  197. bool pad_ok = true;
  198. if (IsOpen() && mode_ == kWriteOnly) {
  199. char buf[1024];
  200. memset(buf, 0xFF, sizeof(buf));
  201. while (nr_written_ < volume_size_) {
  202. // We have written less than the whole volume. In order for us to clear
  203. // the update marker, we need to fill the rest. It is recommended to fill
  204. // UBI writes with 0xFF.
  205. uint64_t to_write = volume_size_ - nr_written_;
  206. if (to_write > sizeof(buf)) {
  207. to_write = sizeof(buf);
  208. }
  209. ssize_t nr_chunk = EintrSafeFileDescriptor::Write(buf, to_write);
  210. if (nr_chunk < 0) {
  211. LOG(ERROR) << "Cannot 0xFF-pad before closing.";
  212. // There is an error, but we can't really do any meaningful thing here.
  213. pad_ok = false;
  214. break;
  215. }
  216. nr_written_ += nr_chunk;
  217. }
  218. }
  219. return EintrSafeFileDescriptor::Close() && pad_ok;
  220. }
  221. } // namespace chromeos_update_engine