blob: 6a3830fa80b609701f554818d100a9b33b60374c [file] [log] [blame]
Jeff Sharkeydeb24052015-03-02 21:01:40 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkeydeb24052015-03-02 21:01:40 -080017#include "Utils.h"
Paul Crowley56292ef2017-10-20 08:07:53 -070018
Jeff Sharkeydeb24052015-03-02 21:01:40 -080019#include "Process.h"
Paul Crowley56292ef2017-10-20 08:07:53 -070020#include "sehandle.h"
Jeff Sharkeydeb24052015-03-02 21:01:40 -080021
Paul Crowleycfe39722018-10-30 15:59:24 -070022#include <android-base/chrono_utils.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080023#include <android-base/file.h>
24#include <android-base/logging.h>
Tom Cherryd6127ef2017-06-15 17:13:56 -070025#include <android-base/properties.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080026#include <android-base/stringprintf.h>
Paul Crowley14c8c072018-09-18 13:30:21 -070027#include <android-base/strings.h>
Paul Crowleyde2d6202018-11-30 11:43:47 -080028#include <android-base/unique_fd.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080029#include <cutils/fs.h>
Jeff Sharkey9c484982015-03-31 10:35:33 -070030#include <logwrap/logwrap.h>
Tom Cherryd6127ef2017-06-15 17:13:56 -070031#include <private/android_filesystem_config.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080032
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070033#include <dirent.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080034#include <fcntl.h>
35#include <linux/fs.h>
Sudheer Shanka89ddf992018-09-25 14:22:07 -070036#include <mntent.h>
37#include <stdio.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080038#include <stdlib.h>
39#include <sys/mount.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080040#include <sys/stat.h>
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070041#include <sys/statvfs.h>
Paul Crowley14c8c072018-09-18 13:30:21 -070042#include <sys/sysmacros.h>
43#include <sys/types.h>
44#include <sys/wait.h>
Paul Crowley747b4212019-04-05 04:09:57 -070045#include <unistd.h>
Paul Crowleycfe39722018-10-30 15:59:24 -070046
Sudheer Shanka89ddf992018-09-25 14:22:07 -070047#include <list>
Paul Crowley14c8c072018-09-18 13:30:21 -070048#include <mutex>
Paul Crowleycfe39722018-10-30 15:59:24 -070049#include <thread>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080050
51#ifndef UMOUNT_NOFOLLOW
Paul Crowley14c8c072018-09-18 13:30:21 -070052#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
Jeff Sharkeydeb24052015-03-02 21:01:40 -080053#endif
54
Paul Crowleycfe39722018-10-30 15:59:24 -070055using namespace std::chrono_literals;
Jeff Sharkeyd0640f62015-05-21 22:35:42 -070056using android::base::ReadFileToString;
Jeff Sharkey9c484982015-03-31 10:35:33 -070057using android::base::StringPrintf;
58
Jeff Sharkeydeb24052015-03-02 21:01:40 -080059namespace android {
60namespace vold {
61
Jeff Sharkey95c87cc2015-04-01 11:54:32 -070062security_context_t sBlkidContext = nullptr;
63security_context_t sBlkidUntrustedContext = nullptr;
64security_context_t sFsckContext = nullptr;
65security_context_t sFsckUntrustedContext = nullptr;
66
Paul Crowley56292ef2017-10-20 08:07:53 -070067bool sSleepOnUnmount = true;
68
Jeff Sharkey9c484982015-03-31 10:35:33 -070069static const char* kBlkidPath = "/system/bin/blkid";
Jeff Sharkeybc40cc82015-06-18 14:25:08 -070070static const char* kKeyPath = "/data/misc/vold";
Jeff Sharkey9c484982015-03-31 10:35:33 -070071
Jeff Sharkeyd0640f62015-05-21 22:35:42 -070072static const char* kProcFilesystems = "/proc/filesystems";
73
Jeff Sharkeyae4f85d2017-10-18 17:02:21 -060074// Lock used to protect process-level SELinux changes from racing with each
75// other between multiple threads.
76static std::mutex kSecurityLock;
77
Jeff Sharkeydeb24052015-03-02 21:01:40 -080078status_t CreateDeviceNode(const std::string& path, dev_t dev) {
Jeff Sharkeyae4f85d2017-10-18 17:02:21 -060079 std::lock_guard<std::mutex> lock(kSecurityLock);
Jeff Sharkeydeb24052015-03-02 21:01:40 -080080 const char* cpath = path.c_str();
81 status_t res = 0;
82
83 char* secontext = nullptr;
84 if (sehandle) {
85 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFBLK)) {
86 setfscreatecon(secontext);
87 }
88 }
89
90 mode_t mode = 0660 | S_IFBLK;
91 if (mknod(cpath, mode, dev) < 0) {
92 if (errno != EEXIST) {
Paul Crowley14c8c072018-09-18 13:30:21 -070093 PLOG(ERROR) << "Failed to create device node for " << major(dev) << ":" << minor(dev)
94 << " at " << path;
Jeff Sharkeydeb24052015-03-02 21:01:40 -080095 res = -errno;
96 }
97 }
98
99 if (secontext) {
100 setfscreatecon(nullptr);
101 freecon(secontext);
102 }
103
104 return res;
105}
106
107status_t DestroyDeviceNode(const std::string& path) {
108 const char* cpath = path.c_str();
109 if (TEMP_FAILURE_RETRY(unlink(cpath))) {
110 return -errno;
111 } else {
112 return OK;
113 }
114}
115
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700116status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
Jeff Sharkeyae4f85d2017-10-18 17:02:21 -0600117 std::lock_guard<std::mutex> lock(kSecurityLock);
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700118 const char* cpath = path.c_str();
119
120 char* secontext = nullptr;
121 if (sehandle) {
122 if (!selabel_lookup(sehandle, &secontext, cpath, S_IFDIR)) {
123 setfscreatecon(secontext);
124 }
125 }
126
127 int res = fs_prepare_dir(cpath, mode, uid, gid);
128
129 if (secontext) {
130 setfscreatecon(nullptr);
131 freecon(secontext);
132 }
133
134 if (res == 0) {
135 return OK;
136 } else {
137 return -errno;
138 }
139}
140
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800141status_t ForceUnmount(const std::string& path) {
142 const char* cpath = path.c_str();
143 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
144 return OK;
145 }
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700146 // Apps might still be handling eject request, so wait before
147 // we start sending signals
Paul Crowley56292ef2017-10-20 08:07:53 -0700148 if (sSleepOnUnmount) sleep(5);
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700149
Jeff Sharkey3472e522017-10-06 18:02:53 -0600150 KillProcessesWithOpenFiles(path, SIGINT);
Paul Crowley56292ef2017-10-20 08:07:53 -0700151 if (sSleepOnUnmount) sleep(5);
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700152 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
153 return OK;
154 }
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700155
Jeff Sharkey3472e522017-10-06 18:02:53 -0600156 KillProcessesWithOpenFiles(path, SIGTERM);
Paul Crowley56292ef2017-10-20 08:07:53 -0700157 if (sSleepOnUnmount) sleep(5);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800158 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
159 return OK;
160 }
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700161
Jeff Sharkey3472e522017-10-06 18:02:53 -0600162 KillProcessesWithOpenFiles(path, SIGKILL);
Paul Crowley56292ef2017-10-20 08:07:53 -0700163 if (sSleepOnUnmount) sleep(5);
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700164 if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
165 return OK;
166 }
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700167
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800168 return -errno;
169}
170
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700171status_t KillProcessesUsingPath(const std::string& path) {
Jeff Sharkey3472e522017-10-06 18:02:53 -0600172 if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700173 return OK;
174 }
Paul Crowley56292ef2017-10-20 08:07:53 -0700175 if (sSleepOnUnmount) sleep(5);
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700176
Jeff Sharkey3472e522017-10-06 18:02:53 -0600177 if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) {
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700178 return OK;
179 }
Paul Crowley56292ef2017-10-20 08:07:53 -0700180 if (sSleepOnUnmount) sleep(5);
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700181
Jeff Sharkey3472e522017-10-06 18:02:53 -0600182 if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700183 return OK;
184 }
Paul Crowley56292ef2017-10-20 08:07:53 -0700185 if (sSleepOnUnmount) sleep(5);
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700186
187 // Send SIGKILL a second time to determine if we've
188 // actually killed everyone with open files
Jeff Sharkey3472e522017-10-06 18:02:53 -0600189 if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
Jeff Sharkey89f74fb2015-10-21 12:16:12 -0700190 return OK;
191 }
192 PLOG(ERROR) << "Failed to kill processes using " << path;
193 return -EBUSY;
194}
195
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700196status_t BindMount(const std::string& source, const std::string& target) {
197 if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) {
198 PLOG(ERROR) << "Failed to bind mount " << source << " to " << target;
199 return -errno;
200 }
201 return OK;
202}
203
Jeff Sharkey3472e522017-10-06 18:02:53 -0600204bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
205 auto qual = key + "=\"";
Paul Crowley95abfa02019-02-05 15:33:34 -0800206 size_t start = 0;
207 while (true) {
208 start = raw.find(qual, start);
209 if (start == std::string::npos) return false;
210 if (start == 0 || raw[start - 1] == ' ') {
211 break;
212 }
213 start += 1;
Jeff Sharkey3472e522017-10-06 18:02:53 -0600214 }
Jeff Sharkey3472e522017-10-06 18:02:53 -0600215 start += qual.length();
216
217 auto end = raw.find("\"", start);
218 if (end == std::string::npos) return false;
219
220 *value = raw.substr(start, end - start);
221 return true;
222}
223
Paul Crowley14c8c072018-09-18 13:30:21 -0700224static status_t readMetadata(const std::string& path, std::string* fsType, std::string* fsUuid,
225 std::string* fsLabel, bool untrusted) {
Jeff Sharkey3472e522017-10-06 18:02:53 -0600226 fsType->clear();
227 fsUuid->clear();
228 fsLabel->clear();
Jeff Sharkey9c484982015-03-31 10:35:33 -0700229
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700230 std::vector<std::string> cmd;
231 cmd.push_back(kBlkidPath);
232 cmd.push_back("-c");
233 cmd.push_back("/dev/null");
Jeff Sharkeyeddf9bd2015-08-12 16:04:35 -0700234 cmd.push_back("-s");
235 cmd.push_back("TYPE");
236 cmd.push_back("-s");
237 cmd.push_back("UUID");
238 cmd.push_back("-s");
239 cmd.push_back("LABEL");
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700240 cmd.push_back(path);
241
242 std::vector<std::string> output;
Paul Crowleyde2d6202018-11-30 11:43:47 -0800243 status_t res = ForkExecvp(cmd, &output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700244 if (res != OK) {
245 LOG(WARNING) << "blkid failed to identify " << path;
246 return res;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700247 }
248
Chih-Hung Hsieh11a2ce82016-07-27 14:11:02 -0700249 for (const auto& line : output) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700250 // Extract values from blkid output, if defined
Jeff Sharkey3472e522017-10-06 18:02:53 -0600251 FindValue(line, "TYPE", fsType);
252 FindValue(line, "UUID", fsUuid);
253 FindValue(line, "LABEL", fsLabel);
Jeff Sharkey9c484982015-03-31 10:35:33 -0700254 }
255
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700256 return OK;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700257}
258
Paul Crowley14c8c072018-09-18 13:30:21 -0700259status_t ReadMetadata(const std::string& path, std::string* fsType, std::string* fsUuid,
260 std::string* fsLabel) {
Jeff Sharkey95c87cc2015-04-01 11:54:32 -0700261 return readMetadata(path, fsType, fsUuid, fsLabel, false);
262}
263
Paul Crowley14c8c072018-09-18 13:30:21 -0700264status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType, std::string* fsUuid,
265 std::string* fsLabel) {
Jeff Sharkey95c87cc2015-04-01 11:54:32 -0700266 return readMetadata(path, fsType, fsUuid, fsLabel, true);
267}
268
Paul Crowleyde2d6202018-11-30 11:43:47 -0800269static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) {
270 std::vector<const char*> argv;
271 argv.reserve(args.size() + 1);
272 for (const auto& arg : args) {
273 if (argv.empty()) {
274 LOG(DEBUG) << arg;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700275 } else {
Paul Crowleyde2d6202018-11-30 11:43:47 -0800276 LOG(DEBUG) << " " << arg;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700277 }
Paul Crowleyde2d6202018-11-30 11:43:47 -0800278 argv.emplace_back(arg.data());
Jeff Sharkey9c484982015-03-31 10:35:33 -0700279 }
Paul Crowleyde2d6202018-11-30 11:43:47 -0800280 argv.emplace_back(nullptr);
281 return argv;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700282}
283
Paul Crowleyde2d6202018-11-30 11:43:47 -0800284static status_t ReadLinesFromFdAndLog(std::vector<std::string>* output,
285 android::base::unique_fd ufd) {
286 std::unique_ptr<FILE, int (*)(FILE*)> fp(android::base::Fdopen(std::move(ufd), "r"), fclose);
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700287 if (!fp) {
Paul Crowleyde2d6202018-11-30 11:43:47 -0800288 PLOG(ERROR) << "fdopen in ReadLinesFromFdAndLog";
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700289 return -errno;
290 }
Paul Crowleyde2d6202018-11-30 11:43:47 -0800291 if (output) output->clear();
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700292 char line[1024];
Paul Crowleyde2d6202018-11-30 11:43:47 -0800293 while (fgets(line, sizeof(line), fp.get()) != nullptr) {
Sudheer Shanka4b6ca4e2018-09-21 10:54:54 -0700294 LOG(DEBUG) << line;
Paul Crowleyde2d6202018-11-30 11:43:47 -0800295 if (output) output->emplace_back(line);
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700296 }
Paul Crowleyde2d6202018-11-30 11:43:47 -0800297 return OK;
298}
299
300status_t ForkExecvp(const std::vector<std::string>& args, std::vector<std::string>* output,
301 security_context_t context) {
302 auto argv = ConvertToArgv(args);
303
Paul Crowleye6d76632018-11-30 11:43:47 -0800304 android::base::unique_fd pipe_read, pipe_write;
305 if (!android::base::Pipe(&pipe_read, &pipe_write)) {
306 PLOG(ERROR) << "Pipe in ForkExecvp";
Paul Crowleyde2d6202018-11-30 11:43:47 -0800307 return -errno;
308 }
Paul Crowleyde2d6202018-11-30 11:43:47 -0800309
310 pid_t pid = fork();
311 if (pid == 0) {
312 if (context) {
313 if (setexeccon(context)) {
Paul Crowleye6d76632018-11-30 11:43:47 -0800314 LOG(ERROR) << "Failed to setexeccon in ForkExecvp";
Paul Crowleyde2d6202018-11-30 11:43:47 -0800315 abort();
316 }
317 }
318 pipe_read.reset();
Paul Crowleybe857bf2018-12-07 12:23:25 -0800319 if (dup2(pipe_write.get(), STDOUT_FILENO) == -1) {
320 PLOG(ERROR) << "dup2 in ForkExecvp";
321 _exit(EXIT_FAILURE);
322 }
Paul Crowleye6d76632018-11-30 11:43:47 -0800323 pipe_write.reset();
Paul Crowleyde2d6202018-11-30 11:43:47 -0800324 execvp(argv[0], const_cast<char**>(argv.data()));
Paul Crowleye6d76632018-11-30 11:43:47 -0800325 PLOG(ERROR) << "exec in ForkExecvp";
Paul Crowleyde2d6202018-11-30 11:43:47 -0800326 _exit(EXIT_FAILURE);
327 }
328 if (pid == -1) {
329 PLOG(ERROR) << "fork in ForkExecvp";
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700330 return -errno;
331 }
332
Paul Crowleyde2d6202018-11-30 11:43:47 -0800333 pipe_write.reset();
334 auto st = ReadLinesFromFdAndLog(output, std::move(pipe_read));
335 if (st != 0) return st;
336
337 int status;
338 if (waitpid(pid, &status, 0) == -1) {
339 PLOG(ERROR) << "waitpid in ForkExecvp";
340 return -errno;
341 }
342 if (!WIFEXITED(status)) {
343 LOG(ERROR) << "Process did not exit normally, status: " << status;
344 return -ECHILD;
345 }
346 if (WEXITSTATUS(status)) {
347 LOG(ERROR) << "Process exited with code: " << WEXITSTATUS(status);
348 return WEXITSTATUS(status);
349 }
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700350 return OK;
351}
352
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700353pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
Paul Crowleyde2d6202018-11-30 11:43:47 -0800354 auto argv = ConvertToArgv(args);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700355
356 pid_t pid = fork();
357 if (pid == 0) {
358 close(STDIN_FILENO);
359 close(STDOUT_FILENO);
360 close(STDERR_FILENO);
361
Paul Crowleyde2d6202018-11-30 11:43:47 -0800362 execvp(argv[0], const_cast<char**>(argv.data()));
363 PLOG(ERROR) << "exec in ForkExecvpAsync";
364 _exit(EXIT_FAILURE);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700365 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700366 if (pid == -1) {
Paul Crowleyde2d6202018-11-30 11:43:47 -0800367 PLOG(ERROR) << "fork in ForkExecvpAsync";
368 return -1;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700369 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700370 return pid;
371}
372
Jeff Sharkey9c484982015-03-31 10:35:33 -0700373status_t ReadRandomBytes(size_t bytes, std::string& out) {
Pavel Grafove2e2d302017-08-01 17:15:53 +0100374 out.resize(bytes);
375 return ReadRandomBytes(bytes, &out[0]);
376}
Jeff Sharkey9c484982015-03-31 10:35:33 -0700377
Pavel Grafove2e2d302017-08-01 17:15:53 +0100378status_t ReadRandomBytes(size_t bytes, char* buf) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700379 int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
380 if (fd == -1) {
381 return -errno;
382 }
383
Eric Biggers0ef7bfd2019-01-16 13:05:34 -0800384 ssize_t n;
Pavel Grafove2e2d302017-08-01 17:15:53 +0100385 while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], bytes))) > 0) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700386 bytes -= n;
Pavel Grafove2e2d302017-08-01 17:15:53 +0100387 buf += n;
Jeff Sharkey9c484982015-03-31 10:35:33 -0700388 }
Elliott Hughesa6231082015-05-15 18:34:24 -0700389 close(fd);
Jeff Sharkey9c484982015-03-31 10:35:33 -0700390
391 if (bytes == 0) {
392 return OK;
393 } else {
394 return -EIO;
395 }
396}
397
Jeff Sharkey46bb69f2017-06-21 13:52:23 -0600398status_t GenerateRandomUuid(std::string& out) {
399 status_t res = ReadRandomBytes(16, out);
400 if (res == OK) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700401 out[6] &= 0x0f; /* clear version */
402 out[6] |= 0x40; /* set to version 4 */
403 out[8] &= 0x3f; /* clear variant */
404 out[8] |= 0x80; /* set to IETF variant */
Jeff Sharkey46bb69f2017-06-21 13:52:23 -0600405 }
406 return res;
407}
408
Jeff Sharkey9c484982015-03-31 10:35:33 -0700409status_t HexToStr(const std::string& hex, std::string& str) {
410 str.clear();
411 bool even = true;
412 char cur = 0;
413 for (size_t i = 0; i < hex.size(); i++) {
414 int val = 0;
415 switch (hex[i]) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700416 // clang-format off
417 case ' ': case '-': case ':': continue;
418 case 'f': case 'F': val = 15; break;
419 case 'e': case 'E': val = 14; break;
420 case 'd': case 'D': val = 13; break;
421 case 'c': case 'C': val = 12; break;
422 case 'b': case 'B': val = 11; break;
423 case 'a': case 'A': val = 10; break;
424 case '9': val = 9; break;
425 case '8': val = 8; break;
426 case '7': val = 7; break;
427 case '6': val = 6; break;
428 case '5': val = 5; break;
429 case '4': val = 4; break;
430 case '3': val = 3; break;
431 case '2': val = 2; break;
432 case '1': val = 1; break;
433 case '0': val = 0; break;
434 default: return -EINVAL;
435 // clang-format on
Jeff Sharkey9c484982015-03-31 10:35:33 -0700436 }
437
438 if (even) {
439 cur = val << 4;
440 } else {
441 cur += val;
442 str.push_back(cur);
443 cur = 0;
444 }
445 even = !even;
446 }
447 return even ? OK : -EINVAL;
448}
449
450static const char* kLookup = "0123456789abcdef";
451
452status_t StrToHex(const std::string& str, std::string& hex) {
453 hex.clear();
454 for (size_t i = 0; i < str.size(); i++) {
Jeff Sharkeyef369752015-04-29 15:57:48 -0700455 hex.push_back(kLookup[(str[i] & 0xF0) >> 4]);
Jeff Sharkey9c484982015-03-31 10:35:33 -0700456 hex.push_back(kLookup[str[i] & 0x0F]);
457 }
458 return OK;
459}
460
Pavel Grafove2e2d302017-08-01 17:15:53 +0100461status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex) {
462 hex.clear();
463 for (size_t i = 0; i < str.size(); i++) {
464 hex.push_back(kLookup[(str.data()[i] & 0xF0) >> 4]);
465 hex.push_back(kLookup[str.data()[i] & 0x0F]);
466 }
467 return OK;
468}
469
Jeff Sharkeybc40cc82015-06-18 14:25:08 -0700470status_t NormalizeHex(const std::string& in, std::string& out) {
471 std::string tmp;
472 if (HexToStr(in, tmp)) {
473 return -EINVAL;
474 }
475 return StrToHex(tmp, out);
476}
477
Oleksiy Avramchenko625dc782018-05-23 10:50:46 +0200478status_t GetBlockDevSize(int fd, uint64_t* size) {
479 if (ioctl(fd, BLKGETSIZE64, size)) {
480 return -errno;
481 }
482
483 return OK;
484}
485
486status_t GetBlockDevSize(const std::string& path, uint64_t* size) {
487 int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
488 status_t res = OK;
489
490 if (fd < 0) {
491 return -errno;
492 }
493
494 res = GetBlockDevSize(fd, size);
495
496 close(fd);
497
498 return res;
499}
500
501status_t GetBlockDev512Sectors(const std::string& path, uint64_t* nr_sec) {
502 uint64_t size;
503 status_t res = GetBlockDevSize(path, &size);
504
505 if (res != OK) {
506 return res;
507 }
508
509 *nr_sec = size / 512;
510
511 return OK;
512}
513
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700514uint64_t GetFreeBytes(const std::string& path) {
515 struct statvfs sb;
516 if (statvfs(path.c_str(), &sb) == 0) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700517 return (uint64_t)sb.f_bavail * sb.f_frsize;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700518 } else {
519 return -1;
520 }
521}
522
523// TODO: borrowed from frameworks/native/libs/diskusage/ which should
524// eventually be migrated into system/
Paul Crowley14c8c072018-09-18 13:30:21 -0700525static int64_t stat_size(struct stat* s) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700526 int64_t blksize = s->st_blksize;
527 // count actual blocks used instead of nominal file size
528 int64_t size = s->st_blocks * 512;
529
530 if (blksize) {
531 /* round up to filesystem block size */
532 size = (size + blksize - 1) & (~(blksize - 1));
533 }
534
535 return size;
536}
537
538// TODO: borrowed from frameworks/native/libs/diskusage/ which should
539// eventually be migrated into system/
540int64_t calculate_dir_size(int dfd) {
541 int64_t size = 0;
542 struct stat s;
Paul Crowley14c8c072018-09-18 13:30:21 -0700543 DIR* d;
544 struct dirent* de;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700545
546 d = fdopendir(dfd);
547 if (d == NULL) {
548 close(dfd);
549 return 0;
550 }
551
552 while ((de = readdir(d))) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700553 const char* name = de->d_name;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700554 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
555 size += stat_size(&s);
556 }
557 if (de->d_type == DT_DIR) {
558 int subfd;
559
560 /* always skip "." and ".." */
561 if (name[0] == '.') {
Paul Crowley14c8c072018-09-18 13:30:21 -0700562 if (name[1] == 0) continue;
563 if ((name[1] == '.') && (name[2] == 0)) continue;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700564 }
565
Jeff Sharkeyfd3dc3c2017-03-27 10:49:21 -0600566 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700567 if (subfd >= 0) {
568 size += calculate_dir_size(subfd);
569 }
570 }
571 }
572 closedir(d);
573 return size;
574}
575
576uint64_t GetTreeBytes(const std::string& path) {
Jeff Sharkeyfd3dc3c2017-03-27 10:49:21 -0600577 int dirfd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700578 if (dirfd < 0) {
579 PLOG(WARNING) << "Failed to open " << path;
580 return -1;
581 } else {
Josh Gao72fb1a62018-05-29 19:05:16 -0700582 return calculate_dir_size(dirfd);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700583 }
584}
585
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700586bool IsFilesystemSupported(const std::string& fsType) {
587 std::string supported;
588 if (!ReadFileToString(kProcFilesystems, &supported)) {
589 PLOG(ERROR) << "Failed to read supported filesystems";
590 return false;
591 }
592 return supported.find(fsType + "\n") != std::string::npos;
593}
594
595status_t WipeBlockDevice(const std::string& path) {
596 status_t res = -1;
597 const char* c_path = path.c_str();
Oleksiy Avramchenko625dc782018-05-23 10:50:46 +0200598 uint64_t range[2] = {0, 0};
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700599
600 int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC));
601 if (fd == -1) {
602 PLOG(ERROR) << "Failed to open " << path;
603 goto done;
604 }
605
Oleksiy Avramchenko625dc782018-05-23 10:50:46 +0200606 if (GetBlockDevSize(fd, &range[1]) != OK) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700607 PLOG(ERROR) << "Failed to determine size of " << path;
608 goto done;
609 }
610
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700611 LOG(INFO) << "About to discard " << range[1] << " on " << path;
612 if (ioctl(fd, BLKDISCARD, &range) == 0) {
613 LOG(INFO) << "Discard success on " << path;
614 res = 0;
615 } else {
616 PLOG(ERROR) << "Discard failure on " << path;
617 }
618
619done:
620 close(fd);
621 return res;
622}
623
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800624static bool isValidFilename(const std::string& name) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700625 if (name.empty() || (name == ".") || (name == "..") || (name.find('/') != std::string::npos)) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800626 return false;
627 } else {
628 return true;
629 }
630}
631
Jeff Sharkeybc40cc82015-06-18 14:25:08 -0700632std::string BuildKeyPath(const std::string& partGuid) {
633 return StringPrintf("%s/expand_%s.key", kKeyPath, partGuid.c_str());
634}
635
Jeff Sharkeybe70c9a2016-04-14 20:45:16 -0600636std::string BuildDataSystemLegacyPath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700637 return StringPrintf("%s/system/users/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkeybe70c9a2016-04-14 20:45:16 -0600638}
639
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800640std::string BuildDataSystemCePath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700641 return StringPrintf("%s/system_ce/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkey47695b22016-02-01 17:02:29 -0700642}
643
644std::string BuildDataSystemDePath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700645 return StringPrintf("%s/system_de/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkey47695b22016-02-01 17:02:29 -0700646}
647
Jeff Sharkeybe70c9a2016-04-14 20:45:16 -0600648std::string BuildDataMiscLegacyPath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700649 return StringPrintf("%s/misc/user/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkeybe70c9a2016-04-14 20:45:16 -0600650}
651
Jeff Sharkey47695b22016-02-01 17:02:29 -0700652std::string BuildDataMiscCePath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700653 return StringPrintf("%s/misc_ce/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkey47695b22016-02-01 17:02:29 -0700654}
655
656std::string BuildDataMiscDePath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700657 return StringPrintf("%s/misc_de/%u", BuildDataPath("").c_str(), userId);
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800658}
659
Calin Juravle79f55a42016-02-17 20:14:46 +0000660// Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
661std::string BuildDataProfilesDePath(userid_t userId) {
Paul Crowley3b71fc52017-10-09 10:55:21 -0700662 return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath("").c_str(), userId);
Calin Juravle79f55a42016-02-17 20:14:46 +0000663}
664
Andreas Huber71cd43f2018-01-22 11:25:29 -0800665std::string BuildDataVendorCePath(userid_t userId) {
666 return StringPrintf("%s/vendor_ce/%u", BuildDataPath("").c_str(), userId);
667}
668
669std::string BuildDataVendorDePath(userid_t userId) {
670 return StringPrintf("%s/vendor_de/%u", BuildDataPath("").c_str(), userId);
671}
672
Paul Crowley3b71fc52017-10-09 10:55:21 -0700673std::string BuildDataPath(const std::string& volumeUuid) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800674 // TODO: unify with installd path generation logic
Paul Crowley3b71fc52017-10-09 10:55:21 -0700675 if (volumeUuid.empty()) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800676 return "/data";
677 } else {
678 CHECK(isValidFilename(volumeUuid));
Paul Crowley3b71fc52017-10-09 10:55:21 -0700679 return StringPrintf("/mnt/expand/%s", volumeUuid.c_str());
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800680 }
681}
682
Paul Crowley3b71fc52017-10-09 10:55:21 -0700683std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userId) {
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700684 // TODO: unify with installd path generation logic
685 std::string data(BuildDataPath(volumeUuid));
686 return StringPrintf("%s/media/%u", data.c_str(), userId);
687}
688
Paul Crowley3b71fc52017-10-09 10:55:21 -0700689std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userId) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800690 // TODO: unify with installd path generation logic
691 std::string data(BuildDataPath(volumeUuid));
Paul Crowley3b71fc52017-10-09 10:55:21 -0700692 if (volumeUuid.empty() && userId == 0) {
cjbaoeb501142017-04-12 00:09:00 +0800693 std::string legacy = StringPrintf("%s/data", data.c_str());
694 struct stat sb;
695 if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
696 /* /data/data is dir, return /data/data for legacy system */
697 return legacy;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800698 }
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800699 }
cjbaoeb501142017-04-12 00:09:00 +0800700 return StringPrintf("%s/user/%u", data.c_str(), userId);
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800701}
702
Paul Crowley3b71fc52017-10-09 10:55:21 -0700703std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userId) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800704 // TODO: unify with installd path generation logic
705 std::string data(BuildDataPath(volumeUuid));
706 return StringPrintf("%s/user_de/%u", data.c_str(), userId);
707}
708
Jeff Sharkey66270a22015-06-24 11:49:24 -0700709dev_t GetDevice(const std::string& path) {
710 struct stat sb;
711 if (stat(path.c_str(), &sb)) {
712 PLOG(WARNING) << "Failed to stat " << path;
713 return 0;
714 } else {
715 return sb.st_dev;
716 }
717}
718
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600719status_t RestoreconRecursive(const std::string& path) {
Sudheer Shanka4b6ca4e2018-09-21 10:54:54 -0700720 LOG(DEBUG) << "Starting restorecon of " << path;
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600721
Tom Cherryd6127ef2017-06-15 17:13:56 -0700722 static constexpr const char* kRestoreconString = "selinux.restorecon_recursive";
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600723
Tom Cherryd6127ef2017-06-15 17:13:56 -0700724 android::base::SetProperty(kRestoreconString, "");
725 android::base::SetProperty(kRestoreconString, path);
726
727 android::base::WaitForProperty(kRestoreconString, path);
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600728
Sudheer Shanka4b6ca4e2018-09-21 10:54:54 -0700729 LOG(DEBUG) << "Finished restorecon of " << path;
Jeff Sharkeyd24aeda2016-07-15 16:20:22 -0600730 return OK;
731}
732
Jeff Sharkey3472e522017-10-06 18:02:53 -0600733bool Readlinkat(int dirfd, const std::string& path, std::string* result) {
734 // Shamelessly borrowed from android::base::Readlink()
735 result->clear();
736
737 // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
738 // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
739 // waste memory to just start there. We add 1 so that we can recognize
740 // whether it actually fit (rather than being truncated to 4095).
741 std::vector<char> buf(4095 + 1);
742 while (true) {
743 ssize_t size = readlinkat(dirfd, path.c_str(), &buf[0], buf.size());
744 // Unrecoverable error?
Paul Crowley14c8c072018-09-18 13:30:21 -0700745 if (size == -1) return false;
Jeff Sharkey3472e522017-10-06 18:02:53 -0600746 // It fit! (If size == buf.size(), it may have been truncated.)
747 if (static_cast<size_t>(size) < buf.size()) {
748 result->assign(&buf[0], size);
749 return true;
750 }
751 // Double our buffer and try again.
752 buf.resize(buf.size() * 2);
Daichi Hirono10d34882016-01-29 14:33:51 +0900753 }
754}
755
Yu Ning942d4e82016-01-08 17:36:47 +0800756bool IsRunningInEmulator() {
Tom Cherryd6127ef2017-06-15 17:13:56 -0700757 return android::base::GetBoolProperty("ro.kernel.qemu", false);
Yu Ning942d4e82016-01-08 17:36:47 +0800758}
759
Sudheer Shanka295fb242019-01-16 23:04:07 -0800760static status_t findMountPointsWithPrefix(const std::string& prefix,
761 std::list<std::string>& mountPoints) {
762 // Add a trailing slash if the client didn't provide one so that we don't match /foo/barbaz
763 // when the prefix is /foo/bar
764 std::string prefixWithSlash(prefix);
765 if (prefix.back() != '/') {
766 android::base::StringAppendF(&prefixWithSlash, "/");
767 }
768
769 std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
770 if (!mnts) {
771 PLOG(ERROR) << "Unable to open /proc/mounts";
772 return -errno;
773 }
774
775 // Some volumes can be stacked on each other, so force unmount in
776 // reverse order to give us the best chance of success.
777 struct mntent* mnt; // getmntent returns a thread local, so it's safe.
778 while ((mnt = getmntent(mnts.get())) != nullptr) {
779 auto mountPoint = std::string(mnt->mnt_dir) + "/";
780 if (android::base::StartsWith(mountPoint, prefixWithSlash)) {
781 mountPoints.push_front(mountPoint);
782 }
783 }
784 return OK;
785}
786
787// Unmount all mountpoints that start with prefix. prefix itself doesn't need to be a mountpoint.
788status_t UnmountTreeWithPrefix(const std::string& prefix) {
789 std::list<std::string> toUnmount;
790 status_t result = findMountPointsWithPrefix(prefix, toUnmount);
791 if (result < 0) {
792 return result;
793 }
794 for (const auto& path : toUnmount) {
795 if (umount2(path.c_str(), MNT_DETACH)) {
796 PLOG(ERROR) << "Failed to unmount " << path;
797 result = -errno;
798 }
799 }
800 return result;
801}
802
803status_t UnmountTree(const std::string& mountPoint) {
804 if (umount2(mountPoint.c_str(), MNT_DETACH)) {
805 PLOG(ERROR) << "Failed to unmount " << mountPoint;
Sudheer Shanka89ddf992018-09-25 14:22:07 -0700806 return -errno;
807 }
Sudheer Shanka89ddf992018-09-25 14:22:07 -0700808 return OK;
809}
810
Paul Crowleycfe39722018-10-30 15:59:24 -0700811// TODO(118708649): fix duplication with init/util.h
812status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
813 android::base::Timer t;
814 while (t.duration() < timeout) {
815 struct stat sb;
816 if (stat(filename, &sb) != -1) {
817 LOG(INFO) << "wait for '" << filename << "' took " << t;
818 return 0;
819 }
820 std::this_thread::sleep_for(10ms);
821 }
822 LOG(WARNING) << "wait for '" << filename << "' timed out and took " << t;
823 return -1;
824}
825
Paul Crowley621d9b92018-12-07 15:36:09 -0800826bool FsyncDirectory(const std::string& dirname) {
827 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dirname.c_str(), O_RDONLY | O_CLOEXEC)));
828 if (fd == -1) {
829 PLOG(ERROR) << "Failed to open " << dirname;
830 return false;
831 }
832 if (fsync(fd) == -1) {
833 if (errno == EROFS || errno == EINVAL) {
834 PLOG(WARNING) << "Skip fsync " << dirname
835 << " on a file system does not support synchronization";
836 } else {
837 PLOG(ERROR) << "Failed to fsync " << dirname;
838 return false;
839 }
840 }
841 return true;
842}
843
Tommy Chiu97466cb2019-03-26 17:18:09 +0800844bool writeStringToFile(const std::string& payload, const std::string& filename) {
845 android::base::unique_fd fd(TEMP_FAILURE_RETRY(
846 open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
847 if (fd == -1) {
848 PLOG(ERROR) << "Failed to open " << filename;
849 return false;
850 }
851 if (!android::base::WriteStringToFd(payload, fd)) {
852 PLOG(ERROR) << "Failed to write to " << filename;
853 unlink(filename.c_str());
854 return false;
855 }
856 // fsync as close won't guarantee flush data
857 // see close(2), fsync(2) and b/68901441
858 if (fsync(fd) == -1) {
859 if (errno == EROFS || errno == EINVAL) {
860 PLOG(WARNING) << "Skip fsync " << filename
861 << " on a file system does not support synchronization";
862 } else {
863 PLOG(ERROR) << "Failed to fsync " << filename;
864 unlink(filename.c_str());
865 return false;
866 }
867 }
868 return true;
869}
870
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800871} // namespace vold
872} // namespace android