• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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