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