blob: b8cf4eb9ab3c3cafcb233a99d9c228305a5b4445 [file] [log] [blame]
Tom Marshall292bd232019-01-04 14:37:31 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 * Copyright (C) 2019 The LineageOS Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "Utils.h"
19#include <volume_manager/VolumeManager.h>
20#include "Process.h"
21#include "sehandle.h"
22
23#include <android-base/file.h>
24#include <android-base/logging.h>
25#include <android-base/properties.h>
26#include <android-base/stringprintf.h>
27
28#include <cutils/fs.h>
29#include <private/android_filesystem_config.h>
30
31#include <dirent.h>
32#include <fcntl.h>
33#include <linux/fs.h>
34#include <stdlib.h>
35#include <sys/mount.h>
36#include <sys/stat.h>
37#include <sys/statvfs.h>
38#include <sys/sysmacros.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41#include <mutex>
42#include <thread>
43
44#ifndef UMOUNT_NOFOLLOW
45#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
46#endif
47
48using android::base::ReadFileToString;
49using android::base::StringPrintf;
50
51using namespace std::chrono_literals;
52
53namespace android {
54namespace volmgr {
55
56char* sBlkidContext = nullptr;
57char* sBlkidUntrustedContext = nullptr;
58char* sFsckContext = nullptr;
59char* sFsckUntrustedContext = nullptr;
60
61#include <blkid/blkid.h>
62
63static const char* kProcFilesystems = "/proc/filesystems";
64
65status_t CreateDeviceNode(const std::string& path, dev_t dev) {
66 const char* cpath = path.c_str();
67 status_t res = 0;
68
69 char* secontext = nullptr;
70 if (sehandle) {
71 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
72 setfscreatecon(secontext);
73 }
74 }
75
76 mode_t mode = 0660 | S_IFBLK;
77 if (mknod(cpath, mode, dev) < 0) {
78 if (errno != EEXIST) {
79 PLOG(ERROR) << "Failed to create device node for " << major(dev) << ":" << minor(dev)
80 << " at " << path;
81 res = -errno;
82 }
83 }
84
85 if (secontext) {
86 setfscreatecon(nullptr);
87 freecon(secontext);
88 }
89
90 return res;
91}
92
93status_t DestroyDeviceNode(const std::string& path) {
94 const char* cpath = path.c_str();
95 if (TEMP_FAILURE_RETRY(unlink(cpath))) {
96 return -errno;
97 } else {
98 return OK;
99 }
100}
101
102status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
103 const char* cpath = path.c_str();
104
105 char* secontext = nullptr;
106 if (sehandle) {
107 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
108 setfscreatecon(secontext);
109 }
110 }
111
112 int res = fs_prepare_dir(cpath, mode, uid, gid);
113
114 if (secontext) {
115 setfscreatecon(nullptr);
116 freecon(secontext);
117 }
118
119 if (res == 0) {
120 return OK;
121 } else {
122 return -errno;
123 }
124}
125
126status_t ForceUnmount(const std::string& path, bool detach /* = false */) {
127 const char* cpath = path.c_str();
128 if (detach) {
129 if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL ||
130 errno == ENOENT) {
131 return OK;
132 }
133 PLOG(WARNING) << "Failed to unmount " << path;
134 return -errno;
135 }
136 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
137 return OK;
138 }
139 sleep(1);
140
141 Process::killProcessesWithOpenFiles(cpath, SIGINT);
142 sleep(1);
143 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
144 return OK;
145 }
146
147 Process::killProcessesWithOpenFiles(cpath, SIGTERM);
148 sleep(1);
149 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
150 return OK;
151 }
152
153 Process::killProcessesWithOpenFiles(cpath, SIGKILL);
154 sleep(1);
155 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
156 return OK;
157 }
158
159 return -errno;
160}
161
162status_t KillProcessesUsingPath(const std::string& path) {
163 const char* cpath = path.c_str();
164 if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) {
165 return OK;
166 }
167 sleep(1);
168
169 if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) {
170 return OK;
171 }
172 sleep(1);
173
174 if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
175 return OK;
176 }
177 sleep(1);
178
179 // Send SIGKILL a second time to determine if we've
180 // actually killed everyone with open files
181 if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
182 return OK;
183 }
184 PLOG(ERROR) << "Failed to kill processes using " << path;
185 return -EBUSY;
186}
187
188status_t BindMount(const std::string& source, const std::string& target) {
189 if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
190 PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
191 return -errno;
192 }
193 return OK;
194}
195
196static status_t readMetadata(const std::string& path, std::string& fsType, std::string& fsUuid,
197 std::string& fsLabel) {
198 char* val = NULL;
199 val = blkid_get_tag_value(NULL, "TYPE", path.c_str());
200 if (val) {
201 fsType = val;
202 }
203 val = blkid_get_tag_value(NULL, "UUID", path.c_str());
204 if (val) {
205 fsUuid = val;
206 }
207 val = blkid_get_tag_value(NULL, "LABEL", path.c_str());
208 if (val) {
209 fsLabel = val;
210 }
211
212 return OK;
213}
214
215status_t ReadMetadata(const std::string& path, std::string& fsType, std::string& fsUuid,
216 std::string& fsLabel) {
217 return readMetadata(path, fsType, fsUuid, fsLabel);
218}
219
220status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType, std::string& fsUuid,
221 std::string& fsLabel) {
222 return readMetadata(path, fsType, fsUuid, fsLabel);
223}
224
225status_t ForkExecvp(const std::vector<std::string>& args) {
226 return ForkExecvp(args, nullptr);
227}
228
229status_t ForkExecvp(const std::vector<std::string>& args, char* context) {
230 std::vector<std::string> output;
231 size_t argc = args.size();
232 char** argv = (char**)calloc(argc + 1, sizeof(char*));
233 for (size_t i = 0; i < argc; i++) {
234 argv[i] = (char*)args[i].c_str();
235 if (i == 0) {
236 LOG(VERBOSE) << args[i];
237 } else {
238 LOG(VERBOSE) << " " << args[i];
239 }
240 }
241
242 if (setexeccon(context)) {
243 LOG(ERROR) << "Failed to setexeccon";
244 abort();
245 }
246
247 pid_t pid = fork();
248 int fork_errno = errno;
249 if (pid == 0) {
250 close(STDIN_FILENO);
251 close(STDOUT_FILENO);
252 close(STDERR_FILENO);
253
254 if (execvp(argv[0], argv)) {
255 PLOG(ERROR) << "Failed to exec";
256 }
257
258 _exit(1);
259 }
260
261 if (setexeccon(nullptr)) {
262 LOG(ERROR) << "Failed to setexeccon";
263 abort();
264 }
265
266 if (pid == -1) {
267 PLOG(ERROR) << "Failed to exec";
268 return -fork_errno;
269 }
270
271 waitpid(pid, nullptr, 0);
272
273 free(argv);
274 return OK;
275}
276
277bool IsFilesystemSupported(const std::string& fsType) {
278 std::string supported;
279 if (!ReadFileToString(kProcFilesystems, &supported)) {
280 PLOG(ERROR) << "Failed to read supported filesystems";
281 return false;
282 }
283
284 /* fuse filesystems */
285 supported.append("fuse\tntfs\n");
286
287 return supported.find(fsType + "\n") != std::string::npos;
288}
289
290status_t WipeBlockDevice(const std::string& path) {
291 status_t res = -1;
292 const char* c_path = path.c_str();
293 unsigned long nr_sec = 0;
294 unsigned long long range[2];
295
296 int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC));
297 if (fd == -1) {
298 PLOG(ERROR) << "Failed to open " << path;
299 goto done;
300 }
301
302 if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
303 PLOG(ERROR) << "Failed to determine size of " << path;
304 goto done;
305 }
306
307 range[0] = 0;
308 range[1] = (unsigned long long)nr_sec * 512;
309
310 LOG(INFO) << "About to discard " << range[1] << " on " << path;
311 if (ioctl(fd, BLKDISCARD, &range) == 0) {
312 LOG(INFO) << "Discard success on " << path;
313 res = 0;
314 } else {
315 PLOG(ERROR) << "Discard failure on " << path;
316 }
317
318done:
319 close(fd);
320 return res;
321}
322
323dev_t GetDevice(const std::string& path) {
324 struct stat sb;
325 if (stat(path.c_str(), &sb)) {
326 PLOG(WARNING) << "Failed to stat " << path;
327 return 0;
328 } else {
329 return sb.st_dev;
330 }
331}
332
333bool IsRunningInEmulator() {
334 return android::base::GetBoolProperty("ro.kernel.qemu", false);
335}
336
337} // namespace volmgr
338} // namespace android