1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "volume/external_volume_info.h"
17
18 #include <algorithm>
19 #include <cerrno>
20 #include <csignal>
21 #include <cstdlib>
22 #include <cstring>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27
28 #include "storage_service_errno.h"
29 #include "storage_service_log.h"
30 #include "utils/file_utils.h"
31 #include "utils/string_utils.h"
32 #include "volume/process.h"
33
34 using namespace std;
35 namespace OHOS {
36 namespace StorageDaemon {
GetBlkidData(const std::string type)37 std::string ExternalVolumeInfo::GetBlkidData(const std::string type)
38 {
39 std::vector<std::string> output;
40 std::vector<std::string> cmd;
41 if (fsType_ == "ntfs" && type == "LABEL") {
42 cmd = {
43 "ntfslabel",
44 devPath_
45 };
46 } else {
47 cmd = {
48 "blkid",
49 "-s",
50 type,
51 "-o",
52 "value",
53 devPath_
54 };
55 }
56
57 int32_t err = ForkExec(cmd, &output);
58 if (err) {
59 return "";
60 }
61
62 if (output.size() > 0) {
63 size_t sep = string::npos;
64 sep = output[0].find_first_of("\n");
65 if (sep != string::npos)
66 output[0].resize(sep);
67 return output[0];
68 }
69 return "";
70 }
71
ReadMetadata()72 int32_t ExternalVolumeInfo::ReadMetadata()
73 {
74 fsUuid_ = GetBlkidData("UUID");
75 fsType_ = GetBlkidData("TYPE");
76 fsLabel_ = GetBlkidData("LABEL");
77
78 if (fsUuid_.empty() || fsType_.empty()) {
79 LOGE("External volume ReadMetadata error.");
80 return E_ERR;
81 }
82 LOGI("ReadMetadata, fsUuid=%{public}s, fsType=%{public}d, fsLabel=%{public}s.",
83 GetFsUuid().c_str(), GetFsType(), GetFsLabel().c_str());
84 return E_OK;
85 }
86
GetFsType()87 int32_t ExternalVolumeInfo::GetFsType()
88 {
89 for (uint32_t i = 0; i < supportMountType_.size(); i++) {
90 if (supportMountType_[i].compare(fsType_) == 0) {
91 return i;
92 }
93 }
94 return -1;
95 }
96
GetFsUuid()97 std::string ExternalVolumeInfo::GetFsUuid()
98 {
99 return fsUuid_;
100 }
101
GetFsLabel()102 std::string ExternalVolumeInfo::GetFsLabel()
103 {
104 return fsLabel_;
105 }
106
GetMountPath()107 std::string ExternalVolumeInfo::GetMountPath()
108 {
109 return mountPath_;
110 }
111
DoCreate(dev_t dev)112 int32_t ExternalVolumeInfo::DoCreate(dev_t dev)
113 {
114 int32_t ret = 0;
115 string id = VolumeInfo::GetVolumeId();
116
117 device_ = dev;
118 devPath_ = StringPrintf(devPathDir_.c_str(), (id).c_str());
119
120 ret = mknod(devPath_.c_str(), S_IFBLK, dev);
121 if (ret) {
122 LOGE("External volume DoCreate error.");
123 return E_ERR;
124 }
125
126 return E_OK;
127 }
128
DoDestroy()129 int32_t ExternalVolumeInfo::DoDestroy()
130 {
131 int err = remove(devPath_.c_str());
132 if (err) {
133 LOGE("External volume DoDestroy error.");
134 return E_ERR;
135 }
136 return E_OK;
137 }
138
DoMount(uint32_t mountFlags)139 int32_t ExternalVolumeInfo::DoMount(uint32_t mountFlags)
140 {
141 int32_t ret = 0;
142 mode_t mode = 0777;
143 struct stat statbuf;
144
145 if (GetFsType() == -1) {
146 return E_NOT_SUPPORT;
147 }
148
149 ret = ReadMetadata();
150 if (ret) {
151 LOGE("External volume ReadMetadata failed.");
152 return E_ERR;
153 }
154 mountPath_ = StringPrintf(mountPathDir_.c_str(), fsUuid_.c_str());
155
156 // check if dir exists
157 ret = lstat(mountPath_.c_str(), &statbuf);
158 if (!ret) {
159 LOGE("volume mount path %{public}s exists, please remove first", GetMountPath().c_str());
160 return E_MOUNT;
161 }
162
163 ret = mkdir(mountPath_.c_str(), S_IRWXU | S_IRWXG | S_IXOTH);
164 if (ret) {
165 LOGE("the volume %{public}s create mount file %{public}s failed",
166 GetVolumeId().c_str(), GetMountPath().c_str());
167 return E_MOUNT;
168 }
169
170 auto mountData = StringPrintf("uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
171 if (fsType_ == "ext2" || fsType_ == "ext3" || fsType_ == "ext4") {
172 ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, "");
173 if (!ret) {
174 TravelChmod(mountPath_, mode);
175 }
176 } else if (fsType_ == "ntfs") {
177 if (mountFlags & MS_RDONLY) {
178 mountData = StringPrintf("ro,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
179 } else {
180 mountData = StringPrintf("rw,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
181 }
182 std::vector<std::string> cmd = {
183 "mount.ntfs",
184 devPath_,
185 mountPath_,
186 "-o",
187 mountData.c_str()
188 };
189 ret = ForkExec(cmd);
190 } else {
191 mountFlags |= MS_MGC_VAL;
192 ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, mountData.c_str());
193 }
194
195 if (ret) {
196 LOGE("External volume DoMount error.");
197 remove(mountPath_.c_str());
198 return E_MOUNT;
199 }
200
201 return E_OK;
202 }
203
DoUMount(bool force)204 int32_t ExternalVolumeInfo::DoUMount(bool force)
205 {
206 if (force) {
207 LOGI("External volume start force to unmount.");
208 Process ps(mountPath_);
209 ps.UpdatePidByPath();
210 ps.KillProcess(SIGKILL);
211 umount2(mountPath_.c_str(), MNT_DETACH);
212 remove(mountPath_.c_str());
213 return E_OK;
214 }
215
216 int ret = umount(mountPath_.c_str());
217 int err = remove(mountPath_.c_str());
218 if (err && ret) {
219 LOGE("External volume DoUmount error.");
220 return E_UMOUNT;
221 }
222
223 if (err) {
224 LOGE("failed to call remove(%{public}s) error, errno = %{public}d", mountPath_.c_str(), errno);
225 return E_SYS_CALL;
226 }
227 return E_OK;
228 }
229
DoCheck()230 int32_t ExternalVolumeInfo::DoCheck()
231 {
232 int32_t ret = ExternalVolumeInfo::ReadMetadata();
233 if (ret) {
234 LOGE("External volume uuid=%{public}s DoCheck failed.", GetFsUuid().c_str());
235 return E_ERR;
236 }
237
238 // check fstype
239 if (GetFsType() == -1) {
240 LOGE("External Volume type not support.");
241 return E_NOT_SUPPORT;
242 }
243 return E_OK;
244 }
245
DoFormat(std::string type)246 int32_t ExternalVolumeInfo::DoFormat(std::string type)
247 {
248 int32_t err = 0;
249 std::map<std::string, std::string>::iterator iter = supportFormatType_.find(type);
250 if (iter == supportFormatType_.end()) {
251 LOGE("External volume format not support.");
252 return E_NOT_SUPPORT;
253 }
254
255 if (type == "vfat") {
256 std::vector<std::string> cmd = {
257 iter->second,
258 "-A",
259 devPath_
260 };
261 err = ForkExec(cmd);
262 } else {
263 std::vector<std::string> cmd = {
264 iter->second,
265 devPath_
266 };
267 err = ForkExec(cmd);
268 }
269
270 if (err == E_NO_CHILD) {
271 err = E_OK;
272 }
273
274 ReadMetadata();
275 return err;
276 }
277
DoSetVolDesc(std::string description)278 int32_t ExternalVolumeInfo::DoSetVolDesc(std::string description)
279 {
280 int32_t err = 0;
281 if (fsType_ == "ntfs") {
282 std::vector<std::string> cmd = {
283 "ntfslabel",
284 devPath_,
285 description
286 };
287 err = ForkExec(cmd);
288 } else if (fsType_ == "exfat") {
289 std::vector<std::string> cmd = {
290 "exfatlabel",
291 devPath_,
292 description
293 };
294 err = ForkExec(cmd);
295 } else if (fsType_ == "vfat") {
296 std::vector<std::string> cmd = {
297 "newfs_msdos",
298 "-L",
299 description,
300 devPath_
301 };
302 err = ForkExec(cmd);
303 } else {
304 LOGE("SetVolumeDescription fsType not support.");
305 return E_NOT_SUPPORT;
306 }
307
308 ReadMetadata();
309 return err;
310 }
311 } // StorageDaemon
312 } // OHOS
313