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