Volume.cpp revision dd9b8e92aaf330b48ddb40a7380588ef92b53de6
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 <stdlib.h>
18#include <string.h>
19#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/mman.h>
27
28#define LOG_TAG "Vold"
29
30#include <cutils/log.h>
31
32#include "Volume.h"
33
34extern "C" int logwrap(int argc, const char **argv, int background);
35
36static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
37
38Volume::Volume(const char *label, const char *mount_point) {
39    mLabel = strdup(label);
40    mMountpoint = strdup(mount_point);
41    mState = Volume::State_Init;
42}
43
44Volume::~Volume() {
45    free(mLabel);
46    free(mMountpoint);
47}
48
49int Volume::handleBlockEvent(NetlinkEvent *evt) {
50    errno = ENOSYS;
51    return -1;
52}
53
54void Volume::setState(int state) {
55    LOGD("Volume %s state changing %d -> %d", mLabel, mState, state);
56    mState = state;
57}
58
59int Volume::createDeviceNode(const char *path, int major, int minor) {
60    mode_t mode = 0660 | S_IFBLK;
61    dev_t dev = (major << 8) | minor;
62    if (mknod(path, mode, dev) < 0) {
63        if (errno != EEXIST) {
64            return -1;
65        }
66    }
67    return 0;
68}
69
70int Volume::mount() {
71    char nodepath[255];
72    int major = -1, minor = -1;
73
74    if (prepareToMount(&major, &minor)) {
75        LOGE("Volume failed to prepare: %s", strerror(errno));
76        return -1;
77    }
78
79    sprintf(nodepath, "/dev/block/vold/%d:%d", major, minor);
80
81    LOGD("nodepath = %s\n", nodepath);
82
83    /* Create device nodes */
84    if (createDeviceNode(nodepath, major, minor)) {
85        LOGE("Error making device nodes for '%s' (%s)", nodepath,
86             strerror(errno));
87        // XXX: cleanup will be needed eventually
88        return -1;
89    }
90
91    /* Run disk checker */
92    if (checkFilesystem(nodepath)) {
93        LOGE("Error checking filesystem (%s)", strerror(errno));
94        setState(Volume::State_Idle);
95        return -1;
96    }
97
98
99
100    setState(Volume::State_Idle);
101    return 0;
102}
103
104int Volume::checkFilesystem(const char *nodepath) {
105
106    bool rw = true;
107    if (access(FSCK_MSDOS_PATH, X_OK)) {
108        LOGW("Skipping fs checks\n");
109        return 0;
110    }
111
112    setState(Volume::State_Checking);
113    int pass = 1;
114    int rc = 0;
115    do {
116        const char *args[5];
117        args[0] = FSCK_MSDOS_PATH;
118        args[1] = "-p";
119        args[2] = "-f";
120        args[3] = nodepath;
121        args[4] = NULL;
122
123        rc = logwrap(4, args, 1);
124
125        switch(rc) {
126        case 0:
127            LOGI("Filesystem check completed OK");
128            return 0;
129
130        case 2:
131            LOGE("Filesystem check failed (not a FAT filesystem)");
132            errno = ENODATA;
133            return -1;
134
135        case 4:
136            if (pass++ <= 3) {
137                LOGW("Filesystem modified - rechecking (pass %d)",
138                        pass);
139                continue;
140            }
141            LOGE("Failing check after too many rechecks");
142            errno = EIO;
143            return -1;
144
145        default:
146            LOGE("Filesystem check failed (unknown exit code %d)", rc);
147            errno = EIO;
148            return -1;
149        }
150    } while (0);
151
152    return 0;
153}
154
155int Volume::unmount() {
156    return 0;
157}
158