Volume.cpp revision dd9b8e92aaf330b48ddb40a7380588ef92b53de6
1f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat/*
2f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Copyright (C) 2008 The Android Open Source Project
3f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
4f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * you may not use this file except in compliance with the License.
6f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * You may obtain a copy of the License at
7f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
8f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
10f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Unless required by applicable law or agreed to in writing, software
11f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * See the License for the specific language governing permissions and
14f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * limitations under the License.
15f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat */
16f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
1749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <stdlib.h>
18f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <string.h>
1949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <dirent.h>
2049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <errno.h>
2149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <fcntl.h>
2249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
2349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/types.h>
2449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/stat.h>
2549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/types.h>
2649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/mman.h>
27f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
28f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#define LOG_TAG "Vold"
29f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
30f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <cutils/log.h>
31f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
32f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "Volume.h"
33f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
3449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatextern "C" int logwrap(int argc, const char **argv, int background);
3549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
3649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatstatic char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
3749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
38f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolume::Volume(const char *label, const char *mount_point) {
39f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mLabel = strdup(label);
40f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mMountpoint = strdup(mount_point);
41f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mState = Volume::State_Init;
42f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
43f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
44f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolume::~Volume() {
45f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    free(mLabel);
46f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    free(mMountpoint);
47f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
48f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
49fd7f5875129adfe2845f4f3fffb17db3a89eea25San Mehatint Volume::handleBlockEvent(NetlinkEvent *evt) {
50f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    errno = ENOSYS;
51f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return -1;
52f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
53f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
54f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehatvoid Volume::setState(int state) {
55f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    LOGD("Volume %s state changing %d -> %d", mLabel, mState, state);
56f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mState = state;
57f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
5849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
59dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehatint Volume::createDeviceNode(const char *path, int major, int minor) {
60dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    mode_t mode = 0660 | S_IFBLK;
61dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    dev_t dev = (major << 8) | minor;
62dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    if (mknod(path, mode, dev) < 0) {
63dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        if (errno != EEXIST) {
64dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat            return -1;
65dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        }
66dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    }
67dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    return 0;
68dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat}
69dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
7049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatint Volume::mount() {
7149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    char nodepath[255];
7249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    int major = -1, minor = -1;
7349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
7449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (prepareToMount(&major, &minor)) {
7549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        LOGE("Volume failed to prepare: %s", strerror(errno));
7649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
7749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
7849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
7949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    sprintf(nodepath, "/dev/block/vold/%d:%d", major, minor);
80dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
81dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    LOGD("nodepath = %s\n", nodepath);
82dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
83dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    /* Create device nodes */
84dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    if (createDeviceNode(nodepath, major, minor)) {
85dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        LOGE("Error making device nodes for '%s' (%s)", nodepath,
86dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat             strerror(errno));
87dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        // XXX: cleanup will be needed eventually
8849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
8949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
9049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
9149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    /* Run disk checker */
9249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (checkFilesystem(nodepath)) {
93dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        LOGE("Error checking filesystem (%s)", strerror(errno));
9449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        setState(Volume::State_Idle);
9549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
9649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
9749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
98dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
99dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
10049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    setState(Volume::State_Idle);
10149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    return 0;
10249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
10349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
10449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatint Volume::checkFilesystem(const char *nodepath) {
10549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
10649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    bool rw = true;
10749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    if (access(FSCK_MSDOS_PATH, X_OK)) {
10849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        LOGW("Skipping fs checks\n");
10949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return 0;
11049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
11149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
11249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    setState(Volume::State_Checking);
11349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    int pass = 1;
11449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    int rc = 0;
11549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    do {
11649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        const char *args[5];
11749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        args[0] = FSCK_MSDOS_PATH;
11849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        args[1] = "-p";
11949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        args[2] = "-f";
12049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        args[3] = nodepath;
12149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        args[4] = NULL;
12249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
12349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        rc = logwrap(4, args, 1);
12449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
12549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        switch(rc) {
12649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        case 0:
12749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            LOGI("Filesystem check completed OK");
12849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            return 0;
12949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
13049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        case 2:
13149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            LOGE("Filesystem check failed (not a FAT filesystem)");
13249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            errno = ENODATA;
13349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            return -1;
13449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
13549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        case 4:
13649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            if (pass++ <= 3) {
13749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat                LOGW("Filesystem modified - rechecking (pass %d)",
13849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat                        pass);
13949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat                continue;
14049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            }
14149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            LOGE("Failing check after too many rechecks");
14249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            errno = EIO;
14349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            return -1;
14449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
14549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        default:
14649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            LOGE("Filesystem check failed (unknown exit code %d)", rc);
14749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            errno = EIO;
14849e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat            return -1;
14949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        }
15049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    } while (0);
15149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
15249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    return 0;
15349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
15449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
15549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehatint Volume::unmount() {
15649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    return 0;
15749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat}
158