Home | History | Annotate | Download | only in fs
      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 <android-base/logging.h>
     41 #include <android-base/stringprintf.h>
     42 #include <cutils/log.h>
     43 #include <cutils/properties.h>
     44 #include <selinux/selinux.h>
     45 
     46 #include <logwrap/logwrap.h>
     47 
     48 #include "Vfat.h"
     49 #include "Utils.h"
     50 #include "VoldUtil.h"
     51 
     52 using android::base::StringPrintf;
     53 
     54 namespace android {
     55 namespace vold {
     56 namespace vfat {
     57 
     58 static const char* kMkfsPath = "/system/bin/newfs_msdos";
     59 static const char* kFsckPath = "/system/bin/fsck_msdos";
     60 
     61 bool IsSupported() {
     62     return access(kMkfsPath, X_OK) == 0
     63             && access(kFsckPath, X_OK) == 0
     64             && IsFilesystemSupported("vfat");
     65 }
     66 
     67 status_t Check(const std::string& source) {
     68     if (access(kFsckPath, X_OK)) {
     69         SLOGW("Skipping fs checks\n");
     70         return 0;
     71     }
     72 
     73     int pass = 1;
     74     int rc = 0;
     75     do {
     76         std::vector<std::string> cmd;
     77         cmd.push_back(kFsckPath);
     78         cmd.push_back("-p");
     79         cmd.push_back("-f");
     80         cmd.push_back(source);
     81 
     82         // Fat devices are currently always untrusted
     83         rc = ForkExecvp(cmd, sFsckUntrustedContext);
     84 
     85         if (rc < 0) {
     86             SLOGE("Filesystem check failed due to logwrap error");
     87             errno = EIO;
     88             return -1;
     89         }
     90 
     91         switch(rc) {
     92         case 0:
     93             SLOGI("Filesystem check completed OK");
     94             return 0;
     95 
     96         case 2:
     97             SLOGE("Filesystem check failed (not a FAT filesystem)");
     98             errno = ENODATA;
     99             return -1;
    100 
    101         case 4:
    102             if (pass++ <= 3) {
    103                 SLOGW("Filesystem modified - rechecking (pass %d)",
    104                         pass);
    105                 continue;
    106             }
    107             SLOGE("Failing check after too many rechecks");
    108             errno = EIO;
    109             return -1;
    110 
    111         case 8:
    112             SLOGE("Filesystem check failed (no filesystem)");
    113             errno = ENODATA;
    114             return -1;
    115 
    116         default:
    117             SLOGE("Filesystem check failed (unknown exit code %d)", rc);
    118             errno = EIO;
    119             return -1;
    120         }
    121     } while (0);
    122 
    123     return 0;
    124 }
    125 
    126 status_t Mount(const std::string& source, const std::string& target, bool ro,
    127         bool remount, bool executable, int ownerUid, int ownerGid, int permMask,
    128         bool createLost) {
    129     int rc;
    130     unsigned long flags;
    131     char mountData[255];
    132 
    133     const char* c_source = source.c_str();
    134     const char* c_target = target.c_str();
    135 
    136     flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC;
    137 
    138     flags |= (executable ? 0 : MS_NOEXEC);
    139     flags |= (ro ? MS_RDONLY : 0);
    140     flags |= (remount ? MS_REMOUNT : 0);
    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(c_source, c_target, "vfat", flags, mountData);
    147 
    148     if (rc && errno == EROFS) {
    149         SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
    150         flags |= MS_RDONLY;
    151         rc = mount(c_source, c_target, "vfat", flags, mountData);
    152     }
    153 
    154     if (rc == 0 && createLost) {
    155         char *lost_path;
    156         asprintf(&lost_path, "%s/LOST.DIR", c_target);
    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 status_t Format(const std::string& source, unsigned long numSectors) {
    173     std::vector<std::string> cmd;
    174     cmd.push_back(kMkfsPath);
    175     cmd.push_back("-F");
    176     cmd.push_back("32");
    177     cmd.push_back("-O");
    178     cmd.push_back("android");
    179     cmd.push_back("-c");
    180     cmd.push_back("64");
    181     cmd.push_back("-A");
    182 
    183     if (numSectors) {
    184         cmd.push_back("-s");
    185         cmd.push_back(StringPrintf("%lu", numSectors));
    186     }
    187 
    188     cmd.push_back(source);
    189 
    190     int rc = ForkExecvp(cmd);
    191     if (rc < 0) {
    192         SLOGE("Filesystem format failed due to logwrap error");
    193         errno = EIO;
    194         return -1;
    195     }
    196 
    197     if (rc == 0) {
    198         SLOGI("Filesystem formatted OK");
    199         return 0;
    200     } else {
    201         SLOGE("Format failed (unknown exit code %d)", rc);
    202         errno = EIO;
    203         return -1;
    204     }
    205     return 0;
    206 }
    207 
    208 }  // namespace vfat
    209 }  // namespace vold
    210 }  // namespace android
    211