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/disk_utils.h"
31 #include "utils/file_utils.h"
32 #include "utils/string_utils.h"
33 #include "volume/process.h"
34
35 using namespace std;
36 namespace OHOS {
37 namespace StorageDaemon {
ReadMetadata()38 int32_t ExternalVolumeInfo::ReadMetadata()
39 {
40 int32_t ret = OHOS::StorageDaemon::ReadMetadata(devPath_, fsUuid_, fsType_, fsLabel_);
41 if (fsType_ == "ntfs") {
42 std::vector<std::string> cmd;
43 cmd = {
44 "ntfslabel",
45 devPath_
46 };
47 fsLabel_ = GetBlkidDataByCmd(cmd);
48 }
49 return ret;
50 }
51
GetFsType()52 int32_t ExternalVolumeInfo::GetFsType()
53 {
54 for (uint32_t i = 0; i < supportMountType_.size(); i++) {
55 if (supportMountType_[i].compare(fsType_) == 0) {
56 return i;
57 }
58 }
59 return -1;
60 }
61
GetFsUuid()62 std::string ExternalVolumeInfo::GetFsUuid()
63 {
64 return fsUuid_;
65 }
66
GetFsLabel()67 std::string ExternalVolumeInfo::GetFsLabel()
68 {
69 return fsLabel_;
70 }
71
GetMountPath()72 std::string ExternalVolumeInfo::GetMountPath()
73 {
74 return mountPath_;
75 }
76
DoCreate(dev_t dev)77 int32_t ExternalVolumeInfo::DoCreate(dev_t dev)
78 {
79 int32_t ret = 0;
80 string id = VolumeInfo::GetVolumeId();
81
82 device_ = dev;
83 devPath_ = StringPrintf(devPathDir_.c_str(), (id).c_str());
84
85 ret = mknod(devPath_.c_str(), S_IFBLK, dev);
86 if (ret) {
87 LOGE("External volume DoCreate error.");
88 return E_ERR;
89 }
90
91 return E_OK;
92 }
93
DoDestroy()94 int32_t ExternalVolumeInfo::DoDestroy()
95 {
96 int err = remove(devPath_.c_str());
97 if (err) {
98 LOGE("External volume DoDestroy error.");
99 return E_ERR;
100 }
101 return E_OK;
102 }
103
DoMount4Ext(uint32_t mountFlags)104 int32_t ExternalVolumeInfo::DoMount4Ext(uint32_t mountFlags)
105 {
106 mode_t mode = 0777;
107 int32_t ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, "");
108 if (!ret) {
109 TravelChmod(mountPath_, mode);
110 }
111 return ret;
112 }
113
DoMount4Ntfs(uint32_t mountFlags)114 int32_t ExternalVolumeInfo::DoMount4Ntfs(uint32_t mountFlags)
115 {
116 auto mountData = StringPrintf("rw,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
117 if (mountFlags & MS_RDONLY) {
118 mountData = StringPrintf("ro,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
119 }
120
121 std::vector<std::string> cmd = {
122 "mount.ntfs",
123 devPath_,
124 mountPath_,
125 "-o",
126 mountData.c_str()
127 };
128 return ForkExec(cmd);
129 }
130
DoMount4Exfat(uint32_t mountFlags)131 int32_t ExternalVolumeInfo::DoMount4Exfat(uint32_t mountFlags)
132 {
133 auto mountData = StringPrintf("rw,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
134 if (mountFlags & MS_RDONLY) {
135 mountData = StringPrintf("ro,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
136 }
137
138 std::vector<std::string> cmd = {
139 "mount.exfat",
140 "-o",
141 mountData.c_str(),
142 devPath_,
143 mountPath_,
144 };
145 return ForkExec(cmd);
146 }
147
DoMount4OtherType(uint32_t mountFlags)148 int32_t ExternalVolumeInfo::DoMount4OtherType(uint32_t mountFlags)
149 {
150 mountFlags |= MS_MGC_VAL;
151 auto mountData = StringPrintf("uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
152 return mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, mountData.c_str());
153 }
154
DoMount4Vfat(uint32_t mountFlags)155 int32_t ExternalVolumeInfo::DoMount4Vfat(uint32_t mountFlags)
156 {
157 mountFlags |= MS_MGC_VAL;
158 auto mountData = StringPrintf("uid=%d,gid=%d,dmask=0007,fmask=0007,utf8", UID_FILE_MANAGER, UID_FILE_MANAGER);
159 return mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, mountData.c_str());
160 }
161
DoMount(uint32_t mountFlags)162 int32_t ExternalVolumeInfo::DoMount(uint32_t mountFlags)
163 {
164 int32_t ret = DoCheck();
165 if (ret != E_OK) {
166 LOGE("External volume uuid=%{public}s check failed.", GetAnonyString(GetFsUuid()).c_str());
167 return ret;
168 }
169
170 struct stat statbuf;
171 mountPath_ = StringPrintf(mountPathDir_.c_str(), fsUuid_.c_str());
172 if (!lstat(mountPath_.c_str(), &statbuf)) {
173 LOGE("volume mount path %{public}s exists, please remove first", GetMountPath().c_str());
174 return E_MOUNT;
175 }
176 ret = mkdir(mountPath_.c_str(), S_IRWXU | S_IRWXG | S_IXOTH);
177 if (ret) {
178 LOGE("the volume %{public}s create mount file %{public}s failed",
179 GetVolumeId().c_str(), GetMountPath().c_str());
180 return E_MOUNT;
181 }
182
183 LOGI("Ready to mount: external volume fstype is %{public}s, mountflag is %{public}d", fsType_.c_str(), mountFlags);
184 if (fsType_ == "ext2" || fsType_ == "ext3" || fsType_ == "ext4") {
185 ret = DoMount4Ext(mountFlags);
186 } else if (fsType_ == "ntfs") {
187 ret = DoMount4Ntfs(mountFlags);
188 } else if (fsType_ == "exfat") {
189 ret = DoMount4Exfat(mountFlags);
190 } else if (fsType_ == "vfat" || fsType_ == "fat32") {
191 ret = DoMount4Vfat(mountFlags);
192 } else {
193 ret = DoMount4OtherType(mountFlags);
194 }
195
196 if (ret) {
197 LOGE("External volume DoMount error, errno = %{public}d", errno);
198 remove(mountPath_.c_str());
199 return E_MOUNT;
200 }
201
202 return E_OK;
203 }
204
DoUMount(bool force)205 int32_t ExternalVolumeInfo::DoUMount(bool force)
206 {
207 if (force) {
208 LOGI("External volume start force to unmount.");
209 Process ps(mountPath_);
210 ps.UpdatePidByPath();
211 ps.KillProcess(SIGKILL);
212 umount2(mountPath_.c_str(), MNT_DETACH);
213 remove(mountPath_.c_str());
214 LOGI("External volume force to unmount success.");
215 return E_OK;
216 }
217 LOGI("External volume start to unmount.");
218 int ret = umount(mountPath_.c_str());
219 int err = remove(mountPath_.c_str());
220 if (err && ret) {
221 LOGE("External volume DoUmount error.");
222 return E_UMOUNT;
223 }
224
225 if (err) {
226 LOGE("failed to call remove(%{public}s) error, errno = %{public}d", mountPath_.c_str(), errno);
227 return E_SYS_CALL;
228 }
229 LOGI("External volume unmount success.");
230 return E_OK;
231 }
232
DoCheck()233 int32_t ExternalVolumeInfo::DoCheck()
234 {
235 int32_t ret = ExternalVolumeInfo::ReadMetadata();
236 if (ret) {
237 LOGE("External volume uuid=%{public}s DoCheck failed.", GetAnonyString(GetFsUuid()).c_str());
238 return E_ERR;
239 }
240
241 // check fstype
242 if (GetFsType() == -1) {
243 LOGE("External Volume type not support.");
244 return E_NOT_SUPPORT;
245 }
246 return E_OK;
247 }
248
DoFormat(std::string type)249 int32_t ExternalVolumeInfo::DoFormat(std::string type)
250 {
251 int32_t err = 0;
252 std::map<std::string, std::string>::iterator iter = supportFormatType_.find(type);
253 if (iter == supportFormatType_.end()) {
254 LOGE("External volume format not support.");
255 return E_NOT_SUPPORT;
256 }
257
258 if (type == "vfat") {
259 std::vector<std::string> cmd = {
260 iter->second,
261 "-A",
262 devPath_
263 };
264 err = ForkExec(cmd);
265 } else {
266 std::vector<std::string> cmd = {
267 iter->second,
268 devPath_
269 };
270 err = ForkExec(cmd);
271 }
272
273 if (err == E_NO_CHILD) {
274 err = E_OK;
275 }
276
277 ReadMetadata();
278 return err;
279 }
280
DoSetVolDesc(std::string description)281 int32_t ExternalVolumeInfo::DoSetVolDesc(std::string description)
282 {
283 int32_t err = 0;
284 if (fsType_ == "ntfs") {
285 std::vector<std::string> cmd = {
286 "ntfslabel",
287 devPath_,
288 description
289 };
290 err = ForkExec(cmd);
291 } else if (fsType_ == "exfat") {
292 std::vector<std::string> cmd = {
293 "exfatlabel",
294 devPath_,
295 description
296 };
297 err = ForkExec(cmd);
298 } else {
299 LOGE("SetVolumeDescription fsType not support.");
300 return E_NOT_SUPPORT;
301 }
302
303 ReadMetadata();
304 return err;
305 }
306 } // StorageDaemon
307 } // OHOS
308