1/* 2 * Copyright (C) 2012 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 17#include <stdio.h> 18#include <stdlib.h> 19#include <fcntl.h> 20#include <unistd.h> 21#include <errno.h> 22#include <string.h> 23#include <dirent.h> 24#include <errno.h> 25#include <fcntl.h> 26#include <vector> 27#include <string> 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <sys/types.h> 32#include <sys/mman.h> 33#include <sys/mount.h> 34#include <sys/wait.h> 35 36#include <linux/kdev_t.h> 37 38#define LOG_TAG "Vold" 39 40#include <android-base/logging.h> 41#include <android-base/stringprintf.h> 42#include <cutils/log.h> 43#include <cutils/properties.h> 44#include <logwrap/logwrap.h> 45#include <selinux/selinux.h> 46 47#include "Ext4.h" 48#include "Utils.h" 49#include "VoldUtil.h" 50 51using android::base::StringPrintf; 52 53namespace android { 54namespace vold { 55namespace ext4 { 56 57static const char* kResizefsPath = "/system/bin/resize2fs"; 58#ifdef TARGET_USES_MKE2FS 59static const char* kMkfsPath = "/system/bin/mke2fs"; 60#else 61static const char* kMkfsPath = "/system/bin/make_ext4fs"; 62#endif 63static const char* kFsckPath = "/system/bin/e2fsck"; 64 65bool IsSupported() { 66 return access(kMkfsPath, X_OK) == 0 67 && access(kFsckPath, X_OK) == 0 68 && IsFilesystemSupported("ext4"); 69} 70 71status_t Check(const std::string& source, const std::string& target) { 72 // The following is shamelessly borrowed from fs_mgr.c, so it should be 73 // kept in sync with any changes over there. 74 75 const char* c_source = source.c_str(); 76 const char* c_target = target.c_str(); 77 78 int status; 79 int ret; 80 long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID; 81 char *tmpmnt_opts = (char*) "nomblk_io_submit,errors=remount-ro"; 82 83 /* 84 * First try to mount and unmount the filesystem. We do this because 85 * the kernel is more efficient than e2fsck in running the journal and 86 * processing orphaned inodes, and on at least one device with a 87 * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes 88 * to do what the kernel does in about a second. 89 * 90 * After mounting and unmounting the filesystem, run e2fsck, and if an 91 * error is recorded in the filesystem superblock, e2fsck will do a full 92 * check. Otherwise, it does nothing. If the kernel cannot mount the 93 * filesytsem due to an error, e2fsck is still run to do a full check 94 * fix the filesystem. 95 */ 96 ret = mount(c_source, c_target, "ext4", tmpmnt_flags, tmpmnt_opts); 97 if (!ret) { 98 int i; 99 for (i = 0; i < 5; i++) { 100 // Try to umount 5 times before continuing on. 101 // Should we try rebooting if all attempts fail? 102 int result = umount(c_target); 103 if (result == 0) { 104 break; 105 } 106 ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno)); 107 sleep(1); 108 } 109 } 110 111 /* 112 * Some system images do not have e2fsck for licensing reasons 113 * (e.g. recent SDK system images). Detect these and skip the check. 114 */ 115 if (access(kFsckPath, X_OK)) { 116 ALOGD("Not running %s on %s (executable not in system image)\n", 117 kFsckPath, c_source); 118 } else { 119 ALOGD("Running %s on %s\n", kFsckPath, c_source); 120 121 std::vector<std::string> cmd; 122 cmd.push_back(kFsckPath); 123 cmd.push_back("-y"); 124 cmd.push_back(c_source); 125 126 // ext4 devices are currently always trusted 127 return ForkExecvp(cmd, sFsckContext); 128 } 129 130 return 0; 131} 132 133status_t Mount(const std::string& source, const std::string& target, bool ro, 134 bool remount, bool executable) { 135 int rc; 136 unsigned long flags; 137 138 const char* c_source = source.c_str(); 139 const char* c_target = target.c_str(); 140 141 flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC; 142 143 flags |= (executable ? 0 : MS_NOEXEC); 144 flags |= (ro ? MS_RDONLY : 0); 145 flags |= (remount ? MS_REMOUNT : 0); 146 147 rc = mount(c_source, c_target, "ext4", flags, NULL); 148 149 if (rc && errno == EROFS) { 150 SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); 151 flags |= MS_RDONLY; 152 rc = mount(c_source, c_target, "ext4", flags, NULL); 153 } 154 155 return rc; 156} 157 158status_t Resize(const std::string& source, unsigned long numSectors) { 159 std::vector<std::string> cmd; 160 cmd.push_back(kResizefsPath); 161 cmd.push_back("-f"); 162 cmd.push_back(source); 163 cmd.push_back(StringPrintf("%lu", numSectors)); 164 165 return ForkExecvp(cmd); 166} 167 168status_t Format(const std::string& source, unsigned long numSectors, 169 const std::string& target) { 170 std::vector<std::string> cmd; 171 cmd.push_back(kMkfsPath); 172 173#ifdef TARGET_USES_MKE2FS 174 cmd.push_back("-b"); 175 cmd.push_back("4096"); 176 177 cmd.push_back("-t"); 178 cmd.push_back("ext4"); 179 180 cmd.push_back("-M"); 181 cmd.push_back(target); 182 183 cmd.push_back("-O"); 184 cmd.push_back("^has_journal"); 185 186 cmd.push_back(source); 187 188 if (numSectors) 189 cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512))); 190#else 191 cmd.push_back("-J"); 192 193 cmd.push_back("-a"); 194 cmd.push_back(target); 195 196 if (numSectors) { 197 cmd.push_back("-l"); 198 cmd.push_back(StringPrintf("%lu", numSectors * 512)); 199 } 200 201 // Always generate a real UUID 202 cmd.push_back("-u"); 203 cmd.push_back(source); 204#endif 205 206 return ForkExecvp(cmd); 207} 208 209} // namespace ext4 210} // namespace vold 211} // namespace android 212