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