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 #include <android-base/logging.h>
     39 #include <android-base/stringprintf.h>
     40 #include <selinux/selinux.h>
     41 
     42 #include <logwrap/logwrap.h>
     43 
     44 #include "Vfat.h"
     45 #include "Utils.h"
     46 #include "VoldUtil.h"
     47 
     48 using android::base::StringPrintf;
     49 
     50 namespace android {
     51 namespace vold {
     52 namespace vfat {
     53 
     54 static const char* kMkfsPath = "/system/bin/newfs_msdos";
     55 static const char* kFsckPath = "/system/bin/fsck_msdos";
     56 
     57 bool IsSupported() {
     58     return access(kMkfsPath, X_OK) == 0
     59             && access(kFsckPath, X_OK) == 0
     60             && IsFilesystemSupported("vfat");
     61 }
     62 
     63 status_t Check(const std::string& source) {
     64     int pass = 1;
     65     int rc = 0;
     66     do {
     67         std::vector<std::string> cmd;
     68         cmd.push_back(kFsckPath);
     69         cmd.push_back("-p");
     70         cmd.push_back("-f");
     71         cmd.push_back(source);
     72 
     73         // Fat devices are currently always untrusted
     74         rc = ForkExecvp(cmd, sFsckUntrustedContext);
     75 
     76         if (rc < 0) {
     77             LOG(ERROR) << "Filesystem check failed due to logwrap error";
     78             errno = EIO;
     79             return -1;
     80         }
     81 
     82         switch(rc) {
     83         case 0:
     84             LOG(INFO) << "Filesystem check completed OK";
     85             return 0;
     86 
     87         case 2:
     88             LOG(ERROR) << "Filesystem check failed (not a FAT filesystem)";
     89             errno = ENODATA;
     90             return -1;
     91 
     92         case 4:
     93             if (pass++ <= 3) {
     94                 LOG(WARNING) << "Filesystem modified - rechecking (pass " << pass << ")";
     95                 continue;
     96             }
     97             LOG(ERROR) << "Failing check after too many rechecks";
     98             errno = EIO;
     99             return -1;
    100 
    101         case 8:
    102             LOG(ERROR) << "Filesystem check failed (no filesystem)";
    103             errno = ENODATA;
    104             return -1;
    105 
    106         default:
    107             LOG(ERROR) << "Filesystem check failed (unknown exit code " << rc << ")";
    108             errno = EIO;
    109             return -1;
    110         }
    111     } while (0);
    112 
    113     return 0;
    114 }
    115 
    116 status_t Mount(const std::string& source, const std::string& target, bool ro,
    117         bool remount, bool executable, int ownerUid, int ownerGid, int permMask,
    118         bool createLost) {
    119     int rc;
    120     unsigned long flags;
    121 
    122     const char* c_source = source.c_str();
    123     const char* c_target = target.c_str();
    124 
    125     flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME;
    126 
    127     flags |= (executable ? 0 : MS_NOEXEC);
    128     flags |= (ro ? MS_RDONLY : 0);
    129     flags |= (remount ? MS_REMOUNT : 0);
    130 
    131     auto mountData = android::base::StringPrintf(
    132             "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
    133             ownerUid, ownerGid, permMask, permMask);
    134 
    135     rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
    136 
    137     if (rc && errno == EROFS) {
    138         LOG(ERROR) << source << " appears to be a read only filesystem - retrying mount RO";
    139         flags |= MS_RDONLY;
    140         rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
    141     }
    142 
    143     if (rc == 0 && createLost) {
    144         auto lost_path = android::base::StringPrintf("%s/LOST.DIR", target.c_str());
    145         if (access(lost_path.c_str(), F_OK)) {
    146             /*
    147              * Create a LOST.DIR in the root so we have somewhere to put
    148              * lost cluster chains (fsck_msdos doesn't currently do this)
    149              */
    150             if (mkdir(lost_path.c_str(), 0755)) {
    151                 PLOG(ERROR) << "Unable to create LOST.DIR";
    152             }
    153         }
    154     }
    155 
    156     return rc;
    157 }
    158 
    159 status_t Format(const std::string& source, unsigned long numSectors) {
    160     std::vector<std::string> cmd;
    161     cmd.push_back(kMkfsPath);
    162     cmd.push_back("-F");
    163     cmd.push_back("32");
    164     cmd.push_back("-O");
    165     cmd.push_back("android");
    166     cmd.push_back("-c");
    167     cmd.push_back("64");
    168     cmd.push_back("-A");
    169 
    170     if (numSectors) {
    171         cmd.push_back("-s");
    172         cmd.push_back(StringPrintf("%lu", numSectors));
    173     }
    174 
    175     cmd.push_back(source);
    176 
    177     int rc = ForkExecvp(cmd);
    178     if (rc < 0) {
    179         LOG(ERROR) << "Filesystem format failed due to logwrap error";
    180         errno = EIO;
    181         return -1;
    182     }
    183 
    184     if (rc == 0) {
    185         LOG(INFO) << "Filesystem formatted OK";
    186         return 0;
    187     } else {
    188         LOG(ERROR) << "Format failed (unknown exit code " << rc << ")";
    189         errno = EIO;
    190         return -1;
    191     }
    192     return 0;
    193 }
    194 
    195 }  // namespace vfat
    196 }  // namespace vold
    197 }  // namespace android
    198