blob: 1b02fed2e066707a82e85b3fc877ea885e51c1ae [file] [log] [blame]
Tom Marshallbead2612019-01-04 14:37:31 -08001/*
2 * Copyright (C) 2012 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 <dirent.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <string>
26#include <vector>
27
28#include <sys/mman.h>
29#include <sys/mount.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <sys/wait.h>
33
34#include <linux/kdev_t.h>
35
36#define LOG_TAG "Vold"
37#include <android-base/logging.h>
38#include <android-base/properties.h>
39#include <android-base/stringprintf.h>
40#include <cutils/log.h>
41#include <cutils/properties.h>
42#include <logwrap/logwrap.h>
43#include <private/android_filesystem_config.h>
44#include <selinux/selinux.h>
45
46#include "Ext4.h"
47#include "Utils.h"
48
49using android::base::StringPrintf;
50
51namespace android {
52namespace volmgr {
53namespace ext4 {
54
55static const char* kFsckPath = "/sbin/e2fsck";
56
57bool IsSupported() {
58 return access(kFsckPath, X_OK) == 0 && IsFilesystemSupported("ext4");
59}
60
61status_t Check(const std::string& source, const std::string& target, bool trusted) {
62 // The following is shamelessly borrowed from fs_mgr.c, so it should be
63 // kept in sync with any changes over there.
64
65 const char* c_source = source.c_str();
66 const char* c_target = target.c_str();
67
68 int ret;
69 long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
70 char* tmpmnt_opts = (char*)"nomblk_io_submit,errors=remount-ro";
71
72 /*
73 * First try to mount and unmount the filesystem. We do this because
74 * the kernel is more efficient than e2fsck in running the journal and
75 * processing orphaned inodes, and on at least one device with a
76 * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
77 * to do what the kernel does in about a second.
78 *
79 * After mounting and unmounting the filesystem, run e2fsck, and if an
80 * error is recorded in the filesystem superblock, e2fsck will do a full
81 * check. Otherwise, it does nothing. If the kernel cannot mount the
82 * filesytsem due to an error, e2fsck is still run to do a full check
83 * fix the filesystem.
84 */
85 ret = mount(c_source, c_target, "ext4", tmpmnt_flags, tmpmnt_opts);
86 if (!ret) {
87 int i;
88 for (i = 0; i < 5; i++) {
89 // Try to umount 5 times before continuing on.
90 // Should we try rebooting if all attempts fail?
91 int result = umount(c_target);
92 if (result == 0) {
93 break;
94 }
95 ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno));
96 sleep(1);
97 }
98 }
99
100 /*
101 * Some system images do not have e2fsck for licensing reasons
102 * (e.g. recent SDK system images). Detect these and skip the check.
103 */
104 if (access(kFsckPath, X_OK)) {
105 ALOGD("Not running %s on %s (executable not in system image)\n", kFsckPath, c_source);
106 } else {
107 ALOGD("Running %s on %s\n", kFsckPath, c_source);
108
109 std::vector<std::string> cmd;
110 cmd.push_back(kFsckPath);
111 cmd.push_back("-y");
112 cmd.push_back(c_source);
113
114 return ForkExecvp(cmd, trusted ? sFsckContext : sFsckUntrustedContext);
115 }
116
117 return 0;
118}
119
120status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
121 bool executable, const std::string& opts /* = "" */, bool trusted, bool portable) {
122 int rc;
123 unsigned long flags;
124
125 std::string data(opts);
126
127 if (portable) {
128 if (!data.empty()) {
129 data += ",";
130 }
131 data += "context=u:object_r:sdcard_posix:s0";
132 }
133 const char* c_source = source.c_str();
134 const char* c_target = target.c_str();
135 const char* c_data = data.c_str();
136
137 flags = MS_NOATIME | MS_NODEV | MS_NOSUID;
138
139 // Only use MS_DIRSYNC if we're not mounting adopted storage
140 if (!trusted) {
141 flags |= MS_DIRSYNC;
142 }
143
144 flags |= (executable ? 0 : MS_NOEXEC);
145 flags |= (ro ? MS_RDONLY : 0);
146 flags |= (remount ? MS_REMOUNT : 0);
147
148 rc = mount(c_source, c_target, "ext4", flags, c_data);
149 if (portable && rc == 0) {
150 chown(c_target, AID_MEDIA_RW, AID_MEDIA_RW);
151 chmod(c_target, 0775);
152 }
153
154 if (rc && errno == EROFS) {
155 SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
156 flags |= MS_RDONLY;
157 rc = mount(c_source, c_target, "ext4", flags, c_data);
158 }
159
160 return rc;
161}
162
163} // namespace ext4
164} // namespace volmgr
165} // namespace android