1 /* 2 * Copyright (C) 2008 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 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/types.h> 30 #include <sys/mman.h> 31 #include <sys/mount.h> 32 #include <sys/wait.h> 33 #include <linux/fs.h> 34 #include <sys/ioctl.h> 35 36 #include <linux/kdev_t.h> 37 38 #define LOG_TAG "Vold" 39 40 #include <cutils/log.h> 41 #include <cutils/properties.h> 42 43 #include <logwrap/logwrap.h> 44 45 #include "Fat.h" 46 #include "VoldUtil.h" 47 48 static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos"; 49 static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos"; 50 extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *); 51 52 int Fat::check(const char *fsPath) { 53 bool rw = true; 54 if (access(FSCK_MSDOS_PATH, X_OK)) { 55 SLOGW("Skipping fs checks\n"); 56 return 0; 57 } 58 59 int pass = 1; 60 int rc = 0; 61 do { 62 const char *args[4]; 63 int status; 64 args[0] = FSCK_MSDOS_PATH; 65 args[1] = "-p"; 66 args[2] = "-f"; 67 args[3] = fsPath; 68 69 rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, 70 false, true); 71 if (rc != 0) { 72 SLOGE("Filesystem check failed due to logwrap error"); 73 errno = EIO; 74 return -1; 75 } 76 77 if (!WIFEXITED(status)) { 78 SLOGE("Filesystem check did not exit properly"); 79 errno = EIO; 80 return -1; 81 } 82 83 status = WEXITSTATUS(status); 84 85 switch(status) { 86 case 0: 87 SLOGI("Filesystem check completed OK"); 88 return 0; 89 90 case 2: 91 SLOGE("Filesystem check failed (not a FAT filesystem)"); 92 errno = ENODATA; 93 return -1; 94 95 case 4: 96 if (pass++ <= 3) { 97 SLOGW("Filesystem modified - rechecking (pass %d)", 98 pass); 99 continue; 100 } 101 SLOGE("Failing check after too many rechecks"); 102 errno = EIO; 103 return -1; 104 105 default: 106 SLOGE("Filesystem check failed (unknown exit code %d)", status); 107 errno = EIO; 108 return -1; 109 } 110 } while (0); 111 112 return 0; 113 } 114 115 int Fat::doMount(const char *fsPath, const char *mountPoint, 116 bool ro, bool remount, bool executable, 117 int ownerUid, int ownerGid, int permMask, bool createLost) { 118 int rc; 119 unsigned long flags; 120 char mountData[255]; 121 122 flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC; 123 124 flags |= (executable ? 0 : MS_NOEXEC); 125 flags |= (ro ? MS_RDONLY : 0); 126 flags |= (remount ? MS_REMOUNT : 0); 127 128 /* 129 * Note: This is a temporary hack. If the sampling profiler is enabled, 130 * we make the SD card world-writable so any process can write snapshots. 131 * 132 * TODO: Remove this code once we have a drop box in system_server. 133 */ 134 char value[PROPERTY_VALUE_MAX]; 135 property_get("persist.sampling_profiler", value, ""); 136 if (value[0] == '1') { 137 SLOGW("The SD card is world-writable because the" 138 " 'persist.sampling_profiler' system property is set to '1'."); 139 permMask = 0; 140 } 141 142 sprintf(mountData, 143 "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed", 144 ownerUid, ownerGid, permMask, permMask); 145 146 rc = mount(fsPath, mountPoint, "vfat", flags, mountData); 147 148 if (rc && errno == EROFS) { 149 SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); 150 flags |= MS_RDONLY; 151 rc = mount(fsPath, mountPoint, "vfat", flags, mountData); 152 } 153 154 if (rc == 0 && createLost) { 155 char *lost_path; 156 asprintf(&lost_path, "%s/LOST.DIR", mountPoint); 157 if (access(lost_path, F_OK)) { 158 /* 159 * Create a LOST.DIR in the root so we have somewhere to put 160 * lost cluster chains (fsck_msdos doesn't currently do this) 161 */ 162 if (mkdir(lost_path, 0755)) { 163 SLOGE("Unable to create LOST.DIR (%s)", strerror(errno)); 164 } 165 } 166 free(lost_path); 167 } 168 169 return rc; 170 } 171 172 int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) { 173 int fd; 174 const char *args[11]; 175 int rc; 176 int status; 177 178 if (wipe) { 179 Fat::wipe(fsPath, numSectors); 180 } 181 182 args[0] = MKDOSFS_PATH; 183 args[1] = "-F"; 184 args[2] = "32"; 185 args[3] = "-O"; 186 args[4] = "android"; 187 args[5] = "-c"; 188 args[6] = "64"; 189 args[7] = "-A"; 190 191 if (numSectors) { 192 char tmp[32]; 193 snprintf(tmp, sizeof(tmp), "%u", numSectors); 194 const char *size = tmp; 195 args[8] = "-s"; 196 args[9] = size; 197 args[10] = fsPath; 198 rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, 199 false, true); 200 } else { 201 args[8] = fsPath; 202 rc = android_fork_execvp(9, (char **)args, &status, false, 203 true); 204 } 205 206 if (rc != 0) { 207 SLOGE("Filesystem format failed due to logwrap error"); 208 errno = EIO; 209 return -1; 210 } 211 212 if (!WIFEXITED(status)) { 213 SLOGE("Filesystem format did not exit properly"); 214 errno = EIO; 215 return -1; 216 } 217 218 status = WEXITSTATUS(status); 219 220 if (status == 0) { 221 SLOGI("Filesystem formatted OK"); 222 return 0; 223 } else { 224 SLOGE("Format failed (unknown exit code %d)", status); 225 errno = EIO; 226 return -1; 227 } 228 return 0; 229 } 230 231 void Fat::wipe(const char *fsPath, unsigned int numSectors) { 232 int fd; 233 unsigned long long range[2]; 234 235 fd = open(fsPath, O_RDWR); 236 if (fd >= 0) { 237 if (numSectors == 0) { 238 numSectors = get_blkdev_size(fd); 239 } 240 if (numSectors == 0) { 241 SLOGE("Fat wipe failed to determine size of %s", fsPath); 242 close(fd); 243 return; 244 } 245 range[0] = 0; 246 range[1] = (unsigned long long)numSectors * 512; 247 if (ioctl(fd, BLKDISCARD, &range) < 0) { 248 SLOGE("Fat wipe failed to discard blocks on %s", fsPath); 249 } else { 250 SLOGI("Fat wipe %d sectors on %s succeeded", numSectors, fsPath); 251 } 252 close(fd); 253 } else { 254 SLOGE("Fat wipe failed to open device %s", fsPath); 255 } 256 } 257