Fat.cpp revision 8d934caeae971d7d08ca33e98dae294eb57c402d
1bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat/*
2bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * Copyright (C) 2008 The Android Open Source Project
3bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat *
4bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * you may not use this file except in compliance with the License.
6bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * You may obtain a copy of the License at
7bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat *
8bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat *
10bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * Unless required by applicable law or agreed to in writing, software
11bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * See the License for the specific language governing permissions and
14bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat * limitations under the License.
15bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat */
16bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
17bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <stdio.h>
18bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <fcntl.h>
19bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <unistd.h>
20bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <errno.h>
21bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <string.h>
22bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <dirent.h>
23bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <errno.h>
24bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <fcntl.h>
25bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
26bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/types.h>
27bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/stat.h>
28bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/types.h>
29bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/mman.h>
30bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/mount.h>
31bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
32bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <linux/kdev_t.h>
33bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
34bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#define LOG_TAG "Vold"
35bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
36bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <cutils/log.h>
37bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <cutils/properties.h>
38bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
39bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include "Fat.h"
40bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
41bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatstatic char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
42bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatstatic char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
43bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatextern "C" int logwrap(int argc, const char **argv, int background);
44bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatextern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
45bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
46bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatint Fat::check(const char *fsPath) {
47bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    bool rw = true;
48bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (access(FSCK_MSDOS_PATH, X_OK)) {
49bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGW("Skipping fs checks\n");
50bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return 0;
51bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
52bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
53bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int pass = 1;
54bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc = 0;
55bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    do {
56bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        const char *args[5];
57bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[0] = FSCK_MSDOS_PATH;
58bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[1] = "-p";
59bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[2] = "-f";
60bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[3] = fsPath;
61bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[4] = NULL;
62bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
63bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        rc = logwrap(4, args, 1);
64bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
65bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        switch(rc) {
66bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 0:
67bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            LOGI("Filesystem check completed OK");
68bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return 0;
69bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
70bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 2:
71bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            LOGE("Filesystem check failed (not a FAT filesystem)");
72bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = ENODATA;
73bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
74bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
75bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 4:
76bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            if (pass++ <= 3) {
77bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                LOGW("Filesystem modified - rechecking (pass %d)",
78bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                        pass);
79bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                continue;
80bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            }
81bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            LOGE("Failing check after too many rechecks");
82bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = EIO;
83bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
84bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
85bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        default:
86bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            LOGE("Filesystem check failed (unknown exit code %d)", rc);
87bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = EIO;
88bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
89bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        }
90bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    } while (0);
91bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
92bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return 0;
93bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
94bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
95fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehatint Fat::doMount(const char *fsPath, const char *mountPoint,
96fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat                 bool ro, bool remount, int ownerUid, int ownerGid,
97fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat                 int permMask, bool createLost) {
98bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc;
99bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    unsigned long flags;
100fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    char mountData[255];
101bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
102bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
103bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
104a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    flags |= (ro ? MS_RDONLY : 0);
105a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    flags |= (remount ? MS_REMOUNT : 0);
106a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
107bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    /*
108bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * Note: This is a temporary hack. If the sampling profiler is enabled,
109bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * we make the SD card world-writable so any process can write snapshots.
110bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     *
111bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * TODO: Remove this code once we have a drop box in system_server.
112bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     */
113bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    char value[PROPERTY_VALUE_MAX];
114bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    property_get("persist.sampling_profiler", value, "");
115bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (value[0] == '1') {
116bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGW("The SD card is world-writable because the"
117bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            " 'persist.sampling_profiler' system property is set to '1'.");
118fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat        permMask = 0;
119bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
120bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
121fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    sprintf(mountData,
122fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat            "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
123fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat            ownerUid, ownerGid, permMask, permMask);
124fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat
125fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
126fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat
127bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (rc && errno == EROFS) {
128bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
129bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        flags |= MS_RDONLY;
130fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat        rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
131bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
132bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
133fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    if (rc == 0 && createLost) {
134bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        char *lost_path;
135bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        asprintf(&lost_path, "%s/LOST.DIR", mountPoint);
136bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        if (access(lost_path, F_OK)) {
137bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            /*
138bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             * Create a LOST.DIR in the root so we have somewhere to put
139bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             * lost cluster chains (fsck_msdos doesn't currently do this)
140bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             */
141bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            if (mkdir(lost_path, 0755)) {
142bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                LOGE("Unable to create LOST.DIR (%s)", strerror(errno));
143bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            }
144bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        }
145bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        free(lost_path);
146bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
147bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
148bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return rc;
149bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
150bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
151bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatint Fat::format(const char *fsPath) {
152bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    unsigned int nr_sec;
153bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int fd;
154bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
155bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if ((fd = open(fsPath, O_RDWR)) < 0) {
156bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGE("Error opening disk file (%s)", strerror(errno));
157bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return -1;
158bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
159bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
160bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
161bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGE("Unable to get device size (%s)", strerror(errno));
162bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        close(fd);
163bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return -1;
164bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
165bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    close(fd);
166bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
167bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    const char *args[7];
168bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc;
169bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[0] = MKDOSFS_PATH;
170bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[1] = "-F";
1718d934caeae971d7d08ca33e98dae294eb57c402dSan Mehat    args[2] = "32";
172bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[3] = "-O";
173bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[4] = "android";
174bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[5] = fsPath;
175bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[6] = NULL;
176bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    rc = logwrap(7, args, 1);
177bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
178bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (rc == 0) {
179bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGI("Filesystem formatted OK");
180bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return 0;
181bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    } else {
182bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        LOGE("Format failed (unknown exit code %d)", rc);
183bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        errno = EIO;
184bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return -1;
185bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
186bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return 0;
187bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
188