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>
1837dcda68d334f70e1f7f69a9817def65fe3ee717Olivier Bailly#include <stdlib.h>
19bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <fcntl.h>
20bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <unistd.h>
21bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <errno.h>
22bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <string.h>
23bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <dirent.h>
24bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <errno.h>
25bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <fcntl.h>
26bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
27bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/types.h>
28bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/stat.h>
29bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/types.h>
30bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/mman.h>
31bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <sys/mount.h>
32bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
33bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <linux/kdev_t.h>
3437dcda68d334f70e1f7f69a9817def65fe3ee717Olivier Bailly#include <linux/fs.h>
35bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
36bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#define LOG_TAG "Vold"
37bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
38bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <cutils/log.h>
39bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include <cutils/properties.h>
40bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
41bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include "Fat.h"
42bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
43bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatstatic char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
44bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatstatic char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
45bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatextern "C" int logwrap(int argc, const char **argv, int background);
46bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatextern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
47bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
48bf04185c88161f13118b9975cdff7967d49a4fa0San Mehatint Fat::check(const char *fsPath) {
49bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    bool rw = true;
50bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (access(FSCK_MSDOS_PATH, X_OK)) {
5197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Skipping fs checks\n");
52bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return 0;
53bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
54bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
55bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int pass = 1;
56bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc = 0;
57bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    do {
58bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        const char *args[5];
59bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[0] = FSCK_MSDOS_PATH;
60bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[1] = "-p";
61bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[2] = "-f";
62bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[3] = fsPath;
63bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        args[4] = NULL;
64bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
65bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        rc = logwrap(4, args, 1);
66bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
67bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        switch(rc) {
68bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 0:
6997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGI("Filesystem check completed OK");
70bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return 0;
71bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
72bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 2:
7397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("Filesystem check failed (not a FAT filesystem)");
74bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = ENODATA;
75bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
76bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
77bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        case 4:
78bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            if (pass++ <= 3) {
7997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat                SLOGW("Filesystem modified - rechecking (pass %d)",
80bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                        pass);
81bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat                continue;
82bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            }
8397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("Failing check after too many rechecks");
84bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = EIO;
85bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
86bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
87bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        default:
8897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("Filesystem check failed (unknown exit code %d)", rc);
89bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            errno = EIO;
90bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            return -1;
91bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        }
92bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    } while (0);
93bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
94bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return 0;
95bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
96bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
97fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehatint Fat::doMount(const char *fsPath, const char *mountPoint,
98a3e06084564c86ff618c40f185f3676b8b629b94Kenny Root                 bool ro, bool remount, bool executable,
99a3e06084564c86ff618c40f185f3676b8b629b94Kenny Root                 int ownerUid, int ownerGid, int permMask, bool createLost) {
100bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc;
101bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    unsigned long flags;
102fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    char mountData[255];
103bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
104a3e06084564c86ff618c40f185f3676b8b629b94Kenny Root    flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC;
105bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
106a3e06084564c86ff618c40f185f3676b8b629b94Kenny Root    flags |= (executable ? 0 : MS_NOEXEC);
107a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    flags |= (ro ? MS_RDONLY : 0);
108a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    flags |= (remount ? MS_REMOUNT : 0);
109a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
110bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    /*
111bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * Note: This is a temporary hack. If the sampling profiler is enabled,
112bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * we make the SD card world-writable so any process can write snapshots.
113bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     *
114bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     * TODO: Remove this code once we have a drop box in system_server.
115bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat     */
116bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    char value[PROPERTY_VALUE_MAX];
117bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    property_get("persist.sampling_profiler", value, "");
118bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (value[0] == '1') {
11997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("The SD card is world-writable because the"
120bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            " 'persist.sampling_profiler' system property is set to '1'.");
121fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat        permMask = 0;
122bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
123bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
124fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    sprintf(mountData,
125fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat            "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
126fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat            ownerUid, ownerGid, permMask, permMask);
127fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat
128fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
129fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat
130bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (rc && errno == EROFS) {
13197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
132bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        flags |= MS_RDONLY;
133fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat        rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
134bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
135bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
136fff0b47998a722d57eea6a07350bbd7a6032b3ccSan Mehat    if (rc == 0 && createLost) {
137bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        char *lost_path;
138bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        asprintf(&lost_path, "%s/LOST.DIR", mountPoint);
139bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        if (access(lost_path, F_OK)) {
140bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            /*
141bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             * Create a LOST.DIR in the root so we have somewhere to put
142bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             * lost cluster chains (fsck_msdos doesn't currently do this)
143bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat             */
144bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            if (mkdir(lost_path, 0755)) {
14597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat                SLOGE("Unable to create LOST.DIR (%s)", strerror(errno));
146bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat            }
147bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        }
148bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        free(lost_path);
149bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
150bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
151bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return rc;
152bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
153bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
154fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehatint Fat::format(const char *fsPath, unsigned int numSectors) {
155bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int fd;
156fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    const char *args[11];
157bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    int rc;
158fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
159bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[0] = MKDOSFS_PATH;
160bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[1] = "-F";
1618d934caeae971d7d08ca33e98dae294eb57c402dSan Mehat    args[2] = "32";
162bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[3] = "-O";
163bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    args[4] = "android";
164b9aed74b146beb7499ebc5775e8ae179d16900efSan Mehat    args[5] = "-c";
165b9aed74b146beb7499ebc5775e8ae179d16900efSan Mehat    args[6] = "8";
166fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat
167fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    if (numSectors) {
168fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        char tmp[32];
169fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        snprintf(tmp, sizeof(tmp), "%u", numSectors);
170fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        const char *size = tmp;
171fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[7] = "-s";
172fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[8] = size;
173fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[9] = fsPath;
174fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[10] = NULL;
175fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        rc = logwrap(11, args, 1);
176fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    } else {
177fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[7] = fsPath;
178fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        args[8] = NULL;
179fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat        rc = logwrap(9, args, 1);
180fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    }
181bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
182bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    if (rc == 0) {
18397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGI("Filesystem formatted OK");
184bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return 0;
185bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    } else {
18697ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Format failed (unknown exit code %d)", rc);
187bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        errno = EIO;
188bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        return -1;
189bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    }
190bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat    return 0;
191bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat}
192