/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG_TAG "Vold"
#include
#include "Ext.h"
static char FSCK_EXT_PATH[] = "/system/bin/e2fsck";
static char MKEXTFS_PATH[] = "/system/bin/mke2fs";
extern "C" int logwrap(int argc, const char **argv, int background);
extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
int Ext::check(const char *fsPath) {
bool rw = true;
if (access(FSCK_EXT_PATH, X_OK)) {
SLOGW("Skipping fs checks\n");
return 0;
}
int pass = 1;
int rc = 0;
do {
const char *args[5];
args[0] = FSCK_EXT_PATH;
args[1] = "-p";
args[2] = "-f";
args[3] = fsPath;
args[4] = NULL;
rc = logwrap(4, args, 1);
switch(rc) {
case 0:
case 1:
SLOGI("Filesystem check completed OK");
return 0;
case 2:
SLOGE("Filesystem check completed, system should be rebooted");
errno = ENODATA;
return -1;
case 4:
SLOGE("Filesystem errors left uncorrected");
errno = EIO;
return -1;
default:
SLOGE("Filesystem check failed (exit code %d)", rc);
errno = EIO;
return -1;
}
} while (0);
return 0;
}
bool Ext::doDir(const char * mountpoint, const char * path) {
char *full_path;
struct stat buffer;
int rc;
mode_t mode = S_IRWXU | S_IRUSR | S_IWUSR | S_IRWXG | S_IRGRP | S_IWGRP | S_IXGRP | S_IXOTH;
asprintf(&full_path, "%s/%s", mountpoint, path);
rc = stat(full_path, &buffer);
if (rc == 0) {
if (S_ISDIR(buffer.st_mode)) {
/* check owner & permissions */
if (buffer.st_uid != 1000 || buffer.st_gid != 1000)
if(chown(full_path, 1000, 1000) != 0) {
SLOGE("Cannot set UID/GID for %s - %s", full_path, strerror(errno));
free(full_path);
return false;
}
if (buffer.st_mode != mode)
if (chmod(full_path, mode) != 0) {
SLOGE("Cannot set permissions on %s - %s", full_path, strerror(errno));
free(full_path);
return false;
}
} else {
SLOGE("%s is not a dir. Retreat!", full_path);
free(full_path);
return false;
}
} else {
/* This assumes that stat will fail only when full_path
* doesn't exists
*/
SLOGI("Creating %s", full_path);
if (mkdir(full_path, mode) == 0) {
if (chown(full_path, 1000, 1000) != 0) {
SLOGE("Cannot set UID/GID for %s - %s", full_path, strerror(errno));
free(full_path);
return false;
}
} else {
SLOGE("Cannot create dir %s - %s", full_path, strerror(errno));
free(full_path);
return false;
}
}
free(full_path);
return true;
}
int Ext::doMount(const char *fsPath, const char *mountPoint,
bool chkDirs, bool remount) {
int rc;
unsigned long flags;
char mountData[255];
flags = MS_NODEV | MS_NOATIME | MS_NODIRATIME;
flags |= (remount ? MS_REMOUNT : 0);
sprintf(mountData,"barrier=1,data=ordered,noauto_da_alloc");
rc = mount(fsPath, mountPoint, "ext4", flags, mountData);
if (rc && errno == EROFS) {
SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
flags |= MS_RDONLY;
rc = mount(fsPath, mountPoint, "ext4", flags, mountData);
}
if (rc == 0 && chkDirs) {
if (!doDir(mountPoint, "app") || !doDir(mountPoint, "app-private") ||
!doDir(mountPoint, "dalvik-cache") || !doDir(mountPoint, "data") ||
!doDir(mountPoint, "system") || !doDir("/data", "system")) {
(void)umount(mountPoint);
return -1;
}
}
return rc;
}
int Ext::format(const char *fsPath) {
int fd;
const char *args[3];
int rc;
args[0] = MKEXTFS_PATH;
args[1] = fsPath;
args[2] = NULL;
rc = logwrap(3, args, 1);
if (rc == 0) {
SLOGI("Filesystem formatted OK");
return 0;
} else {
SLOGE("Format failed (unknown exit code %d)", rc);
errno = EIO;
return -1;
}
return 0;
}