Volume.cpp revision 49e2bce5b74129c26a35e25d4693cbfe98c4688e
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::mount() {
60    char nodepath[255];
61    int major = -1, minor = -1;
62
63    if (prepareToMount(&major, &minor)) {
64        LOGE("Volume failed to prepare: %s", strerror(errno));
65        return -1;
66    }
67
68    /* Create device nodes */
69    mode_t mode = 0660 | S_IFBLK;
70    dev_t dev = (major << 8) | minor;
71    sprintf(nodepath, "/dev/block/vold/%d:%d", major, minor);
72    if (mknod(nodepath, mode, dev) < 0) {
73        LOGE("Error making device nodes for '%s' (%s)",
74             nodepath, strerror(errno));
75        return -1;
76    }
77
78    /* Run disk checker */
79    if (checkFilesystem(nodepath)) {
80        setState(Volume::State_Idle);
81        return -1;
82    }
83
84    setState(Volume::State_Idle);
85    return 0;
86}
87
88int Volume::checkFilesystem(const char *nodepath) {
89
90    bool rw = true;
91    if (access(FSCK_MSDOS_PATH, X_OK)) {
92        LOGW("Skipping fs checks\n");
93        return 0;
94    }
95
96    setState(Volume::State_Checking);
97    int pass = 1;
98    int rc = 0;
99    do {
100        const char *args[5];
101        args[0] = FSCK_MSDOS_PATH;
102        args[1] = "-p";
103        args[2] = "-f";
104        args[3] = nodepath;
105        args[4] = NULL;
106
107        rc = logwrap(4, args, 1);
108
109        switch(rc) {
110        case 0:
111            LOGI("Filesystem check completed OK");
112            return 0;
113
114        case 2:
115            LOGE("Filesystem check failed (not a FAT filesystem)");
116            errno = ENODATA;
117            return -1;
118
119        case 4:
120            if (pass++ <= 3) {
121                LOGW("Filesystem modified - rechecking (pass %d)",
122                        pass);
123                continue;
124            }
125            LOGE("Failing check after too many rechecks");
126            errno = EIO;
127            return -1;
128
129        default:
130            LOGE("Filesystem check failed (unknown exit code %d)", rc);
131            errno = EIO;
132            return -1;
133        }
134    } while (0);
135
136    return 0;
137}
138
139int Volume::unmount() {
140    return 0;
141}
142