| |
| /* |
| * 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; |
| } |