blob: 1b33d05b126db428de4b1558eed10288da26338e [file] [log] [blame]
Nam T. Nguyenf1d582e2014-12-08 15:07:17 -08001// Copyright 2014 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/mtd_file_descriptor.h"
6
7#include <fcntl.h>
8#include <mtd/ubi-user.h>
9#include <string>
10#include <sys/ioctl.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13
14#include <base/files/file_path.h>
15#include <base/strings/string_number_conversions.h>
16
17#include "update_engine/utils.h"
18
19namespace {
20
21static const char kSysfsClassUbi[] = "/sys/class/ubi/";
22static const char kUsableEbSize[] = "/usable_eb_size";
23static const char kReservedEbs[] = "/reserved_ebs";
24
25using chromeos_update_engine::UbiVolumeInfo;
26using chromeos_update_engine::utils::ReadFile;
27
28// Return a UbiVolumeInfo pointer if |path| is a UBI volume. Otherwise, return
29// a null unique pointer.
30std::unique_ptr<UbiVolumeInfo> GetUbiVolumeInfo(const char* path) {
31 base::FilePath device_node(path);
32 base::FilePath ubi_name(device_node.BaseName());
33
34 std::string sysfs_node(kSysfsClassUbi);
35 sysfs_node.append(ubi_name.MaybeAsASCII());
36
37 std::unique_ptr<UbiVolumeInfo> ret;
38
39 // Obtain volume info from sysfs.
40 std::string s_reserved_ebs;
41 if (!ReadFile(sysfs_node + kReservedEbs, &s_reserved_ebs)) {
42 return ret;
43 }
44 std::string s_eb_size;
45 if (!ReadFile(sysfs_node + kUsableEbSize, &s_eb_size)) {
46 return ret;
47 }
48
49 size_t reserved_ebs, eb_size;
50 if (!base::StringToSizeT(s_reserved_ebs, &reserved_ebs)) {
51 return ret;
52 }
53 if (!base::StringToSizeT(s_eb_size, &eb_size)) {
54 return ret;
55 }
56
57 ret.reset(new UbiVolumeInfo);
58 ret->size = reserved_ebs * eb_size;
59 return ret;
60}
61
62} // namespace
63
64namespace chromeos_update_engine {
65
66MtdFileDescriptor::MtdFileDescriptor()
67 : read_ctx_(nullptr, &mtd_read_close),
68 write_ctx_(nullptr, &mtd_write_close) {}
69
70bool MtdFileDescriptor::IsMtd(const char* path) {
71 uint64_t size;
72 return mtd_node_info(path, &size, nullptr, nullptr) == 0;
73}
74
75bool MtdFileDescriptor::Open(const char* path, int flags, mode_t mode) {
76 // This File Descriptor does not support read and write.
77 TEST_AND_RETURN_FALSE((flags & O_RDWR) != O_RDWR);
78 TEST_AND_RETURN_FALSE(
79 EintrSafeFileDescriptor::Open(path, flags | O_CLOEXEC, mode));
80
81 if (flags & O_RDONLY) {
82 read_ctx_.reset(mtd_read_descriptor(fd_, path));
83 } else if (flags & O_WRONLY) {
84 write_ctx_.reset(mtd_write_descriptor(fd_, path));
85 }
86
87 if (!read_ctx_ && !write_ctx_) {
88 Close();
89 return false;
90 }
91
92 return true;
93}
94
95bool MtdFileDescriptor::Open(const char* path, int flags) {
96 mode_t cur = umask(022);
97 umask(cur);
98 return Open(path, flags, 0777 & ~cur);
99}
100
101ssize_t MtdFileDescriptor::Read(void* buf, size_t count) {
102 CHECK(read_ctx_);
103 return mtd_read_data(read_ctx_.get(), static_cast<char*>(buf), count);
104}
105
106ssize_t MtdFileDescriptor::Write(const void* buf, size_t count) {
107 CHECK(write_ctx_);
108 return mtd_write_data(write_ctx_.get(), static_cast<const char*>(buf), count);
109}
110
111off64_t MtdFileDescriptor::Seek(off64_t offset, int whence) {
112 CHECK(read_ctx_);
113 return EintrSafeFileDescriptor::Seek(offset, whence);
114}
115
116void MtdFileDescriptor::Reset() {
117 EintrSafeFileDescriptor::Reset();
118 read_ctx_.reset();
119 write_ctx_.reset();
120}
121
122bool UbiFileDescriptor::IsUbi(const char* path) {
123 return static_cast<bool>(GetUbiVolumeInfo(path));
124}
125
126std::unique_ptr<UbiVolumeInfo> UbiFileDescriptor::CreateWriteContext(
127 const char* path) {
128 std::unique_ptr<UbiVolumeInfo> info = GetUbiVolumeInfo(path);
129 uint64_t volume_size;
130 if (info && (ioctl(fd_, UBI_IOCVOLUP, &volume_size) != 0 ||
131 volume_size != info->size)) {
132 info.reset();
133 }
134 return info;
135}
136
137bool UbiFileDescriptor::Open(const char* path, int flags, mode_t mode) {
138 // This File Descriptor does not support read and write.
139 TEST_AND_RETURN_FALSE((flags & O_RDWR) != O_RDWR);
140 TEST_AND_RETURN_FALSE(
141 EintrSafeFileDescriptor::Open(path, flags | O_CLOEXEC, mode));
142
143 if (flags & O_RDONLY) {
144 read_ctx_ = GetUbiVolumeInfo(path);
145 } else if (flags & O_WRONLY) {
146 write_ctx_ = CreateWriteContext(path);
147 }
148
149 if (!read_ctx_ && !write_ctx_) {
150 Close();
151 return false;
152 }
153
154 return true;
155}
156
157bool UbiFileDescriptor::Open(const char* path, int flags) {
158 mode_t cur = umask(022);
159 umask(cur);
160 return Open(path, flags, 0777 & ~cur);
161}
162
163ssize_t UbiFileDescriptor::Read(void* buf, size_t count) {
164 CHECK(read_ctx_);
165 return EintrSafeFileDescriptor::Read(buf, count);
166}
167
168ssize_t UbiFileDescriptor::Write(const void* buf, size_t count) {
169 CHECK(write_ctx_);
170 return EintrSafeFileDescriptor::Write(buf, count);
171}
172
173off64_t UbiFileDescriptor::Seek(off64_t offset, int whence) {
174 CHECK(read_ctx_);
175 return EintrSafeFileDescriptor::Seek(offset, whence);
176}
177
178void UbiFileDescriptor::Reset() {
179 EintrSafeFileDescriptor::Reset();
180 read_ctx_.reset();
181 write_ctx_.reset();
182}
183
184} // namespace chromeos_update_engine