/* * 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 <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mount.h> #include <linux/ext2_fs.h> #include <linux/ext3_fs.h> #include "vold.h" #include "volmgr.h" #include "volmgr_ext3.h" #include "logwrapper.h" #define EXT_DEBUG 0 static char E2FSCK_PATH[] = "/system/bin/e2fsck"; int ext_identify(blkdev_t *dev) { int rc = -1; int fd; struct ext3_super_block sb; char *devpath; #if EXT_DEBUG LOG_VOL("ext_identify(%d:%d):", dev-major, dev->minor); #endif devpath = blkdev_get_devpath(dev); if ((fd = open(devpath, O_RDWR)) < 0) { LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno)); free(devpath); return -errno; } if (lseek(fd, 1024, SEEK_SET) < 0) { LOGE("Unable to lseek to get superblock (%s)", strerror(errno)); rc = -errno; goto out; } if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { LOGE("Unable to read superblock (%s)", strerror(errno)); rc = -errno; goto out; } if (sb.s_magic == EXT2_SUPER_MAGIC || sb.s_magic == EXT3_SUPER_MAGIC) rc = 0; else rc = -ENODATA; out: #if EXT_DEBUG LOG_VOL("ext_identify(%s): rc = %d", devpath, rc); #endif free(devpath); close(fd); return rc; } int ext_check(blkdev_t *dev) { char *devpath; #if EXT_DEBUG LOG_VOL("ext_check(%s):", dev->dev_fspath); #endif devpath = blkdev_get_devpath(dev); if (access(E2FSCK_PATH, X_OK)) { LOGE("ext_check(%s): %s not found (skipping checks)", devpath, E2FSCK_PATH); free(devpath); return 0; } char *args[5]; args[0] = E2FSCK_PATH; args[1] = "-v"; args[2] = "-p"; args[3] = devpath; args[4] = NULL; int rc = logwrap(4, args, 1); if (rc == 0) { LOG_VOL("filesystem '%s' had no errors", devpath); } else if (rc == 1) { LOG_VOL("filesystem '%s' had corrected errors", devpath); rc = 0; } else if (rc == 2) { LOGE("VOL volume '%s' had corrected errors (system should be rebooted)", devpath); rc = -EIO; } else if (rc == 4) { LOGE("VOL volume '%s' had uncorrectable errors", devpath); rc = -EIO; } else if (rc == 8) { LOGE("Operational error while checking volume '%s'", devpath); rc = -EIO; } else { LOGE("Unknown e2fsck exit code (%d)", rc); rc = -EIO; } free(devpath); return rc; } int ext_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode) { #if EXT_DEBUG LOG_VOL("ext_mount(%s, %s, %d):", dev->dev_fspath, vol->mount_point, safe_mode); #endif char *fs[] = { "ext3", "ext2", NULL }; char *devpath; devpath = blkdev_get_devpath(dev); int flags, rc = 0; flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME; if (safe_mode) flags |= MS_SYNCHRONOUS; if (vol->state == volstate_mounted) { LOG_VOL("Remounting %s on %s, safe mode %d", devpath, vol->mount_point, safe_mode); flags |= MS_REMOUNT; } char **f; for (f = fs; *f != NULL; f++) { rc = mount(devpath, vol->mount_point, *f, flags, NULL); if (rc && errno == EROFS) { LOGE("ext_mount(%s, %s): Read only filesystem - retrying mount RO", devpath, vol->mount_point); flags |= MS_RDONLY; rc = mount(devpath, vol->mount_point, *f, flags, NULL); } #if EXT_DEBUG LOG_VOL("ext_mount(%s, %s): %s mount rc = %d", devpath, *f, vol->mount_point, rc); #endif if (!rc) break; } free(devpath); // Chmod the mount point so that its a free-for-all. // (required for consistency with VFAT.. sigh) if (chmod(vol->mount_point, 0777) < 0) { LOGE("Failed to chmod %s (%s)", vol->mount_point, strerror(errno)); return -errno; } return rc; }