Vold: Add fsync in writeStringToFile() am: 701d05d32c
am: ee8170f2ac
Change-Id: I2ce9e9a6ea1969e1bf41ef6886dc4d27ee19f58a
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..ae4a451
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..5941cd9
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,190 @@
+cc_defaults {
+ name: "vold_default_flags",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ ],
+
+ clang: true,
+
+ tidy: true,
+ tidy_checks: [
+ "-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ ],
+ tidy_flags: [
+ "-warnings-as-errors=clang-analyzer-security*,cert-*",
+ ],
+}
+
+cc_defaults {
+ name: "vold_default_libs",
+
+ static_libs: [
+ "libavb",
+ "libbootloader_message",
+ "libfec",
+ "libfec_rs",
+ "libfs_mgr",
+ "libscrypt_static",
+ "libsquashfs_utils",
+ "libvold_binder",
+ ],
+ shared_libs: [
+ "android.hardware.keymaster@3.0",
+ "libbase",
+ "libbinder",
+ "libcrypto",
+ "libcrypto_utils",
+ "libcutils",
+ "libdiskconfig",
+ "libext4_utils",
+ "libf2fs_sparseblock",
+ "libhardware",
+ "libhardware_legacy",
+ "libhidlbase",
+ "libhwbinder",
+ "libkeystore_binder",
+ "libkeyutils",
+ "liblog",
+ "liblogwrap",
+ "libselinux",
+ "libsysutils",
+ "libutils",
+ ],
+}
+
+cc_library_static {
+ name: "libvold_binder",
+ defaults: ["vold_default_flags"],
+
+ srcs: [
+ "binder/android/os/IVold.aidl",
+ "binder/android/os/IVoldListener.aidl",
+ "binder/android/os/IVoldTaskListener.aidl",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ local_include_dirs: ["binder"],
+ include_dirs: ["frameworks/native/aidl/binder"],
+ export_aidl_headers: true,
+ },
+}
+
+// Static library factored out to support testing
+cc_library_static {
+ name: "libvold",
+ defaults: [
+ "vold_default_flags",
+ "vold_default_libs",
+ ],
+
+ srcs: [
+ "Benchmark.cpp",
+ "CheckEncryption.cpp",
+ "Devmapper.cpp",
+ "EncryptInplace.cpp",
+ "Ext4Crypt.cpp",
+ "FileDeviceUtils.cpp",
+ "IdleMaint.cpp",
+ "KeyBuffer.cpp",
+ "KeyStorage.cpp",
+ "KeyUtil.cpp",
+ "Keymaster.cpp",
+ "Loop.cpp",
+ "MetadataCrypt.cpp",
+ "MoveStorage.cpp",
+ "NetlinkHandler.cpp",
+ "NetlinkManager.cpp",
+ "Process.cpp",
+ "ScryptParameters.cpp",
+ "Utils.cpp",
+ "VoldNativeService.cpp",
+ "VoldUtil.cpp",
+ "VolumeManager.cpp",
+ "cryptfs.cpp",
+ "fs/Ext4.cpp",
+ "fs/F2fs.cpp",
+ "fs/Vfat.cpp",
+ "model/Disk.cpp",
+ "model/EmulatedVolume.cpp",
+ "model/ObbVolume.cpp",
+ "model/PrivateVolume.cpp",
+ "model/PublicVolume.cpp",
+ "model/VolumeBase.cpp",
+ "secontext.cpp",
+ ],
+}
+
+cc_binary {
+ name: "vold",
+ defaults: [
+ "vold_default_flags",
+ "vold_default_libs",
+ ],
+
+ srcs: ["main.cpp"],
+ static_libs: ["libvold"],
+ init_rc: ["vold.rc"],
+
+ required: [
+ "mke2fs",
+ "vold_prepare_subdirs",
+ ],
+}
+
+cc_binary {
+ name: "vdc",
+ defaults: ["vold_default_flags"],
+
+ srcs: ["vdc.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+ static_libs: [
+ "libvold_binder",
+ ],
+ init_rc: ["vdc.rc"],
+}
+
+cc_binary {
+ name: "secdiscard",
+ defaults: ["vold_default_flags"],
+
+ srcs: [
+ "FileDeviceUtils.cpp",
+ "secdiscard.cpp",
+ ],
+ shared_libs: ["libbase"],
+}
+
+cc_binary {
+ name: "vold_prepare_subdirs",
+ defaults: ["vold_default_flags"],
+
+ srcs: ["vold_prepare_subdirs.cpp", "Utils.cpp"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblogwrap",
+ "libselinux",
+ "libutils",
+ ],
+ static_libs: [
+ "libvold_binder",
+ ],
+}
+
+subdirs = ["tests"]
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index bd457f6..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,173 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-common_src_files := \
- VolumeManager.cpp \
- CommandListener.cpp \
- CryptCommandListener.cpp \
- VoldCommand.cpp \
- NetlinkManager.cpp \
- NetlinkHandler.cpp \
- Process.cpp \
- fs/Ext4.cpp \
- fs/F2fs.cpp \
- fs/Vfat.cpp \
- Loop.cpp \
- Devmapper.cpp \
- ResponseCode.cpp \
- Ext4Crypt.cpp \
- VoldUtil.c \
- cryptfs.cpp \
- Disk.cpp \
- VolumeBase.cpp \
- PublicVolume.cpp \
- PrivateVolume.cpp \
- EmulatedVolume.cpp \
- Utils.cpp \
- MoveTask.cpp \
- Benchmark.cpp \
- TrimTask.cpp \
- KeyBuffer.cpp \
- Keymaster.cpp \
- KeyStorage.cpp \
- KeyUtil.cpp \
- ScryptParameters.cpp \
- secontext.cpp \
- EncryptInplace.cpp \
- MetadataCrypt.cpp \
-
-common_c_includes := \
- system/extras/f2fs_utils \
- external/scrypt/lib/crypto \
- external/f2fs-tools/include \
- frameworks/native/include \
- system/security/keystore \
-
-common_shared_libraries := \
- libsysutils \
- libbinder \
- libcutils \
- libkeyutils \
- liblog \
- libdiskconfig \
- libhardware_legacy \
- liblogwrap \
- libext4_utils \
- libf2fs_sparseblock \
- libcrypto_utils \
- libcrypto \
- libselinux \
- libutils \
- libhardware \
- libbase \
- libhwbinder \
- libhidlbase \
- android.hardware.keymaster@3.0 \
- libkeystore_binder
-
-common_static_libraries := \
- libbootloader_message \
- libfs_mgr \
- libfec \
- libfec_rs \
- libsquashfs_utils \
- libscrypt_static \
- libavb \
-
-# TODO: include "cert-err34-c" once we move to Binder
-# TODO: include "cert-err58-cpp" once 36656327 is fixed
-common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*
-common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp
-
-vold_conlyflags := -std=c11
-vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter
-
-required_modules :=
-ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- ifeq ($(TARGET_USES_MKE2FS), true)
- vold_cflags += -DTARGET_USES_MKE2FS
- required_modules += mke2fs
- else
- # Adoptable storage has fully moved to mke2fs, so we need both tools
- required_modules += mke2fs
- required_modules += make_ext4fs
- endif
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE := libvold
-LOCAL_CLANG := true
-LOCAL_TIDY := true
-LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
-LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES := $(common_src_files)
-LOCAL_C_INCLUDES := $(common_c_includes)
-LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
-LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
-LOCAL_MODULE_TAGS := eng tests
-LOCAL_CFLAGS := $(vold_cflags)
-LOCAL_CONLYFLAGS := $(vold_conlyflags)
-LOCAL_REQUIRED_MODULES := $(required_modules)
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE := vold
-LOCAL_CLANG := true
-LOCAL_TIDY := true
-LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
-LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES := \
- main.cpp \
- $(common_src_files)
-
-LOCAL_INIT_RC := vold.rc
-
-LOCAL_C_INCLUDES := $(common_c_includes)
-LOCAL_CFLAGS := $(vold_cflags)
-LOCAL_CONLYFLAGS := $(vold_conlyflags)
-
-LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
-LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
-LOCAL_REQUIRED_MODULES := $(required_modules)
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-LOCAL_TIDY := true
-LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
-LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES := vdc.cpp
-LOCAL_MODULE := vdc
-LOCAL_SHARED_LIBRARIES := libcutils libbase
-LOCAL_CFLAGS := $(vold_cflags)
-LOCAL_CONLYFLAGS := $(vold_conlyflags)
-LOCAL_INIT_RC := vdc.rc
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-LOCAL_TIDY := true
-LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
-LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES:= \
- FileDeviceUtils.cpp \
- secdiscard.cpp \
-
-LOCAL_MODULE:= secdiscard
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_CFLAGS := $(vold_cflags)
-LOCAL_CONLYFLAGS := $(vold_conlyflags)
-
-include $(BUILD_EXECUTABLE)
-
-include $(LOCAL_PATH)/tests/Android.mk
diff --git a/Asec.h b/Asec.h
deleted file mode 100644
index dd64fd0..0000000
--- a/Asec.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _ASEC_H
-#define _ASEC_H
-
-struct asec_superblock {
-#define ASEC_SB_MAGIC 0xc0def00d
- unsigned int magic;
-
-#define ASEC_SB_VER 1
- unsigned char ver;
-
-#define ASEC_SB_C_CIPHER_NONE 0
-#define ASEC_SB_C_CIPHER_TWOFISH 1
-#define ASEC_SB_C_CIPHER_AES 2
- unsigned char c_cipher;
-
-#define ASEC_SB_C_CHAIN_NONE 0
- unsigned char c_chain;
-
-#define ASEC_SB_C_OPTS_NONE 0
-#define ASEC_SB_C_OPTS_EXT4 1
- unsigned char c_opts;
-
-#define ASEC_SB_C_MODE_NONE 0
- unsigned char c_mode;
-} __attribute__((packed));
-
-#endif
diff --git a/Benchmark.cpp b/Benchmark.cpp
index bbab792..dfe3366 100644
--- a/Benchmark.cpp
+++ b/Benchmark.cpp
@@ -17,57 +17,91 @@
#include "Benchmark.h"
#include "BenchmarkGen.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
+#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+
#include <cutils/iosched_policy.h>
+#include <hardware_legacy/power.h>
#include <private/android_filesystem_config.h>
+#include <thread>
+
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
-#define ENABLE_DROP_CACHES 1
-
using android::base::ReadFileToString;
using android::base::WriteStringToFile;
namespace android {
namespace vold {
-static void notifyResult(const std::string& path, int64_t create_d,
- int64_t drop_d, int64_t run_d, int64_t destroy_d) {
- std::string res(path +
- + " " + BenchmarkIdent()
- + " " + std::to_string(create_d)
- + " " + std::to_string(drop_d)
- + " " + std::to_string(run_d)
- + " " + std::to_string(destroy_d));
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
- ResponseCode::BenchmarkResult, res.c_str(), false);
-}
+// Benchmark currently uses chdir(), which means we can only
+// safely run one at a time.
+static std::mutex kBenchmarkLock;
-static nsecs_t benchmark(const std::string& path) {
- errno = 0;
- int orig_prio = getpriority(PRIO_PROCESS, 0);
- if (errno != 0) {
- PLOG(ERROR) << "Failed to getpriority";
- return -1;
- }
- if (setpriority(PRIO_PROCESS, 0, -10) != 0) {
- PLOG(ERROR) << "Failed to setpriority";
- return -1;
+static const char* kWakeLock = "Benchmark";
+
+// Reasonable cards are able to complete the create/run stages
+// in under 20 seconds.
+constexpr auto kTimeout = 20s;
+
+// RAII class for boosting device performance during benchmarks.
+class PerformanceBoost {
+private:
+ int orig_prio;
+ int orig_ioprio;
+ IoSchedClass orig_clazz;
+
+public:
+ PerformanceBoost() {
+ errno = 0;
+ orig_prio = getpriority(PRIO_PROCESS, 0);
+ if (errno != 0) {
+ PLOG(WARNING) << "Failed to getpriority";
+ orig_prio = 0;
+ }
+ if (setpriority(PRIO_PROCESS, 0, -10) != 0) {
+ PLOG(WARNING) << "Failed to setpriority";
+ }
+ if (android_get_ioprio(0, &orig_clazz, &orig_ioprio)) {
+ PLOG(WARNING) << "Failed to android_get_ioprio";
+ orig_ioprio = 0;
+ orig_clazz = IoSchedClass_NONE;
+ }
+ if (android_set_ioprio(0, IoSchedClass_RT, 0)) {
+ PLOG(WARNING) << "Failed to android_set_ioprio";
+ }
}
- IoSchedClass orig_clazz = IoSchedClass_NONE;
- int orig_ioprio = 0;
- if (android_get_ioprio(0, &orig_clazz, &orig_ioprio)) {
- PLOG(ERROR) << "Failed to android_get_ioprio";
+ ~PerformanceBoost() {
+ if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
+ PLOG(WARNING) << "Failed to android_set_ioprio";
+ }
+ if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
+ PLOG(WARNING) << "Failed to setpriority";
+ }
+ }
+};
+
+static status_t benchmarkInternal(const std::string& rootPath,
+ const android::sp<android::os::IVoldTaskListener>& listener,
+ android::os::PersistableBundle* extras) {
+ status_t res = 0;
+
+ auto path = rootPath;
+ path += "/misc";
+ if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
}
- if (android_set_ioprio(0, IoSchedClass_RT, 0)) {
- PLOG(ERROR) << "Failed to android_set_ioprio";
+ path += "/vold";
+ if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
+ return -1;
+ }
+ path += "/bench";
+ if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
@@ -83,70 +117,81 @@
sync();
- LOG(INFO) << "Benchmarking " << path;
- nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
+ extras->putString(String16("path"), String16(path.c_str()));
+ extras->putString(String16("ident"), String16(BenchmarkIdent().c_str()));
- BenchmarkCreate();
- sync();
- nsecs_t create = systemTime(SYSTEM_TIME_BOOTTIME);
-
-#if ENABLE_DROP_CACHES
- LOG(VERBOSE) << "Before drop_caches";
- if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
- PLOG(ERROR) << "Failed to drop_caches";
+ // Always create
+ {
+ android::base::Timer timer;
+ LOG(INFO) << "Creating " << path;
+ res |= BenchmarkCreate([&](int progress) -> bool {
+ if (listener) {
+ listener->onStatus(progress, *extras);
+ }
+ return (timer.duration() < kTimeout);
+ });
+ sync();
+ if (res == OK) extras->putLong(String16("create"), timer.duration().count());
}
- LOG(VERBOSE) << "After drop_caches";
-#endif
- nsecs_t drop = systemTime(SYSTEM_TIME_BOOTTIME);
- BenchmarkRun();
- sync();
- nsecs_t run = systemTime(SYSTEM_TIME_BOOTTIME);
+ // Only drop when we haven't aborted
+ if (res == OK) {
+ android::base::Timer timer;
+ LOG(VERBOSE) << "Before drop_caches";
+ if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
+ PLOG(ERROR) << "Failed to drop_caches";
+ res = -1;
+ }
+ LOG(VERBOSE) << "After drop_caches";
+ sync();
+ if (res == OK) extras->putLong(String16("drop"), timer.duration().count());
+ }
- BenchmarkDestroy();
- sync();
- nsecs_t destroy = systemTime(SYSTEM_TIME_BOOTTIME);
+ // Only run when we haven't aborted
+ if (res == OK) {
+ android::base::Timer timer;
+ LOG(INFO) << "Running " << path;
+ res |= BenchmarkRun([&](int progress) -> bool {
+ if (listener) {
+ listener->onStatus(progress, *extras);
+ }
+ return (timer.duration() < kTimeout);
+ });
+ sync();
+ if (res == OK) extras->putLong(String16("run"), timer.duration().count());
+ }
+
+ // Always destroy
+ {
+ android::base::Timer timer;
+ LOG(INFO) << "Destroying " << path;
+ res |= BenchmarkDestroy();
+ sync();
+ if (res == OK) extras->putLong(String16("destroy"), timer.duration().count());
+ }
if (chdir(orig_cwd) != 0) {
PLOG(ERROR) << "Failed to chdir";
- }
- if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
- PLOG(ERROR) << "Failed to android_set_ioprio";
- }
- if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
- PLOG(ERROR) << "Failed to setpriority";
+ return -1;
}
- nsecs_t create_d = create - start;
- nsecs_t drop_d = drop - create;
- nsecs_t run_d = run - drop;
- nsecs_t destroy_d = destroy - run;
-
- LOG(INFO) << "create took " << nanoseconds_to_milliseconds(create_d) << "ms";
- LOG(INFO) << "drop took " << nanoseconds_to_milliseconds(drop_d) << "ms";
- LOG(INFO) << "run took " << nanoseconds_to_milliseconds(run_d) << "ms";
- LOG(INFO) << "destroy took " << nanoseconds_to_milliseconds(destroy_d) << "ms";
-
- notifyResult(path, create_d, drop_d, run_d, destroy_d);
-
- return run_d;
+ return res;
}
-nsecs_t BenchmarkPrivate(const std::string& path) {
- std::string benchPath(path);
- benchPath += "/misc";
- if (android::vold::PrepareDir(benchPath, 01771, AID_SYSTEM, AID_MISC)) {
- return -1;
+void Benchmark(const std::string& path,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
+ std::lock_guard<std::mutex> lock(kBenchmarkLock);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
+
+ PerformanceBoost boost;
+ android::os::PersistableBundle extras;
+
+ status_t res = benchmarkInternal(path, listener, &extras);
+ if (listener) {
+ listener->onFinished(res, extras);
}
- benchPath += "/vold";
- if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
- return -1;
- }
- benchPath += "/bench";
- if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
- return -1;
- }
- return benchmark(benchPath);
+
+ release_wake_lock(kWakeLock);
}
} // namespace vold
diff --git a/Benchmark.h b/Benchmark.h
index 13f9009..4f19b01 100644
--- a/Benchmark.h
+++ b/Benchmark.h
@@ -17,16 +17,15 @@
#ifndef ANDROID_VOLD_BENCHMARK_H
#define ANDROID_VOLD_BENCHMARK_H
-#include <utils/Errors.h>
-#include <utils/Timers.h>
+#include "android/os/IVoldTaskListener.h"
#include <string>
namespace android {
namespace vold {
-/* Benchmark a private volume mounted at the given path */
-nsecs_t BenchmarkPrivate(const std::string& path);
+void Benchmark(const std::string& path,
+ const android::sp<android::os::IVoldTaskListener>& listener);
} // namespace vold
} // namespace android
diff --git a/BenchmarkGen.h b/BenchmarkGen.h
index cd95aae..a1bf718 100644
--- a/BenchmarkGen.h
+++ b/BenchmarkGen.h
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <algorithm>
+#include <functional>
#include <string>
#include <Utils.h>
@@ -36,10 +37,11 @@
namespace android {
namespace vold {
-static status_t BenchmarkRun() {
+static status_t BenchmarkRun(std::function<bool(int)> checkpoint) {
+
char* buf = (char*) malloc(1048576);
-int t3433f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
+int t3433f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(lseek(t3433f17, 0, SEEK_END));
TEMP_FAILURE_RETRY(lseek(t3433f17, 38891199, SEEK_SET));
TEMP_FAILURE_RETRY(read(t3433f17, buf, 65557));
@@ -50,7 +52,7 @@
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 30, 37276895));
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 14, 37276925));
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 914520, 37273600)); // mmap2
-int t3433f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE));
+int t3433f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3433f18, buf, 4096, 0)); // mmap2
@@ -211,8 +213,8 @@
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 30, 32521955));
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 45, 32521985));
TEMP_FAILURE_RETRY(pread(t3433f17, buf, 6350, 32518144)); // mmap2
-int t3450f18 = TEMP_FAILURE_RETRY(open("file11", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
-int t3450f22 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE));
+int t3450f18 = TEMP_FAILURE_RETRY(open("file11", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3450f22 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3450f22, buf, 1));
close(t3450f22);
t3450f22 = TEMP_FAILURE_RETRY(open("file13", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
@@ -224,7 +226,7 @@
TEMP_FAILURE_RETRY(fsync(t3450f22));
close(t3450f22);
close(t3450f18);
-int t3454f26 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3454f26 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(lseek(t3454f26, 0, SEEK_END));
TEMP_FAILURE_RETRY(lseek(t3454f26, 38891199, SEEK_SET));
TEMP_FAILURE_RETRY(read(t3454f26, buf, 65557));
@@ -236,7 +238,7 @@
TEMP_FAILURE_RETRY(read(t3454f26, buf, 65557));
TEMP_FAILURE_RETRY(pread(t3454f26, buf, 769726, 38187008)); // mmap2
close(t3454f26);
-int t3455f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
+int t3455f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(lseek(t3455f17, 0, SEEK_END));
TEMP_FAILURE_RETRY(lseek(t3455f17, 38891199, SEEK_SET));
TEMP_FAILURE_RETRY(read(t3455f17, buf, 65557));
@@ -247,10 +249,10 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 37276895));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 14, 37276925));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 914520, 37273600)); // mmap2
-int t3454f29 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE));
+int t3454f29 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(pread(t3454f29, buf, 14048, 0)); // mmap2
close(t3454f29);
-int t3455f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE));
+int t3455f18 = TEMP_FAILURE_RETRY(open("file1", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 0)); // mmap2
@@ -277,6 +279,7 @@
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 1048576, 0)); // mmap2
close(t3455f18);
t3455f18 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
+if (!checkpoint(52)) return -1;
TEMP_FAILURE_RETRY(read(t3455f18, buf, 4));
TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_SET));
TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_END));
@@ -397,7 +400,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 3513185));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 46, 3513215));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3262, 3510272)); // mmap2
-int t3455f19 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE));
+int t3455f19 = TEMP_FAILURE_RETRY(open("file12", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3455f19, buf, 1));
close(t3455f19);
t3455f19 = TEMP_FAILURE_RETRY(open("file13", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
@@ -415,9 +418,9 @@
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 13748, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4196, 12288)); // mmap2
close(t3455f18);
-int t3483f20 = TEMP_FAILURE_RETRY(open("file17", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3483f20 = TEMP_FAILURE_RETRY(open("file17", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 100, 0));
-int t3483f21 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3483f21 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3483f21, buf, 1, 0));
close(t3483f21);
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 0));
@@ -440,7 +443,7 @@
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 12288));
-int t3483f22 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3483f22 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3483f22, buf, 1, 0));
close(t3483f22);
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 16, 24));
@@ -467,9 +470,9 @@
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 49152));
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 139264));
TEMP_FAILURE_RETRY(pread(t3483f20, buf, 4096, 172032));
-int t3483f25 = TEMP_FAILURE_RETRY(open("file19", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3483f25 = TEMP_FAILURE_RETRY(open("file19", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 100, 0));
-int t3483f26 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3483f26 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3483f26, buf, 1, 0));
close(t3483f26);
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 0));
@@ -492,7 +495,7 @@
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 12288));
-int t3483f27 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3483f27 = TEMP_FAILURE_RETRY(open("file20", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3483f27, buf, 1, 0));
close(t3483f27);
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24));
@@ -533,6 +536,7 @@
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 69632));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 81920));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 90112));
+if (!checkpoint(55)) return -1;
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 102400));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 114688));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 131072));
@@ -541,16 +545,16 @@
TEMP_FAILURE_RETRY(pread(t3483f27, buf, 1, 0));
close(t3483f27);
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 16, 24));
-int t3498f30 = TEMP_FAILURE_RETRY(open("file21", O_RDONLY|O_LARGEFILE));
+int t3498f30 = TEMP_FAILURE_RETRY(open("file21", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3498f30, buf, 16384));
close(t3498f30);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 278721));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 19, 278751));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 25119, 278528)); // mmap2
-int t3499f30 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f30 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f30, buf, 1, 0));
close(t3499f30);
-int t3499f31 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
+int t3499f31 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4096, 516));
@@ -595,7 +599,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f30));
close(t3499f30);
-int t3500f30 = TEMP_FAILURE_RETRY(open("file23", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3500f30 = TEMP_FAILURE_RETRY(open("file23", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3500f30, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3500f30, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3500f30, buf, 27898, 0)); // mmap2
@@ -631,7 +635,7 @@
TEMP_FAILURE_RETRY(pread(t3500f30, buf, 1048576, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3500f30, buf, 122564, 3059712)); // mmap2
close(t3500f30);
-int t3502f30 = TEMP_FAILURE_RETRY(open("file29", O_RDONLY|O_LARGEFILE));
+int t3502f30 = TEMP_FAILURE_RETRY(open("file29", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3502f30, buf, 1));
TEMP_FAILURE_RETRY(read(t3502f30, buf, 4));
TEMP_FAILURE_RETRY(read(t3502f30, buf, 1));
@@ -776,6 +780,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2073, 32759808)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32273035));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 32273065));
+if (!checkpoint(58)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1692, 32272384)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34612102));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 38, 34612132));
@@ -802,7 +807,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f31, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f31));
-int t3499f32 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f32 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f32));
close(t3499f32);
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 12, 0));
@@ -837,9 +842,9 @@
TEMP_FAILURE_RETRY(pwrite(t3499f31, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f31));
close(t3499f31);
-int t3492f31 = TEMP_FAILURE_RETRY(open("file30", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3492f31 = TEMP_FAILURE_RETRY(open("file30", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 100, 0));
-int t3492f32 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f32 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f32, buf, 1, 0));
close(t3492f32);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 0));
@@ -865,7 +870,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1005, 35635200)); // mmap2
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 12288));
-int t3492f33 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f33 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f33, buf, 1, 0));
close(t3492f33);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
@@ -899,7 +904,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f30, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f30));
-int t3499f34 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f34 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f34));
close(t3499f34);
TEMP_FAILURE_RETRY(pwrite(t3499f30, buf, 12, 0));
@@ -1001,6 +1006,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 43, 35474168));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3682, 35471360)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34394223));
+if (!checkpoint(61)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 41, 34394253));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 481, 34394112)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32648704));
@@ -1034,19 +1040,19 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 36096678));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 29, 36096708));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3292, 36093952)); // mmap2
-int t3509f41 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE));
-int t3492f42 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3509f41 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE));
+int t3492f42 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f42, buf, 1, 0));
close(t3492f42);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 4096, 53248));
-int t3499f42 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f42 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f42, buf, 1, 0));
close(t3499f42);
TEMP_FAILURE_RETRY(read(t3509f41, buf, 8192));
TEMP_FAILURE_RETRY(read(t3509f41, buf, 8091));
close(t3509f41);
-int t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f41, buf, 1, 0));
close(t3499f41);
t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -1103,10 +1109,10 @@
t3499f41 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f41, buf, 1, 0));
close(t3499f41);
-int t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f40, buf, 1, 0));
close(t3499f40);
-int t3492f40 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f40 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f40, buf, 1, 0));
close(t3492f40);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
@@ -1192,7 +1198,7 @@
t3499f40 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f40, buf, 1, 0));
close(t3499f40);
-int t3492f41 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f41 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f41, buf, 1, 0));
close(t3492f41);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
@@ -1223,6 +1229,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12820));
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12824));
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 12828));
+if (!checkpoint(64)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f40, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f40));
@@ -1253,7 +1260,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f40, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f40));
-int t3508f42 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3508f42 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(lseek(t3508f42, 0, SEEK_END));
TEMP_FAILURE_RETRY(lseek(t3508f42, 38891199, SEEK_SET));
TEMP_FAILURE_RETRY(read(t3508f42, buf, 65557));
@@ -1265,7 +1272,7 @@
TEMP_FAILURE_RETRY(read(t3508f42, buf, 65557));
TEMP_FAILURE_RETRY(pread(t3508f42, buf, 769726, 38187008)); // mmap2
close(t3508f42);
-int t3499f43 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f43 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f43));
close(t3499f43);
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 12, 0));
@@ -1273,10 +1280,10 @@
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f40));
close(t3499f40);
-int t3508f40 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE));
+int t3508f40 = TEMP_FAILURE_RETRY(open("file16", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(pread(t3508f40, buf, 14048, 0)); // mmap2
close(t3508f40);
-int t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f33, buf, 1, 0));
close(t3499f33);
t3499f33 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -1295,7 +1302,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f33, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f33, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f33));
-int t3499f39 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f39 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f39));
close(t3499f39);
TEMP_FAILURE_RETRY(pwrite(t3499f33, buf, 12, 0));
@@ -1336,7 +1343,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35448800));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 31, 35448830));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2408, 35446784)); // mmap2
-int t3519f33 = TEMP_FAILURE_RETRY(open("file34", O_RDONLY|O_LARGEFILE));
+int t3519f33 = TEMP_FAILURE_RETRY(open("file34", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f33, buf, 1422));
TEMP_FAILURE_RETRY(read(t3519f33, buf, 1));
close(t3519f33);
@@ -1436,11 +1443,11 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29897692));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 34, 29897722));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1809, 29896704)); // mmap2
-int t3523f49 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE));
+int t3523f49 = TEMP_FAILURE_RETRY(open("file33", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3523f49, buf, 8192));
TEMP_FAILURE_RETRY(read(t3523f49, buf, 8091));
close(t3523f49);
-int t3455f50 = TEMP_FAILURE_RETRY(open("file7", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3455f50 = TEMP_FAILURE_RETRY(open("file7", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
close(t3455f50);
t3455f50 = TEMP_FAILURE_RETRY(open("file35", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 52, 0));
@@ -1452,6 +1459,7 @@
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 187587, 0)); // mmap2
+if (!checkpoint(67)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4128, 188416)); // mmap2
close(t3455f50);
t3455f50 = TEMP_FAILURE_RETRY(open("file24", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@@ -1471,7 +1479,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29922405));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 45, 29922435));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1962, 29921280)); // mmap2
-int t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f50, buf, 1, 0));
close(t3499f50);
t3499f50 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -1490,7 +1498,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f50, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f50, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f50));
-int t3499f52 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f52 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f52));
close(t3499f52);
TEMP_FAILURE_RETRY(pwrite(t3499f50, buf, 12, 0));
@@ -1534,7 +1542,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 33255456));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 43, 33255486));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 795, 33255424)); // mmap2
-int t3492f52 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f52 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f52, buf, 1, 0));
close(t3492f52);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
@@ -1594,8 +1602,8 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513539));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 35513569));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1673, 35512320)); // mmap2
-int t3526f50 = TEMP_FAILURE_RETRY(open("file39", O_RDONLY|O_LARGEFILE));
-int t3526f52 = TEMP_FAILURE_RETRY(open("file40", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3526f50 = TEMP_FAILURE_RETRY(open("file39", O_RDONLY|O_LARGEFILE));
+int t3526f52 = TEMP_FAILURE_RETRY(open("file40", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3526f52, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3526f52, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3526f52, buf, 1584, 0)); // mmap2
@@ -1619,7 +1627,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32575657));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 32575687));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 451, 32575488)); // mmap2
-int t3519f50 = TEMP_FAILURE_RETRY(open("file41", O_RDONLY|O_LARGEFILE));
+int t3519f50 = TEMP_FAILURE_RETRY(open("file41", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384));
TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384));
close(t3519f50);
@@ -1632,7 +1640,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29920348));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 42, 29920378));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 5221, 29917184)); // mmap2
-int t3527f50 = TEMP_FAILURE_RETRY(open("file42", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3527f50 = TEMP_FAILURE_RETRY(open("file42", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3527f50, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3527f50, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32567874));
@@ -1652,7 +1660,7 @@
TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384));
TEMP_FAILURE_RETRY(read(t3519f50, buf, 16384));
close(t3519f50);
-int t3492f50 = TEMP_FAILURE_RETRY(open("file44", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f50 = TEMP_FAILURE_RETRY(open("file44", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f50, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3492f50, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3492f50, buf, 10313, 0)); // mmap2
@@ -1666,23 +1674,23 @@
TEMP_FAILURE_RETRY(read(t3526f52, buf, 16384));
TEMP_FAILURE_RETRY(read(t3526f52, buf, 16384));
close(t3526f52);
-int t3532f53 = TEMP_FAILURE_RETRY(open("file47", O_RDONLY|O_LARGEFILE));
+int t3532f53 = TEMP_FAILURE_RETRY(open("file47", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384));
-int t3533f47 = TEMP_FAILURE_RETRY(open("file48", O_RDONLY|O_LARGEFILE));
+int t3533f47 = TEMP_FAILURE_RETRY(open("file48", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384));
close(t3532f53);
TEMP_FAILURE_RETRY(read(t3533f47, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f47, buf, 16384));
close(t3533f47);
-int t3519f43 = TEMP_FAILURE_RETRY(open("file49", O_RDONLY|O_LARGEFILE));
+int t3519f43 = TEMP_FAILURE_RETRY(open("file49", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f43, buf, 16384));
TEMP_FAILURE_RETRY(read(t3519f43, buf, 16384));
close(t3519f43);
-int t3532f43 = TEMP_FAILURE_RETRY(open("file50", O_RDONLY|O_LARGEFILE));
+int t3532f43 = TEMP_FAILURE_RETRY(open("file50", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3532f43, buf, 16384));
TEMP_FAILURE_RETRY(read(t3532f43, buf, 16384));
close(t3532f43);
-int t3533f43 = TEMP_FAILURE_RETRY(open("file51", O_RDONLY|O_LARGEFILE));
+int t3533f43 = TEMP_FAILURE_RETRY(open("file51", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3533f43, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f43, buf, 16384));
close(t3533f43);
@@ -1695,10 +1703,11 @@
TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384));
close(t3519f43);
close(t3532f53);
-int t3492f57 = TEMP_FAILURE_RETRY(open("file54", O_RDONLY|O_LARGEFILE));
+int t3492f57 = TEMP_FAILURE_RETRY(open("file54", O_RDONLY|O_LARGEFILE));
+if (!checkpoint(70)) return -1;
TEMP_FAILURE_RETRY(read(t3492f57, buf, 39938));
close(t3492f57);
-int t3492f61 = TEMP_FAILURE_RETRY(open("file55", O_RDONLY|O_LARGEFILE));
+int t3492f61 = TEMP_FAILURE_RETRY(open("file55", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3492f61, buf, 8192));
TEMP_FAILURE_RETRY(read(t3492f61, buf, 8192));
close(t3492f61);
@@ -1793,7 +1802,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 28977951));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 48, 28977981));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3292, 28975104)); // mmap2
-int t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f55, buf, 1, 0));
close(t3499f55);
t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -1812,7 +1821,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f55, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f55));
-int t3499f56 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f56 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f56));
close(t3499f56);
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 12, 0));
@@ -1820,14 +1829,14 @@
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f55));
close(t3499f55);
-int t3505f55 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f55 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f55, buf, 1, 0));
close(t3505f55);
-int t3519f55 = TEMP_FAILURE_RETRY(open("file57", O_RDONLY|O_LARGEFILE));
+int t3519f55 = TEMP_FAILURE_RETRY(open("file57", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f55, buf, 16384));
TEMP_FAILURE_RETRY(read(t3519f55, buf, 16384));
close(t3519f55);
-int t3532f55 = TEMP_FAILURE_RETRY(open("file58", O_RDONLY|O_LARGEFILE));
+int t3532f55 = TEMP_FAILURE_RETRY(open("file58", O_RDONLY|O_LARGEFILE));
t3499f56 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f56, buf, 1, 0));
close(t3499f56);
@@ -1835,7 +1844,7 @@
TEMP_FAILURE_RETRY(read(t3532f55, buf, 16384));
close(t3532f55);
t3499f55 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
-int t3505f56 = TEMP_FAILURE_RETRY(open("file59", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3505f56 = TEMP_FAILURE_RETRY(open("file59", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 516));
@@ -1848,7 +1857,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f55, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f55));
-int t3499f59 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f59 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f59));
close(t3499f59);
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 12, 0));
@@ -1856,11 +1865,11 @@
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f55));
close(t3499f55);
-int t3533f55 = TEMP_FAILURE_RETRY(open("file60", O_RDONLY|O_LARGEFILE));
+int t3533f55 = TEMP_FAILURE_RETRY(open("file60", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3533f55, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f55, buf, 16384));
close(t3533f55);
-int t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f58, buf, 1, 0));
close(t3499f58);
t3499f58 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -1928,6 +1937,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 516));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4612));
+if (!checkpoint(73)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4616));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 4620));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 8716));
@@ -2026,7 +2036,7 @@
TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 12824));
TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4096, 12828));
TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 16924));
-int t3499f62 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f62 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f62, buf, 1, 0));
close(t3499f62);
TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 4, 16928));
@@ -2048,7 +2058,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f62, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f62));
-int t3499f68 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f68 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f68));
close(t3499f68);
TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 12, 0));
@@ -2058,7 +2068,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f62));
close(t3499f62);
-int t3505f62 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f62 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3505f62));
close(t3505f62);
TEMP_FAILURE_RETRY(pwrite(t3505f56, buf, 12, 0));
@@ -2069,11 +2079,11 @@
t3505f56 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f56, buf, 1, 0));
close(t3505f56);
-int t3533f56 = TEMP_FAILURE_RETRY(open("file61", O_RDONLY|O_LARGEFILE));
+int t3533f56 = TEMP_FAILURE_RETRY(open("file61", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3533f56, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f56, buf, 16384));
close(t3533f56);
-int t3532f56 = TEMP_FAILURE_RETRY(open("file62", O_RDONLY|O_LARGEFILE));
+int t3532f56 = TEMP_FAILURE_RETRY(open("file62", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3532f56, buf, 16384));
TEMP_FAILURE_RETRY(read(t3532f56, buf, 16384));
close(t3532f56);
@@ -2130,7 +2140,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 29935078));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 50, 29935108));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1983, 29933568)); // mmap2
-int t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f66, buf, 1, 0));
close(t3499f66);
t3499f66 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2142,7 +2152,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4096, 4620));
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 8716));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 36467015));
-int t3532f68 = TEMP_FAILURE_RETRY(open("file64", O_RDONLY|O_LARGEFILE));
+int t3532f68 = TEMP_FAILURE_RETRY(open("file64", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 41, 36467045));
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 8720));
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4096, 8724));
@@ -2152,13 +2162,14 @@
TEMP_FAILURE_RETRY(fdatasync(t3499f66));
TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384));
TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384));
-int t3499f73 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f73 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(read(t3532f68, buf, 16384));
TEMP_FAILURE_RETRY(fdatasync(t3499f73));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34267550));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 34267580));
close(t3499f73);
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 12, 0));
+if (!checkpoint(76)) return -1;
close(t3532f68);
TEMP_FAILURE_RETRY(fdatasync(t3499f66));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 722, 34267136)); // mmap2
@@ -2180,11 +2191,11 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513539));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 35513569));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1673, 35512320)); // mmap2
-int t3532f61 = TEMP_FAILURE_RETRY(open("file65", O_RDONLY|O_LARGEFILE));
+int t3532f61 = TEMP_FAILURE_RETRY(open("file65", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3532f61, buf, 16384));
TEMP_FAILURE_RETRY(read(t3532f61, buf, 16384));
close(t3532f61);
-int t3533f61 = TEMP_FAILURE_RETRY(open("file66", O_RDONLY|O_LARGEFILE));
+int t3533f61 = TEMP_FAILURE_RETRY(open("file66", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384));
close(t3533f61);
@@ -2212,7 +2223,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f62, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f62));
-int t3499f61 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f61 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f61));
close(t3499f61);
TEMP_FAILURE_RETRY(pwrite(t3499f62, buf, 12, 0));
@@ -2228,11 +2239,11 @@
TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384));
TEMP_FAILURE_RETRY(read(t3533f61, buf, 16384));
close(t3533f61);
-int t3519f61 = TEMP_FAILURE_RETRY(open("file71", O_RDONLY|O_LARGEFILE));
+int t3519f61 = TEMP_FAILURE_RETRY(open("file71", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f61, buf, 16384));
TEMP_FAILURE_RETRY(read(t3519f61, buf, 16384));
close(t3519f61);
-int t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f80, buf, 1, 0));
close(t3499f80);
t3499f80 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2248,7 +2259,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f80, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f80, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f80));
-int t3499f81 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f81 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f81));
close(t3499f81);
TEMP_FAILURE_RETRY(pwrite(t3499f80, buf, 12, 0));
@@ -2283,7 +2294,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34957756));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 29, 34957786));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3273, 34955264)); // mmap2
-int t3519f68 = TEMP_FAILURE_RETRY(open("file72", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f68 = TEMP_FAILURE_RETRY(open("file72", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f68);
t3519f68 = TEMP_FAILURE_RETRY(open("file73", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f68);
@@ -2305,7 +2316,7 @@
close(t3519f68);
t3519f68 = TEMP_FAILURE_RETRY(open("file82", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f68);
-int t3519f70 = TEMP_FAILURE_RETRY(open("file83", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f70 = TEMP_FAILURE_RETRY(open("file83", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f70);
t3519f68 = TEMP_FAILURE_RETRY(open("file84", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f68);
@@ -2330,12 +2341,12 @@
t3519f70 = TEMP_FAILURE_RETRY(open("file94", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f70);
t3519f70 = TEMP_FAILURE_RETRY(open("file95", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
-int t3492f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f72, buf, 1, 0));
close(t3492f72);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
close(t3519f70);
-int t3492f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3492f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3492f70, buf, 1, 0));
close(t3492f70);
TEMP_FAILURE_RETRY(pread(t3492f31, buf, 16, 24));
@@ -2367,15 +2378,15 @@
close(t3519f68);
t3519f68 = TEMP_FAILURE_RETRY(open("file109", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f68);
-int t3519f72 = TEMP_FAILURE_RETRY(open("file110", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f72 = TEMP_FAILURE_RETRY(open("file110", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f72);
-int t3519f80 = TEMP_FAILURE_RETRY(open("file111", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f80 = TEMP_FAILURE_RETRY(open("file111", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f80);
-int t3519f81 = TEMP_FAILURE_RETRY(open("file112", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f81 = TEMP_FAILURE_RETRY(open("file112", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f81);
t3519f81 = TEMP_FAILURE_RETRY(open("file113", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f81);
-int t3519f76 = TEMP_FAILURE_RETRY(open("file114", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f76 = TEMP_FAILURE_RETRY(open("file114", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f76);
t3519f70 = TEMP_FAILURE_RETRY(open("file115", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f70);
@@ -2383,7 +2394,7 @@
close(t3519f70);
t3519f70 = TEMP_FAILURE_RETRY(open("file117", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f70);
-int t3519f67 = TEMP_FAILURE_RETRY(open("file118", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3519f67 = TEMP_FAILURE_RETRY(open("file118", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file119", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
@@ -2396,6 +2407,7 @@
t3519f67 = TEMP_FAILURE_RETRY(open("file123", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file124", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+if (!checkpoint(79)) return -1;
close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file125", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
@@ -2405,8 +2417,8 @@
close(t3519f67);
t3519f70 = TEMP_FAILURE_RETRY(open("file128", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3519f70);
-int t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
-int t3519f75 = TEMP_FAILURE_RETRY(open("file128", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3519f75 = TEMP_FAILURE_RETRY(open("file128", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
close(t3526f70);
t3526f70 = TEMP_FAILURE_RETRY(open("file129", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3519f75, buf, 2991));
@@ -2415,7 +2427,7 @@
close(t3526f70);
t3519f67 = TEMP_FAILURE_RETRY(open("file130", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3519f67, buf, 16384));
-int t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f72, buf, 1, 0));
close(t3499f72);
TEMP_FAILURE_RETRY(read(t3519f67, buf, 16384));
@@ -2433,7 +2445,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f72, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f72));
-int t3499f67 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f67 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f67));
close(t3499f67);
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 12, 0));
@@ -2446,7 +2458,7 @@
t3526f70 = TEMP_FAILURE_RETRY(open("file131", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f70, buf, 4622));
close(t3526f70);
-int t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f72);
t3526f72 = TEMP_FAILURE_RETRY(open("file132", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f72, buf, 16384));
@@ -2454,10 +2466,10 @@
close(t3526f72);
t3526f70 = TEMP_FAILURE_RETRY(open("file133", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f70);
-int t3526f75 = TEMP_FAILURE_RETRY(open("file133", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3526f75 = TEMP_FAILURE_RETRY(open("file133", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f75, buf, 13332));
close(t3526f75);
-int t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3495f70, buf, 1, 0));
close(t3495f70);
t3495f70 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2473,7 +2485,7 @@
TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3495f70, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3495f70));
-int t3495f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3495f75));
close(t3495f75);
TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 12, 0));
@@ -2481,9 +2493,9 @@
TEMP_FAILURE_RETRY(pwrite(t3495f70, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3495f70));
close(t3495f70);
-int t3526f93 = TEMP_FAILURE_RETRY(open("file134", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f93 = TEMP_FAILURE_RETRY(open("file134", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f93);
-int t3526f88 = TEMP_FAILURE_RETRY(open("file134", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3526f88 = TEMP_FAILURE_RETRY(open("file134", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f88, buf, 15056));
close(t3526f88);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34433108));
@@ -2511,7 +2523,7 @@
TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3495f75, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3495f75));
-int t3495f86 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f86 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3495f86));
close(t3495f86);
TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 12, 0));
@@ -2519,7 +2531,7 @@
TEMP_FAILURE_RETRY(pwrite(t3495f75, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3495f75));
close(t3495f75);
-int t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f74, buf, 1, 0));
close(t3499f74);
t3499f74 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2535,7 +2547,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f74, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f74));
-int t3499f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f75 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f75));
close(t3499f75);
TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 12, 0));
@@ -2543,18 +2555,18 @@
TEMP_FAILURE_RETRY(pwrite(t3499f74, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f74));
close(t3499f74);
-int t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f64);
t3526f64 = TEMP_FAILURE_RETRY(open("file135", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f64, buf, 16384));
TEMP_FAILURE_RETRY(write(t3526f64, buf, 4873));
close(t3526f64);
-int t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file136", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f90, buf, 4199));
close(t3526f90);
-int t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0));
close(t3499f90);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35511105));
@@ -2579,7 +2591,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f90));
-int t3499f92 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f92 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f92));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35513993));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 34, 35514023));
@@ -2620,6 +2632,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f90));
close(t3499f90);
+if (!checkpoint(82)) return -1;
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0));
close(t3499f90);
@@ -2644,17 +2657,17 @@
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f90));
close(t3499f90);
-int t3495f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f72 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3495f72, buf, 1, 0));
close(t3495f72);
-int t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f84, buf, 1, 0));
close(t3499f84);
t3499f72 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4096, 516));
-int t3495f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
+int t3495f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 4612));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4, 4616));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 4096, 4620));
@@ -2667,7 +2680,7 @@
TEMP_FAILURE_RETRY(pread(t3499f72, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f72));
TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4096, 516));
-int t3499f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f88));
TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4, 4612));
TEMP_FAILURE_RETRY(pwrite(t3495f84, buf, 4, 4616));
@@ -2683,7 +2696,7 @@
TEMP_FAILURE_RETRY(fdatasync(t3495f84));
TEMP_FAILURE_RETRY(pwrite(t3499f72, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f72));
-int t3495f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f88 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 31156572));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 58, 31156602));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3099, 31154176)); // mmap2
@@ -2698,7 +2711,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34907552));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 39, 34907582));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2551, 34906112)); // mmap2
-int t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3495f66, buf, 1, 0));
close(t3495f66);
t3495f66 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2738,7 +2751,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f66, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f66));
-int t3499f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f70));
close(t3499f70);
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 12, 0));
@@ -2746,11 +2759,11 @@
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f66));
close(t3499f66);
-int t3526f66 = TEMP_FAILURE_RETRY(open("file137", O_RDONLY|O_LARGEFILE));
+int t3526f66 = TEMP_FAILURE_RETRY(open("file137", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3526f66, buf, 16384));
TEMP_FAILURE_RETRY(read(t3526f66, buf, 16384));
close(t3526f66);
-int t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f66, buf, 1, 0));
close(t3505f66);
t3505f66 = TEMP_FAILURE_RETRY(open("file138", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
@@ -2786,7 +2799,7 @@
TEMP_FAILURE_RETRY(fdatasync(t3495f70));
close(t3495f70);
TEMP_FAILURE_RETRY(write(t3505f66, buf, 10592));
-int t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f70);
t3533f70 = TEMP_FAILURE_RETRY(open("file140", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3533f70, buf, 4042));
@@ -2796,7 +2809,7 @@
t3533f70 = TEMP_FAILURE_RETRY(open("file141", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f70);
t3526f70 = TEMP_FAILURE_RETRY(open("file142", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
-int t3533f72 = TEMP_FAILURE_RETRY(open("file141", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3533f72 = TEMP_FAILURE_RETRY(open("file141", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
close(t3526f70);
t3526f70 = TEMP_FAILURE_RETRY(open("file142", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f70, buf, 5057));
@@ -2838,6 +2851,7 @@
close(t3505f66);
t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 512, 0));
+if (!checkpoint(85)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4096, 516));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 4612));
@@ -2858,7 +2872,7 @@
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 25132));
TEMP_FAILURE_RETRY(pread(t3505f66, buf, 8, 25600));
TEMP_FAILURE_RETRY(fdatasync(t3505f66));
-int t3505f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f70 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3505f70));
close(t3505f70);
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 12, 0));
@@ -2923,7 +2937,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34261624));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 34261654));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2993, 34258944)); // mmap2
-int t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f91);
t3533f91 = TEMP_FAILURE_RETRY(open("file143", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 31210525));
@@ -2932,7 +2946,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3673, 31207424)); // mmap2
TEMP_FAILURE_RETRY(write(t3533f91, buf, 2024));
close(t3533f91);
-int t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f91, buf, 1, 0));
close(t3499f91);
t3499f91 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2948,7 +2962,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f91, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f91));
-int t3499f93 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f93 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f93));
close(t3499f93);
TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 12, 0));
@@ -2956,7 +2970,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f91, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f91));
close(t3499f91);
-int t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f84, buf, 1, 0));
close(t3505f84);
t3505f84 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -2972,7 +2986,7 @@
TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3505f84, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3505f84));
-int t3505f90 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f90 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3505f90));
close(t3505f90);
TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 12, 0));
@@ -2980,41 +2994,41 @@
TEMP_FAILURE_RETRY(pwrite(t3505f84, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3505f84));
close(t3505f84);
-int t3533f102 = TEMP_FAILURE_RETRY(open("file144", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f102 = TEMP_FAILURE_RETRY(open("file144", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f102);
t3533f72 = TEMP_FAILURE_RETRY(open("file144", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3533f72, buf, 5550));
close(t3533f72);
-int t3526f84 = TEMP_FAILURE_RETRY(open("file145", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f84 = TEMP_FAILURE_RETRY(open("file145", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f84);
-int t3526f101 = TEMP_FAILURE_RETRY(open("file145", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3526f101 = TEMP_FAILURE_RETRY(open("file145", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f101, buf, 3612));
close(t3526f101);
t3526f90 = TEMP_FAILURE_RETRY(open("file146", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file146", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f90, buf, 5414));
-int t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f96);
t3533f96 = TEMP_FAILURE_RETRY(open("file147", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
close(t3526f90);
TEMP_FAILURE_RETRY(write(t3533f96, buf, 3834));
close(t3533f96);
-int t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3519f90);
t3519f90 = TEMP_FAILURE_RETRY(open("file148", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3519f90, buf, 3461));
-int t3526f96 = TEMP_FAILURE_RETRY(open("file149", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3526f96 = TEMP_FAILURE_RETRY(open("file149", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3526f96);
close(t3519f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file149", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
TEMP_FAILURE_RETRY(write(t3526f90, buf, 16384));
TEMP_FAILURE_RETRY(write(t3526f90, buf, 12766));
close(t3526f90);
-int t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f90);
t3533f90 = TEMP_FAILURE_RETRY(open("file150", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
-int t3505f96 = TEMP_FAILURE_RETRY(open("file151", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3505f96 = TEMP_FAILURE_RETRY(open("file151", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3505f96, buf, 100, 0));
TEMP_FAILURE_RETRY(write(t3533f90, buf, 10056));
close(t3533f90);
@@ -3036,7 +3050,7 @@
close(t3505f90);
TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24));
t3505f90 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
-int t3533f99 = TEMP_FAILURE_RETRY(open("file153", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
+int t3533f99 = TEMP_FAILURE_RETRY(open("file153", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600));
close(t3533f99);
TEMP_FAILURE_RETRY(pread(t3505f90, buf, 1, 0));
close(t3505f90);
@@ -3046,7 +3060,7 @@
close(t3533f90);
TEMP_FAILURE_RETRY(pread(t3505f96, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3505f96, buf, 4096, 12288));
-int t3505f99 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f99 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f99, buf, 1, 0));
close(t3505f99);
TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24));
@@ -3066,6 +3080,7 @@
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0));
close(t3499f90);
+if (!checkpoint(88)) return -1;
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 512));
@@ -3079,7 +3094,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f90));
-int t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f97));
close(t3499f97);
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 12, 0));
@@ -3114,7 +3129,7 @@
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34438470));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 63, 34438500));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3681, 34435072)); // mmap2
-int t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3576f95, buf, 1, 0));
close(t3576f95);
t3499f92 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@@ -3136,7 +3151,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f92, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f92));
-int t3499f95 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f95 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f95));
close(t3499f95);
TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 12, 0));
@@ -3174,7 +3189,7 @@
t3576f95 = TEMP_FAILURE_RETRY(open("file152", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3576f95, buf, 1, 0));
close(t3576f95);
-int t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f100, buf, 1, 0));
close(t3499f100);
t3499f100 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -3190,7 +3205,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f100, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f100));
-int t3499f106 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f106 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f106));
close(t3499f106);
TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 12, 0));
@@ -3217,7 +3232,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f100, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f100));
-int t3499f105 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f105 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f105));
close(t3499f105);
TEMP_FAILURE_RETRY(pwrite(t3499f100, buf, 12, 0));
@@ -3278,11 +3293,12 @@
close(t3499f100);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35636928));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 60, 35636958));
+if (!checkpoint(91)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2062, 35635200)); // mmap2
t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f84, buf, 1, 0));
close(t3499f84);
-int t3499f27 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
+int t3499f27 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f27, buf, 4096, 516));
@@ -3360,9 +3376,9 @@
TEMP_FAILURE_RETRY(pwrite(t3499f92, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f92));
close(t3499f92);
-int t3545f92 = TEMP_FAILURE_RETRY(open("file154", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3545f92 = TEMP_FAILURE_RETRY(open("file154", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 100, 0));
-int t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f97, buf, 1, 0));
close(t3545f97);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 4096, 0));
@@ -3392,7 +3408,7 @@
TEMP_FAILURE_RETRY(read(t3545f97, buf, 8));
TEMP_FAILURE_RETRY(read(t3545f97, buf, 1));
close(t3545f97);
-int t3545f100 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f100 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f100, buf, 1, 0));
close(t3545f100);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
@@ -3427,11 +3443,11 @@
TEMP_FAILURE_RETRY(pwrite(t3545f97, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f97));
close(t3545f97);
-int t3545f104 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f104 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f104, buf, 1, 0));
close(t3545f104);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
-int t3545f29 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f29 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f29, buf, 1, 0));
close(t3545f29);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
@@ -3460,7 +3476,7 @@
TEMP_FAILURE_RETRY(pwrite(t3545f97, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f97));
close(t3545f97);
-int t3575f29 = TEMP_FAILURE_RETRY(open("file16", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0));
+int t3575f29 = TEMP_FAILURE_RETRY(open("file16", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0));
TEMP_FAILURE_RETRY(write(t3575f29, buf, 17344));
close(t3575f29);
t3545f97 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@@ -3496,7 +3512,7 @@
TEMP_FAILURE_RETRY(pwrite(t3545f29, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f29));
close(t3545f29);
-int t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f26, buf, 1, 0));
close(t3499f26);
t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -3514,6 +3530,7 @@
TEMP_FAILURE_RETRY(fdatasync(t3499f26));
t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f97));
+if (!checkpoint(93)) return -1;
close(t3499f97);
TEMP_FAILURE_RETRY(pwrite(t3499f26, buf, 12, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f26));
@@ -3523,7 +3540,7 @@
t3499f26 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f26, buf, 1, 0));
close(t3499f26);
-int t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
+int t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 4096, 516));
@@ -3548,7 +3565,7 @@
TEMP_FAILURE_RETRY(pread(t3545f97, buf, 1, 0));
close(t3545f97);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
-int t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f90, buf, 1, 0));
close(t3545f90);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
@@ -3594,13 +3611,13 @@
TEMP_FAILURE_RETRY(pwrite(t3545f29, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f29));
close(t3545f29);
-int t3545f84 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f84 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f84, buf, 1, 0));
close(t3545f84);
TEMP_FAILURE_RETRY(pread(t3545f92, buf, 16, 24));
-int t3584f84 = TEMP_FAILURE_RETRY(open("file157", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3584f84 = TEMP_FAILURE_RETRY(open("file157", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 100, 0));
-int t3584f90 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3584f90 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3584f90, buf, 1, 0));
close(t3584f90);
t3545f90 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@@ -3619,13 +3636,13 @@
TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4, 8720));
TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4096, 8724));
TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 4, 12820));
-int t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f90, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3545f90));
TEMP_FAILURE_RETRY(pread(t3584f99, buf, 1, 0));
close(t3584f99);
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24));
-int t3545f99 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f99 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3545f99));
close(t3545f99);
TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 12, 0));
@@ -3637,16 +3654,16 @@
TEMP_FAILURE_RETRY(pwrite(t3545f90, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f90));
close(t3545f90);
-int t3584f29 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3584f29 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3584f29, buf, 1, 0));
close(t3584f29);
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 4096, 8192));
-int t3584f27 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3584f27 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3584f27, buf, 1, 0));
close(t3584f27);
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24));
-int t3545f95 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3545f95 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
t3584f99 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3545f95, buf, 1, 0));
TEMP_FAILURE_RETRY(pread(t3584f99, buf, 1, 0));
@@ -3665,7 +3682,7 @@
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 4616));
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4096, 4620));
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 8716));
-int t3584f95 = TEMP_FAILURE_RETRY(open("file159", O_RDONLY|O_LARGEFILE));
+int t3584f95 = TEMP_FAILURE_RETRY(open("file159", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3584f95, buf, 8));
TEMP_FAILURE_RETRY(read(t3584f95, buf, 1));
close(t3584f95);
@@ -3679,7 +3696,7 @@
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 16928));
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4096, 16932));
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 4, 21028));
-int t3584f101 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3584f101 = TEMP_FAILURE_RETRY(open("file158", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3584f101, buf, 1, 0));
close(t3584f101);
TEMP_FAILURE_RETRY(pread(t3584f84, buf, 16, 24));
@@ -3722,7 +3739,7 @@
TEMP_FAILURE_RETRY(pwrite(t3545f99, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3545f99));
close(t3545f99);
-int t3581f99 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3581f99 = TEMP_FAILURE_RETRY(open("file155", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3581f99, buf, 1, 0));
close(t3581f99);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34970937));
@@ -3760,6 +3777,7 @@
t3526f90 = TEMP_FAILURE_RETRY(open("file162", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
+if (!checkpoint(96)) return -1;
close(t3526f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file163", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
@@ -3773,20 +3791,20 @@
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
close(t3526f90);
-int t3586f102 = TEMP_FAILURE_RETRY(open("file166", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3586f102 = TEMP_FAILURE_RETRY(open("file166", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3586f102);
-int t3586f97 = TEMP_FAILURE_RETRY(open("file167", O_RDONLY|O_LARGEFILE));
+int t3586f97 = TEMP_FAILURE_RETRY(open("file167", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3586f97, buf, 8192));
TEMP_FAILURE_RETRY(read(t3586f97, buf, 8192));
close(t3586f97);
-int t3587f95 = TEMP_FAILURE_RETRY(open("file168", O_RDONLY|O_LARGEFILE));
+int t3587f95 = TEMP_FAILURE_RETRY(open("file168", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3587f95, buf, 16384));
close(t3587f95);
t3499f28 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f28, buf, 1, 0));
close(t3499f28);
-int t3496f28 = TEMP_FAILURE_RETRY(open("file169", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
-int t3499f103 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
+int t3496f28 = TEMP_FAILURE_RETRY(open("file169", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600));
+int t3499f103 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f103, buf, 4096, 516));
@@ -3835,9 +3853,9 @@
TEMP_FAILURE_RETRY(pwrite(t3499f28, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f28));
close(t3499f28);
-int t3541f103 = TEMP_FAILURE_RETRY(open("file170", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3541f103 = TEMP_FAILURE_RETRY(open("file170", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3541f103, buf, 100, 0));
-int t3541f105 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3541f105 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3541f105, buf, 1, 0));
close(t3541f105);
TEMP_FAILURE_RETRY(pread(t3541f103, buf, 4096, 0));
@@ -3864,12 +3882,12 @@
TEMP_FAILURE_RETRY(read(t3541f105, buf, 8));
TEMP_FAILURE_RETRY(read(t3541f105, buf, 1));
close(t3541f105);
-int t3541f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3541f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3541f106, buf, 1, 0));
close(t3541f106);
TEMP_FAILURE_RETRY(pread(t3541f103, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3541f103, buf, 4096, 20480));
-int t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f107, buf, 1, 0));
close(t3499f107);
t3499f107 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
@@ -3885,7 +3903,7 @@
TEMP_FAILURE_RETRY(pwrite(t3499f107, buf, 4, 12820));
TEMP_FAILURE_RETRY(pread(t3499f107, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f107));
-int t3499f108 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3499f108 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f108));
close(t3499f108);
TEMP_FAILURE_RETRY(pwrite(t3499f107, buf, 12, 0));
@@ -3917,16 +3935,16 @@
TEMP_FAILURE_RETRY(pwrite(t3499f105, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f105));
close(t3499f105);
-int t3505f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3505f106 = TEMP_FAILURE_RETRY(open("file171", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3505f106, buf, 1, 0));
close(t3505f106);
-int t3540f107 = TEMP_FAILURE_RETRY(open("file173", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3540f107 = TEMP_FAILURE_RETRY(open("file173", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3540f107, buf, 100, 0));
-int t3540f108 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3540f108 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3540f108, buf, 1, 0));
close(t3540f108);
TEMP_FAILURE_RETRY(pread(t3540f107, buf, 4096, 0));
-int t3540f105 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3540f105 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3540f105, buf, 1, 0));
close(t3540f105);
TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24));
@@ -3949,7 +3967,7 @@
TEMP_FAILURE_RETRY(read(t3540f105, buf, 8));
TEMP_FAILURE_RETRY(read(t3540f105, buf, 1));
close(t3540f105);
-int t3540f106 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3540f106 = TEMP_FAILURE_RETRY(open("file174", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3540f106, buf, 1, 0));
close(t3540f106);
TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24));
@@ -3963,14 +3981,14 @@
TEMP_FAILURE_RETRY(pread(t3540f106, buf, 1, 0));
close(t3540f106);
TEMP_FAILURE_RETRY(pread(t3540f107, buf, 16, 24));
-int t3496f105 = TEMP_FAILURE_RETRY(open("file176", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
+int t3496f105 = TEMP_FAILURE_RETRY(open("file176", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3496f105);
t3499f108 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f108, buf, 1, 0));
close(t3499f108);
-int t3597f108 = TEMP_FAILURE_RETRY(open("file177", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
+int t3597f108 = TEMP_FAILURE_RETRY(open("file177", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0600));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 100, 0));
-int t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0));
close(t3597f109);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 0));
@@ -3987,27 +4005,28 @@
TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0));
close(t3597f109);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24));
-int t3540f109 = TEMP_FAILURE_RETRY(open("file179", O_RDONLY|O_LARGEFILE));
+int t3540f109 = TEMP_FAILURE_RETRY(open("file179", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3540f109, buf, 4000));
-int t3597f110 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3597f110 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3597f110, buf, 1, 0));
close(t3597f110);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24));
close(t3540f109);
+if (!checkpoint(99)) return -1;
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 12288));
t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3597f109, buf, 1, 0));
close(t3597f109);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24));
-int t3597f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3597f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3597f111, buf, 1, 0));
close(t3597f111);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 24576));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 20480));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 57344));
-int t3598f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
+int t3598f111 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3598f111, buf, 1, 0));
close(t3598f111);
close(t3540f107);
@@ -4054,7 +4073,7 @@
return OK;
}
-static status_t BenchmarkCreate() {
+static status_t BenchmarkCreate(std::function<bool(int)> checkpoint) {
status_t res = 0;
res |= CreateFile("stub", 0);
@@ -4069,6 +4088,7 @@
res |= CreateFile("file76", 0);
res |= CreateFile("file140", 4042);
res |= CreateFile("file80", 0);
+if (!checkpoint(3)) return -1;
res |= CreateFile("file139", 49152);
res |= CreateFile("file50", 32768);
res |= CreateFile("file179", 4000);
@@ -4081,6 +4101,7 @@
res |= CreateFile("file72", 0);
res |= CreateFile("file55", 16384);
res |= CreateFile("file54", 39938);
+if (!checkpoint(6)) return -1;
res |= CreateFile("file129", 3974);
res |= CreateFile("file107", 0);
res |= CreateFile("file95", 0);
@@ -4093,6 +4114,7 @@
res |= CreateFile("file40", 4172);
res |= CreateFile("file20", 1);
res |= CreateFile("file151", 499712);
+if (!checkpoint(10)) return -1;
res |= CreateFile("file106", 0);
res |= CreateFile("file159", 9);
res |= CreateFile("file47", 32768);
@@ -4105,6 +4127,7 @@
res |= CreateFile("file148", 3461);
res |= CreateFile("file7", 794976);
res |= CreateFile("file68", 32768);
+if (!checkpoint(13)) return -1;
res |= CreateFile("file109", 0);
res |= CreateFile("file142", 5057);
res |= CreateFile("file147", 3834);
@@ -4117,6 +4140,7 @@
res |= CreateFile("file79", 0);
res |= CreateFile("file65", 32768);
res |= CreateFile("file135", 21257);
+if (!checkpoint(16)) return -1;
res |= CreateFile("file124", 0);
res |= CreateFile("file87", 0);
res |= CreateFile("file64", 49152);
@@ -4129,6 +4153,7 @@
res |= CreateFile("file163", 32768);
res |= CreateFile("file67", 32768);
res |= CreateFile("file155", 21512);
+if (!checkpoint(20)) return -1;
res |= CreateFile("file156", 9);
res |= CreateFile("file23", 28700);
res |= CreateFile("file61", 32768);
@@ -4141,6 +4166,7 @@
res |= CreateFile("file57", 32768);
res |= CreateFile("file104", 0);
res |= CreateFile("file113", 0);
+if (!checkpoint(23)) return -1;
res |= CreateFile("file99", 0);
res |= CreateFile("file120", 0);
res |= CreateFile("file154", 73728);
@@ -4153,6 +4179,7 @@
res |= CreateFile("file91", 0);
res |= CreateFile("file158", 1);
res |= CreateFile("file174", 1);
+if (!checkpoint(26)) return -1;
res |= CreateFile("file48", 32768);
res |= CreateFile("file33", 32566);
res |= CreateFile("file83", 0);
@@ -4165,6 +4192,7 @@
res |= CreateFile("file164", 32768);
res |= CreateFile("file36", 192544);
res |= CreateFile("file6", 4636);
+if (!checkpoint(30)) return -1;
res |= CreateFile("file10", 16484);
res |= CreateFile("file150", 10056);
res |= CreateFile("file62", 32768);
@@ -4177,6 +4205,7 @@
res |= CreateFile("file103", 0);
res |= CreateFile("file26", 28676);
res |= CreateFile("file46", 32768);
+if (!checkpoint(33)) return -1;
res |= CreateFile("file60", 32768);
res |= CreateFile("file162", 32768);
res |= CreateFile("file25", 32872);
@@ -4189,6 +4218,7 @@
res |= CreateFile("file37", 159752);
res |= CreateFile("file73", 0);
res |= CreateFile("file71", 32768);
+if (!checkpoint(36)) return -1;
res |= CreateFile("file98", 0);
res |= CreateFile("file74", 0);
res |= CreateFile("file93", 0);
@@ -4201,6 +4231,7 @@
res |= CreateFile("file132", 23233);
res |= CreateFile("file92", 0);
res |= CreateFile("file11", 0);
+if (!checkpoint(40)) return -1;
res |= CreateFile("file86", 0);
res |= CreateFile("file22", 0);
res |= CreateFile("file56", 16384);
@@ -4213,6 +4244,7 @@
res |= CreateFile("file116", 0);
res |= CreateFile("file29", 1035);
res |= CreateFile("file35", 118788);
+if (!checkpoint(43)) return -1;
res |= CreateFile("file170", 24576);
res |= CreateFile("file30", 98304);
res |= CreateFile("file14", 0);
@@ -4225,6 +4257,7 @@
res |= CreateFile("file134", 15056);
res |= CreateFile("file31", 25608);
res |= CreateFile("file97", 0);
+if (!checkpoint(46)) return -1;
res |= CreateFile("file84", 0);
res |= CreateFile("file114", 0);
res |= CreateFile("file88", 0);
@@ -4237,6 +4270,7 @@
res |= CreateFile("file169", 11354);
res |= CreateFile("file166", 0);
res |= CreateFile("file49", 32768);
+if (!checkpoint(50)) return -1;
res |= CreateFile("file177", 61440);
return res;
diff --git a/CheckEncryption.cpp b/CheckEncryption.cpp
new file mode 100644
index 0000000..ffa3698
--- /dev/null
+++ b/CheckEncryption.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 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 "CheckEncryption.h"
+#include "FileDeviceUtils.h"
+#include "Utils.h"
+#include "VolumeManager.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/iosched_policy.h>
+#include <private/android_filesystem_config.h>
+
+#include <sstream>
+
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using android::base::unique_fd;
+
+using android::base::ReadFileToString;
+using android::base::WriteStringToFile;
+
+namespace android {
+namespace vold {
+
+constexpr uint32_t max_extents = 32;
+constexpr size_t bytecount = 8;
+constexpr int repeats = 256;
+
+bool check_file(const std::string& needle) {
+ LOG(DEBUG) << "checkEncryption check_file: " << needle;
+ auto haystack = android::vold::BlockDeviceForPath(needle);
+ if (haystack.empty()) {
+ LOG(ERROR) << "Failed to find device for path: " << needle;
+ return false;
+ }
+
+ std::string randombytes;
+ if (ReadRandomBytes(bytecount, randombytes) != 0) {
+ LOG(ERROR) << "Failed to read random bytes";
+ return false;
+ }
+ std::string randomhex;
+ StrToHex(randombytes, randomhex);
+ std::ostringstream os;
+ for (int i = 0; i < repeats; i++) os << randomhex;
+ auto towrite = os.str();
+
+ if (access(needle.c_str(), F_OK) == 0) {
+ if (unlink(needle.c_str()) != 0) {
+ PLOG(ERROR) << "Failed to unlink " << needle;
+ return false;
+ }
+ }
+ LOG(DEBUG) << "Writing to " << needle;
+ if (!WriteStringToFile(towrite, needle)) {
+ PLOG(ERROR) << "Failed to write " << needle;
+ return false;
+ }
+ sync();
+
+ unique_fd haystack_fd(open(haystack.c_str(), O_RDONLY | O_CLOEXEC));
+ if (haystack_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open " << haystack;
+ return false;
+ }
+
+ auto fiemap = PathFiemap(needle, max_extents);
+
+ std::string area;
+ for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++) {
+ auto xt = &(fiemap->fm_extents[i]);
+ LOG(DEBUG) << "Extent " << i << " at " << xt->fe_physical << " length " << xt->fe_length;
+ if (lseek64(haystack_fd.get(), xt->fe_physical, SEEK_SET) == -1) {
+ PLOG(ERROR) << "Failed lseek";
+ return false;
+ }
+ auto toread = xt->fe_length;
+ while (toread > 0) {
+ char buf[BUFSIZ];
+ size_t wlen =
+ static_cast<size_t>(std::min(static_cast<typeof(toread)>(sizeof(buf)), toread));
+ auto l = read(haystack_fd.get(), buf, wlen);
+ if (l < 1) {
+ PLOG(ERROR) << "Failed read";
+ if (errno != EINTR) {
+ return false;
+ }
+ }
+ area.append(buf, l);
+ toread -= l;
+ }
+ }
+
+ LOG(DEBUG) << "Searching " << area.size() << " bytes of " << needle;
+ LOG(DEBUG) << "First position of blob: " << area.find(randomhex);
+ return true;
+}
+
+int CheckEncryption(const std::string& path) {
+ auto deNeedle(path);
+ deNeedle += "/misc";
+ if (android::vold::PrepareDir(deNeedle, 01771, AID_SYSTEM, AID_MISC)) {
+ return -1;
+ }
+ deNeedle += "/vold";
+ if (android::vold::PrepareDir(deNeedle, 0700, AID_ROOT, AID_ROOT)) {
+ return -1;
+ }
+ deNeedle += "/checkEncryption";
+
+ auto neNeedle(path);
+ neNeedle += "/unencrypted/checkEncryption";
+
+ check_file(deNeedle);
+ check_file(neNeedle);
+
+ return 0;
+}
+
+} // namespace vold
+} // namespace android
diff --git a/VoldCommand.h b/CheckEncryption.h
similarity index 62%
copy from VoldCommand.h
copy to CheckEncryption.h
index e435159..158d886 100644
--- a/VoldCommand.h
+++ b/CheckEncryption.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#ifndef _VOLD_COMMAND_H
-#define _VOLD_COMMAND_H
+#ifndef ANDROID_VOLD_CHECK_ENCRYPTION_H
+#define ANDROID_VOLD_CHECK_ENCRYPTION_H
-#include <sysutils/FrameworkCommand.h>
+#include <string>
-class VoldCommand : public FrameworkCommand {
-public:
- explicit VoldCommand(const char *cmd);
- virtual ~VoldCommand() {}
-};
+namespace android {
+namespace vold {
+
+/* Check encryption of private volume mounted at the given path */
+int CheckEncryption(const std::string& path);
+
+} // namespace vold
+} // namespace android
#endif
diff --git a/CommandListener.cpp b/CommandListener.cpp
deleted file mode 100644
index 8da3f69..0000000
--- a/CommandListener.cpp
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * 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 <stdlib.h>
-#include <sys/mount.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fs_mgr.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#define LOG_TAG "VoldCmdListener"
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-
-#include <sysutils/SocketClient.h>
-#include <private/android_filesystem_config.h>
-
-#include "CommandListener.h"
-#include "VolumeManager.h"
-#include "VolumeBase.h"
-#include "ResponseCode.h"
-#include "Process.h"
-#include "Loop.h"
-#include "Devmapper.h"
-#include "MoveTask.h"
-#include "TrimTask.h"
-
-#define DUMP_ARGS 0
-#define DEBUG_APPFUSE 0
-
-using android::base::unique_fd;
-
-CommandListener::CommandListener() :
- FrameworkListener("vold", true) {
- registerCmd(new DumpCmd());
- registerCmd(new VolumeCmd());
- registerCmd(new AsecCmd());
- registerCmd(new ObbCmd());
- registerCmd(new StorageCmd());
- registerCmd(new FstrimCmd());
- registerCmd(new AppFuseCmd());
-}
-
-#if DUMP_ARGS
-void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
- char buffer[4096];
- char *p = buffer;
-
- memset(buffer, 0, sizeof(buffer));
- int i;
- for (i = 0; i < argc; i++) {
- unsigned int len = strlen(argv[i]) + 1; // Account for space
- if (i == argObscure) {
- len += 2; // Account for {}
- }
- if (((p - buffer) + len) < (sizeof(buffer)-1)) {
- if (i == argObscure) {
- *p++ = '{';
- *p++ = '}';
- *p++ = ' ';
- continue;
- }
- strcpy(p, argv[i]);
- p+= strlen(argv[i]);
- if (i != (argc -1)) {
- *p++ = ' ';
- }
- }
- }
- SLOGD("%s", buffer);
-}
-#else
-void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
-#endif
-
-int CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
- if (!cond) {
- return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
- } else {
- return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
- }
-}
-
-CommandListener::DumpCmd::DumpCmd() :
- VoldCommand("dump") {
-}
-
-int CommandListener::DumpCmd::runCommand(SocketClient *cli,
- int /*argc*/, char ** /*argv*/) {
- cli->sendMsg(0, "Dumping loop status", false);
- if (Loop::dumpState(cli)) {
- cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
- }
- cli->sendMsg(0, "Dumping DM status", false);
- if (Devmapper::dumpState(cli)) {
- cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
- }
- cli->sendMsg(0, "Dumping mounted filesystems", false);
- FILE *fp = fopen("/proc/mounts", "re");
- if (fp) {
- char line[1024];
- while (fgets(line, sizeof(line), fp)) {
- line[strlen(line)-1] = '\0';
- cli->sendMsg(0, line, false);;
- }
- fclose(fp);
- }
-
- cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
- return 0;
-}
-
-CommandListener::VolumeCmd::VolumeCmd() :
- VoldCommand("volume") {
-}
-
-int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- dumpArgs(argc, argv, -1);
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
-
- VolumeManager *vm = VolumeManager::Instance();
- std::lock_guard<std::mutex> lock(vm->getLock());
-
- // TODO: tease out methods not directly related to volumes
-
- std::string cmd(argv[1]);
- if (cmd == "reset") {
- return sendGenericOkFail(cli, vm->reset());
-
- } else if (cmd == "shutdown") {
- return sendGenericOkFail(cli, vm->shutdown());
-
- } else if (cmd == "debug") {
- return sendGenericOkFail(cli, vm->setDebug(true));
-
- } else if (cmd == "partition" && argc > 3) {
- // partition [diskId] [public|private|mixed] [ratio]
- std::string id(argv[2]);
- auto disk = vm->findDisk(id);
- if (disk == nullptr) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
- }
-
- std::string type(argv[3]);
- if (type == "public") {
- return sendGenericOkFail(cli, disk->partitionPublic());
- } else if (type == "private") {
- return sendGenericOkFail(cli, disk->partitionPrivate());
- } else if (type == "mixed") {
- if (argc < 4) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
- }
- int frac = atoi(argv[4]);
- return sendGenericOkFail(cli, disk->partitionMixed(frac));
- } else {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
- }
-
- } else if (cmd == "mkdirs" && argc > 2) {
- // mkdirs [path]
- return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
-
- } else if (cmd == "user_added" && argc > 3) {
- // user_added [user] [serial]
- return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
-
- } else if (cmd == "user_removed" && argc > 2) {
- // user_removed [user]
- return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
-
- } else if (cmd == "user_started" && argc > 2) {
- // user_started [user]
- return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
-
- } else if (cmd == "user_stopped" && argc > 2) {
- // user_stopped [user]
- return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
-
- } else if (cmd == "mount" && argc > 2) {
- // mount [volId] [flags] [user]
- std::string id(argv[2]);
- auto vol = vm->findVolume(id);
- if (vol == nullptr) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
- }
-
- int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
- userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
-
- vol->setMountFlags(mountFlags);
- vol->setMountUserId(mountUserId);
-
- int res = vol->mount();
- if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
- vm->setPrimary(vol);
- }
- return sendGenericOkFail(cli, res);
-
- } else if (cmd == "unmount" && argc > 2) {
- // unmount [volId]
- std::string id(argv[2]);
- auto vol = vm->findVolume(id);
- if (vol == nullptr) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
- }
-
- return sendGenericOkFail(cli, vol->unmount());
-
- } else if (cmd == "format" && argc > 3) {
- // format [volId] [fsType|auto]
- std::string id(argv[2]);
- std::string fsType(argv[3]);
- auto vol = vm->findVolume(id);
- if (vol == nullptr) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
- }
-
- return sendGenericOkFail(cli, vol->format(fsType));
-
- } else if (cmd == "move_storage" && argc > 3) {
- // move_storage [fromVolId] [toVolId]
- auto fromVol = vm->findVolume(std::string(argv[2]));
- auto toVol = vm->findVolume(std::string(argv[3]));
- if (fromVol == nullptr || toVol == nullptr) {
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
- }
-
- (new android::vold::MoveTask(fromVol, toVol))->start();
- return sendGenericOkFail(cli, 0);
-
- } else if (cmd == "benchmark" && argc > 2) {
- // benchmark [volId]
- std::string id(argv[2]);
- nsecs_t res = vm->benchmarkPrivate(id);
- return cli->sendMsg(ResponseCode::CommandOkay,
- android::base::StringPrintf("%" PRId64, res).c_str(), false);
-
- } else if (cmd == "forget_partition" && argc > 2) {
- // forget_partition [partGuid]
- std::string partGuid(argv[2]);
- return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
-
- } else if (cmd == "remount_uid" && argc > 3) {
- // remount_uid [uid] [none|default|read|write]
- uid_t uid = atoi(argv[2]);
- std::string mode(argv[3]);
- return sendGenericOkFail(cli, vm->remountUid(uid, mode));
- }
-
- return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
-}
-
-CommandListener::StorageCmd::StorageCmd() :
- VoldCommand("storage") {
-}
-
-int CommandListener::StorageCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- /* Guarantied to be initialized by vold's main() before the CommandListener is active */
- extern struct fstab *fstab;
-
- dumpArgs(argc, argv, -1);
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
-
- if (!strcmp(argv[1], "mountall")) {
- if (argc != 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
- return 0;
- }
- fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
- cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
- return 0;
- }
- if (!strcmp(argv[1], "users")) {
- DIR *dir;
- struct dirent *de;
-
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
- return 0;
- }
- if (!(dir = opendir("/proc"))) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
- return 0;
- }
-
- while ((de = readdir(dir))) {
- int pid = Process::getPid(de->d_name);
-
- if (pid < 0) {
- continue;
- }
-
- std::string processName;
- Process::getProcessName(pid, processName);
-
- if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
- Process::checkFileMaps(pid, argv[2]) ||
- Process::checkSymLink(pid, argv[2], "cwd") ||
- Process::checkSymLink(pid, argv[2], "root") ||
- Process::checkSymLink(pid, argv[2], "exe")) {
-
- char msg[1024];
- snprintf(msg, sizeof(msg), "%d %s", pid, processName.c_str());
- cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
- }
- }
- closedir(dir);
- cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
- } else {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
- }
- return 0;
-}
-
-CommandListener::AsecCmd::AsecCmd() :
- VoldCommand("asec") {
-}
-
-void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
- DIR *d = opendir(directory);
-
- if (!d) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
- return;
- }
-
- dirent* dent;
- while ((dent = readdir(d)) != NULL) {
- if (dent->d_name[0] == '.')
- continue;
- if (dent->d_type != DT_REG)
- continue;
- size_t name_len = strlen(dent->d_name);
- if (name_len > 5 && name_len < 260 &&
- !strcmp(&dent->d_name[name_len - 5], ".asec")) {
- char id[255];
- memset(id, 0, sizeof(id));
- strlcpy(id, dent->d_name, name_len - 4);
- cli->sendMsg(ResponseCode::AsecListResult, id, false);
- }
- }
- closedir(d);
-}
-
-int CommandListener::AsecCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
-
- VolumeManager *vm = VolumeManager::Instance();
- int rc = 0;
-
- if (!strcmp(argv[1], "list")) {
- dumpArgs(argc, argv, -1);
-
- listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_EXT);
- listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_INT);
- } else if (!strcmp(argv[1], "create")) {
- dumpArgs(argc, argv, 5);
- if (argc != 8) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
- "<isExternal>", false);
- return 0;
- }
-
- unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
- const bool isExternal = (atoi(argv[7]) == 1);
- rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
- } else if (!strcmp(argv[1], "resize")) {
- dumpArgs(argc, argv, -1);
- if (argc != 5) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
- return 0;
- }
- unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
- rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
- } else if (!strcmp(argv[1], "finalize")) {
- dumpArgs(argc, argv, -1);
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
- return 0;
- }
- rc = vm->finalizeAsec(argv[2]);
- } else if (!strcmp(argv[1], "fixperms")) {
- dumpArgs(argc, argv, -1);
- if (argc != 5) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
- return 0;
- }
-
- char *endptr;
- gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
- if (*endptr != '\0') {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
- return 0;
- }
-
- rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
- } else if (!strcmp(argv[1], "destroy")) {
- dumpArgs(argc, argv, -1);
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
- return 0;
- }
- bool force = false;
- if (argc > 3 && !strcmp(argv[3], "force")) {
- force = true;
- }
- rc = vm->destroyAsec(argv[2], force);
- } else if (!strcmp(argv[1], "mount")) {
- dumpArgs(argc, argv, 3);
- if (argc != 6) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
- return 0;
- }
- bool readOnly = true;
- if (!strcmp(argv[5], "rw")) {
- readOnly = false;
- }
- rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
- } else if (!strcmp(argv[1], "unmount")) {
- dumpArgs(argc, argv, -1);
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
- return 0;
- }
- bool force = false;
- if (argc > 3 && !strcmp(argv[3], "force")) {
- force = true;
- }
- rc = vm->unmountAsec(argv[2], force);
- } else if (!strcmp(argv[1], "rename")) {
- dumpArgs(argc, argv, -1);
- if (argc != 4) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: asec rename <old_id> <new_id>", false);
- return 0;
- }
- rc = vm->renameAsec(argv[2], argv[3]);
- } else if (!strcmp(argv[1], "path")) {
- dumpArgs(argc, argv, -1);
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
- return 0;
- }
- char path[255];
-
- if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
- cli->sendMsg(ResponseCode::AsecPathResult, path, false);
- return 0;
- }
- } else if (!strcmp(argv[1], "fspath")) {
- dumpArgs(argc, argv, -1);
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
- return 0;
- }
- char path[255];
-
- if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
- cli->sendMsg(ResponseCode::AsecPathResult, path, false);
- return 0;
- }
- } else {
- dumpArgs(argc, argv, -1);
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
- }
-
- if (!rc) {
- cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
- } else {
- rc = ResponseCode::convertFromErrno();
- cli->sendMsg(rc, "asec operation failed", true);
- }
-
- return 0;
-}
-
-CommandListener::ObbCmd::ObbCmd() :
- VoldCommand("obb") {
-}
-
-int CommandListener::ObbCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
-
- VolumeManager *vm = VolumeManager::Instance();
- int rc = 0;
-
- if (!strcmp(argv[1], "list")) {
- dumpArgs(argc, argv, -1);
-
- rc = vm->listMountedObbs(cli);
- } else if (!strcmp(argv[1], "mount")) {
- dumpArgs(argc, argv, 3);
- if (argc != 5) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: obb mount <filename> <key> <ownerGid>", false);
- return 0;
- }
- rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
- } else if (!strcmp(argv[1], "unmount")) {
- dumpArgs(argc, argv, -1);
- if (argc < 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
- return 0;
- }
- bool force = false;
- if (argc > 3 && !strcmp(argv[3], "force")) {
- force = true;
- }
- rc = vm->unmountObb(argv[2], force);
- } else if (!strcmp(argv[1], "path")) {
- dumpArgs(argc, argv, -1);
- if (argc != 3) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
- return 0;
- }
- char path[255];
-
- if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
- cli->sendMsg(ResponseCode::AsecPathResult, path, false);
- return 0;
- }
- } else {
- dumpArgs(argc, argv, -1);
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
- }
-
- if (!rc) {
- cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
- } else {
- rc = ResponseCode::convertFromErrno();
- cli->sendMsg(rc, "obb operation failed", true);
- }
-
- return 0;
-}
-
-CommandListener::FstrimCmd::FstrimCmd() :
- VoldCommand("fstrim") {
-}
-int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
- cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
- return 0;
- }
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
- return 0;
- }
-
- VolumeManager *vm = VolumeManager::Instance();
- std::lock_guard<std::mutex> lock(vm->getLock());
-
- int flags = 0;
-
- std::string cmd(argv[1]);
- if (cmd == "dotrim") {
- flags = 0;
- } else if (cmd == "dotrimbench") {
- flags = android::vold::TrimTask::Flags::kBenchmarkAfter;
- } else if (cmd == "dodtrim") {
- flags = android::vold::TrimTask::Flags::kDeepTrim;
- } else if (cmd == "dodtrimbench") {
- flags = android::vold::TrimTask::Flags::kDeepTrim
- | android::vold::TrimTask::Flags::kBenchmarkAfter;
- }
-
- (new android::vold::TrimTask(flags))->start();
- return sendGenericOkFail(cli, 0);
-}
-
-static size_t kAppFuseMaxMountPointName = 32;
-
-static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
- if (name.size() > kAppFuseMaxMountPointName) {
- LOG(ERROR) << "AppFuse mount name is too long.";
- return -EINVAL;
- }
- for (size_t i = 0; i < name.size(); i++) {
- if (!isalnum(name[i])) {
- LOG(ERROR) << "AppFuse mount name contains invalid character.";
- return -EINVAL;
- }
- }
- *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
- return android::OK;
-}
-
-static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
- // Remove existing mount.
- android::vold::ForceUnmount(path);
-
- const auto opts = android::base::StringPrintf(
- "fd=%i,"
- "rootmode=40000,"
- "default_permissions,"
- "allow_other,"
- "user_id=%d,group_id=%d,"
- "context=\"u:object_r:app_fuse_file:s0\","
- "fscontext=u:object_r:app_fusefs:s0",
- device_fd,
- uid,
- uid);
-
- const int result = TEMP_FAILURE_RETRY(mount(
- "/dev/fuse", path.c_str(), "fuse",
- MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
- if (result != 0) {
- PLOG(ERROR) << "Failed to mount " << path;
- return -errno;
- }
-
- return android::OK;
-}
-
-static android::status_t runCommandInNamespace(const std::string& command,
- uid_t uid,
- pid_t pid,
- const std::string& path,
- int device_fd) {
- if (DEBUG_APPFUSE) {
- LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
- << " in namespace " << uid;
- }
-
- unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (dir.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc";
- return -errno;
- }
-
- // Obtains process file descriptor.
- const std::string pid_str = android::base::StringPrintf("%d", pid);
- const unique_fd pid_fd(
- openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (pid_fd.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc/" << pid;
- return -errno;
- }
-
- // Check UID of process.
- {
- struct stat sb;
- const int result = fstat(pid_fd.get(), &sb);
- if (result == -1) {
- PLOG(ERROR) << "Failed to stat /proc/" << pid;
- return -errno;
- }
- if (sb.st_uid != AID_SYSTEM) {
- LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
- << ", actual=" << sb.st_uid;
- return -EPERM;
- }
- }
-
- // Matches so far, but refuse to touch if in root namespace
- {
- char rootName[PATH_MAX];
- char pidName[PATH_MAX];
- const int root_result =
- android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
- const int pid_result =
- android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
- if (root_result == -1) {
- LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
- return -EPERM;
- }
- if (pid_result == -1) {
- LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
- return -EPERM;
- }
- if (!strcmp(rootName, pidName)) {
- LOG(ERROR) << "Don't mount appfuse in root namespace";
- return -EPERM;
- }
- }
-
- // We purposefully leave the namespace open across the fork
- unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
- if (ns_fd.get() < 0) {
- PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
- return -errno;
- }
-
- int child = fork();
- if (child == 0) {
- if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
- PLOG(ERROR) << "Failed to setns";
- _exit(-errno);
- }
-
- if (command == "mount") {
- _exit(mountInNamespace(uid, device_fd, path));
- } else if (command == "unmount") {
- // If it's just after all FD opened on mount point are closed, umount2 can fail with
- // EBUSY. To avoid the case, specify MNT_DETACH.
- if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
- errno != EINVAL && errno != ENOENT) {
- PLOG(ERROR) << "Failed to unmount directory.";
- _exit(-errno);
- }
- if (rmdir(path.c_str()) != 0) {
- PLOG(ERROR) << "Failed to remove the mount directory.";
- _exit(-errno);
- }
- _exit(android::OK);
- } else {
- LOG(ERROR) << "Unknown appfuse command " << command;
- _exit(-EPERM);
- }
- }
-
- if (child == -1) {
- PLOG(ERROR) << "Failed to folk child process";
- return -errno;
- }
-
- android::status_t status;
- TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
-
- return status;
-}
-
-CommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
-
-int CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char **argv) {
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
- return 0;
- }
-
- const std::string command(argv[1]);
-
- if (command == "mount" && argc == 5) {
- const uid_t uid = atoi(argv[2]);
- const pid_t pid = atoi(argv[3]);
- const std::string name(argv[4]);
-
- // Check mount point name.
- std::string path;
- if (getMountPath(uid, name, &path) != android::OK) {
- return cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid mount point name.",
- false);
- }
-
- // Create directories.
- {
- const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
- if (result != android::OK) {
- PLOG(ERROR) << "Failed to prepare directory " << path;
- return sendGenericOkFail(cli, result);
- }
- }
-
- // Open device FD.
- unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
- if (device_fd.get() == -1) {
- PLOG(ERROR) << "Failed to open /dev/fuse";
- return sendGenericOkFail(cli, -errno);
- }
-
- // Mount.
- {
- const android::status_t result =
- runCommandInNamespace(command, uid, pid, path, device_fd.get());
- if (result != android::OK) {
- return sendGenericOkFail(cli, result);
- }
- }
-
- return sendFd(cli, device_fd.get());
- } else if (command == "unmount" && argc == 5) {
- const uid_t uid = atoi(argv[2]);
- const uid_t pid = atoi(argv[3]);
- const std::string name(argv[4]);
-
- // Check mount point name.
- std::string path;
- if (getMountPath(uid, name, &path) != android::OK) {
- return cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid mount point name.",
- false);
- }
-
- const android::status_t result =
- runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
- return sendGenericOkFail(cli, result);
- }
-
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
-}
-
-android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
- struct iovec data;
- char dataBuffer[128];
- char controlBuffer[CMSG_SPACE(sizeof(int))];
- struct msghdr message;
-
- // Message.
- memset(&message, 0, sizeof(struct msghdr));
- message.msg_iov = &data;
- message.msg_iovlen = 1;
- message.msg_control = controlBuffer;
- message.msg_controllen = CMSG_SPACE(sizeof(int));
-
- // Data.
- data.iov_base = dataBuffer;
- data.iov_len = snprintf(dataBuffer,
- sizeof(dataBuffer),
- "200 %d AppFuse command succeeded",
- cli->getCmdNum()) + 1;
-
- // Control.
- struct cmsghdr* const controlMessage = CMSG_FIRSTHDR(&message);
- memset(controlBuffer, 0, CMSG_SPACE(sizeof(int)));
- controlMessage->cmsg_level = SOL_SOCKET;
- controlMessage->cmsg_type = SCM_RIGHTS;
- controlMessage->cmsg_len = CMSG_LEN(sizeof(int));
- *((int *) CMSG_DATA(controlMessage)) = fd;
-
- const int result = TEMP_FAILURE_RETRY(sendmsg(cli->getSocket(), &message, 0));
- if (result == -1) {
- PLOG(ERROR) << "Failed to send FD from vold";
- return -errno;
- }
-
- return android::OK;
-}
diff --git a/CommandListener.h b/CommandListener.h
deleted file mode 100644
index f858ac0..0000000
--- a/CommandListener.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _COMMANDLISTENER_H__
-#define _COMMANDLISTENER_H__
-
-#include <sysutils/FrameworkListener.h>
-#include <utils/Errors.h>
-#include "VoldCommand.h"
-
-class CommandListener : public FrameworkListener {
-public:
- CommandListener();
- virtual ~CommandListener() {}
-
-private:
- static void dumpArgs(int argc, char **argv, int argObscure);
- static int sendGenericOkFail(SocketClient *cli, int cond);
-
- class DumpCmd : public VoldCommand {
- public:
- DumpCmd();
- virtual ~DumpCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class VolumeCmd : public VoldCommand {
- public:
- VolumeCmd();
- virtual ~VolumeCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class AsecCmd : public VoldCommand {
- public:
- AsecCmd();
- virtual ~AsecCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- private:
- void listAsecsInDirectory(SocketClient *c, const char *directory);
- };
-
- class ObbCmd : public VoldCommand {
- public:
- ObbCmd();
- virtual ~ObbCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class StorageCmd : public VoldCommand {
- public:
- StorageCmd();
- virtual ~StorageCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class FstrimCmd : public VoldCommand {
- public:
- FstrimCmd();
- virtual ~FstrimCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class AppFuseCmd : public VoldCommand {
- public:
- AppFuseCmd();
- virtual ~AppFuseCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- private:
- android::status_t sendFd(SocketClient *c, int fd);
- };
-};
-
-#endif
diff --git a/CryptCommandListener.cpp b/CryptCommandListener.cpp
deleted file mode 100644
index 779338f..0000000
--- a/CryptCommandListener.cpp
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2015 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 <assert.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fs_mgr.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <inttypes.h>
-
-#include <algorithm>
-#include <thread>
-
-#define LOG_TAG "VoldCryptCmdListener"
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-
-#include <cutils/fs.h>
-#include <cutils/log.h>
-#include <cutils/sockets.h>
-
-#include <sysutils/SocketClient.h>
-#include <private/android_filesystem_config.h>
-
-#include "CryptCommandListener.h"
-#include "Process.h"
-#include "ResponseCode.h"
-#include "cryptfs.h"
-#include "Ext4Crypt.h"
-#include "MetadataCrypt.h"
-#include "Utils.h"
-
-#define DUMP_ARGS 0
-
-CryptCommandListener::CryptCommandListener() :
-FrameworkListener("cryptd", true) {
- registerCmd(new CryptfsCmd());
-}
-
-#if DUMP_ARGS
-void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
- char buffer[4096];
- char *p = buffer;
-
- memset(buffer, 0, sizeof(buffer));
- int i;
- for (i = 0; i < argc; i++) {
- unsigned int len = strlen(argv[i]) + 1; // Account for space
- if (i == argObscure) {
- len += 2; // Account for {}
- }
- if (((p - buffer) + len) < (sizeof(buffer)-1)) {
- if (i == argObscure) {
- *p++ = '{';
- *p++ = '}';
- *p++ = ' ';
- continue;
- }
- strcpy(p, argv[i]);
- p+= strlen(argv[i]);
- if (i != (argc -1)) {
- *p++ = ' ';
- }
- }
- }
- SLOGD("%s", buffer);
-}
-#else
-void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
-#endif
-
-int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
- if (success) {
- return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
- } else {
- return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
- }
-}
-
-CryptCommandListener::CryptfsCmd::CryptfsCmd() :
- VoldCommand("cryptfs") {
-}
-
-static int getType(const char* type)
-{
- if (!strcmp(type, "default")) {
- return CRYPT_TYPE_DEFAULT;
- } else if (!strcmp(type, "password")) {
- return CRYPT_TYPE_PASSWORD;
- } else if (!strcmp(type, "pin")) {
- return CRYPT_TYPE_PIN;
- } else if (!strcmp(type, "pattern")) {
- return CRYPT_TYPE_PATTERN;
- } else {
- return -1;
- }
-}
-
-static char* parseNull(char* arg) {
- if (strcmp(arg, "!") == 0) {
- return nullptr;
- } else {
- return arg;
- }
-}
-
-static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
- int expected, std::string usage) {
- assert(expected >= 2);
- if (expected == 2) {
- assert(usage.empty());
- } else {
- assert(!usage.empty());
- assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
- }
- if (argc == expected) {
- return true;
- }
- auto message = std::string() + "Usage: cryptfs " + subcommand;
- if (!usage.empty()) {
- message += " " + usage;
- }
- cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
- return false;
-}
-
-static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
- int rc;
- int tries;
- for (tries = 0; tries < 2; ++tries) {
- if (type == CRYPT_TYPE_DEFAULT) {
- rc = cryptfs_enable_default(arg2, no_ui);
- } else {
- rc = cryptfs_enable(arg2, type, arg4, no_ui);
- }
-
- if (rc == 0) {
- free(arg2);
- free(arg4);
- return 0;
- } else if (tries == 0) {
- Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
- }
- }
-
- free(arg2);
- free(arg4);
- return -1;
-}
-
-int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
- cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
- return 0;
- }
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
- return 0;
- }
-
- int rc = 0;
-
- std::string subcommand(argv[1]);
- if (subcommand == "checkpw") {
- if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
- dumpArgs(argc, argv, 2);
- rc = cryptfs_check_passwd(argv[2]);
- } else if (subcommand == "restart") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- dumpArgs(argc, argv, -1);
-
- // Spawn as thread so init can issue commands back to vold without
- // causing deadlock, usually as a result of prep_data_fs.
- std::thread(&cryptfs_restart).detach();
- } else if (subcommand == "cryptocomplete") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- dumpArgs(argc, argv, -1);
- rc = cryptfs_crypto_complete();
- } else if (subcommand == "enablecrypto") {
- if (e4crypt_is_native()) {
- if (argc != 5 || strcmp(argv[2], "inplace") || strcmp(argv[3], "default")
- || strcmp(argv[4], "noui")) {
- cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage with ext4crypt: cryptfs enablecrypto inplace default noui", false);
- return 0;
- }
- return sendGenericOkFailOnBool(cli, e4crypt_enable_crypto());
- }
- const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
- "default|password|pin|pattern [passwd] [noui]";
-
- // This should be replaced with a command line parser if more options
- // are added
- bool valid = true;
- bool no_ui = false;
- int type = CRYPT_TYPE_DEFAULT;
- int options = 4; // Optional parameters are at this offset
- if (argc < 4) {
- // Minimum 4 parameters
- valid = false;
- } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
- // Second parameter must be wipe or inplace
- valid = false;
- } else {
- // Third parameter must be valid type
- type = getType(argv[3]);
- if (type == -1) {
- valid = false;
- } else if (type != CRYPT_TYPE_DEFAULT) {
- options++;
- }
- }
-
- if (valid) {
- if(argc < options) {
- // Too few parameters
- valid = false;
- } else if (argc == options) {
- // No more, done
- } else if (argc == options + 1) {
- // One option, must be noui
- if (!strcmp(argv[options], "noui")) {
- no_ui = true;
- } else {
- valid = false;
- }
- } else {
- // Too many options
- valid = false;
- }
- }
-
- if (!valid) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
- return 0;
- }
-
- dumpArgs(argc, argv, 4);
-
- // Spawn as thread so init can issue commands back to vold without
- // causing deadlock, usually as a result of prep_data_fs.
- char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
- char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
- std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
- } else if (subcommand == "enablefilecrypto") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- dumpArgs(argc, argv, -1);
- rc = e4crypt_initialize_global_de();
- } else if (subcommand == "changepw") {
- const char* syntax = "Usage: cryptfs changepw "
- "default|password|pin|pattern [newpasswd]";
- const char* password;
- if (argc == 3) {
- password = "";
- } else if (argc == 4) {
- password = argv[3];
- } else {
- cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
- return 0;
- }
- int type = getType(argv[2]);
- if (type == -1) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
- return 0;
- }
- SLOGD("cryptfs changepw %s {}", argv[2]);
- rc = cryptfs_changepw(type, password);
- } else if (subcommand == "verifypw") {
- if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
- SLOGD("cryptfs verifypw {}");
- rc = cryptfs_verify_passwd(argv[2]);
- } else if (subcommand == "getfield") {
- if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
- char *valbuf;
- int valbuf_len = PROPERTY_VALUE_MAX;
-
- dumpArgs(argc, argv, -1);
-
- // Increase the buffer size until it is big enough for the field value stored.
- while (1) {
- valbuf = (char*)malloc(valbuf_len);
- if (valbuf == NULL) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
- return 0;
- }
- rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
- if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
- break;
- }
- free(valbuf);
- valbuf_len *= 2;
- }
- if (rc == CRYPTO_GETFIELD_OK) {
- cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
- }
- free(valbuf);
- } else if (subcommand == "setfield") {
- if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
- dumpArgs(argc, argv, -1);
- rc = cryptfs_setfield(argv[2], argv[3]);
- } else if (subcommand == "mountdefaultencrypted") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- SLOGD("cryptfs mountdefaultencrypted");
- dumpArgs(argc, argv, -1);
-
- if (e4crypt_is_native()) {
- return sendGenericOkFailOnBool(cli, e4crypt_mount_metadata_encrypted());
- }
- // Spawn as thread so init can issue commands back to vold without
- // causing deadlock, usually as a result of prep_data_fs.
- std::thread(&cryptfs_mount_default_encrypted).detach();
- } else if (subcommand == "getpwtype") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- SLOGD("cryptfs getpwtype");
- dumpArgs(argc, argv, -1);
- switch(cryptfs_get_password_type()) {
- case CRYPT_TYPE_PASSWORD:
- cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
- return 0;
- case CRYPT_TYPE_PATTERN:
- cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
- return 0;
- case CRYPT_TYPE_PIN:
- cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
- return 0;
- case CRYPT_TYPE_DEFAULT:
- cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
- return 0;
- default:
- /** @TODO better error and make sure handled by callers */
- cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
- return 0;
- }
- } else if (subcommand == "getpw") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- SLOGD("cryptfs getpw");
- dumpArgs(argc, argv, -1);
- const char* password = cryptfs_get_password();
- if (password) {
- char* message = 0;
- int size = asprintf(&message, "{{sensitive}} %s", password);
- if (size != -1) {
- cli->sendMsg(ResponseCode::CommandOkay, message, false);
- memset(message, 0, size);
- free (message);
- return 0;
- }
- }
- rc = -1;
- } else if (subcommand == "clearpw") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- SLOGD("cryptfs clearpw");
- dumpArgs(argc, argv, -1);
- cryptfs_clear_password();
- rc = 0;
-
- } else if (subcommand == "isConvertibleToFBE") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
- SLOGD("cryptfs isConvertibleToFBE");
- dumpArgs(argc, argv, -1);
- rc = cryptfs_isConvertibleToFBE();
-
- } else if (subcommand == "init_user0") {
- if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
-
- } else if (subcommand == "create_user_key") {
- if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
- atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
-
- } else if (subcommand == "destroy_user_key") {
- if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
-
- } else if (subcommand == "add_user_key_auth") {
- if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
- atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
-
- } else if (subcommand == "fixate_newest_user_key_auth") {
- if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
-
- } else if (subcommand == "unlock_user_key") {
- if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
- atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
-
- } else if (subcommand == "lock_user_key") {
- if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
-
- } else if (subcommand == "prepare_user_storage") {
- if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
- return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
- parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
-
- } else if (subcommand == "destroy_user_storage") {
- if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
- return sendGenericOkFailOnBool(cli,
- e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
-
- } else if (subcommand == "secdiscard") {
- if (!check_argc(cli, subcommand, argc, 3, "<path>")) return 0;
- return sendGenericOkFailOnBool(cli,
- e4crypt_secdiscard(parseNull(argv[2])));
-
- } else {
- dumpArgs(argc, argv, -1);
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
- return 0;
- }
-
- // Always report that the command succeeded and return the error code.
- // The caller will check the return value to see what the error was.
- char msg[255];
- snprintf(msg, sizeof(msg), "%d", rc);
- cli->sendMsg(ResponseCode::CommandOkay, msg, false);
-
- return 0;
-}
diff --git a/CryptCommandListener.h b/CryptCommandListener.h
deleted file mode 100644
index 478ac02..0000000
--- a/CryptCommandListener.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef _CRYPTCOMMANDLISTENER_H__
-#define _CRYPTCOMMANDLISTENER_H__
-
-#include <sysutils/FrameworkListener.h>
-#include <utils/Errors.h>
-#include "VoldCommand.h"
-
-class CryptCommandListener : public FrameworkListener {
-public:
- CryptCommandListener();
- virtual ~CryptCommandListener() {}
-
-private:
- static void dumpArgs(int argc, char **argv, int argObscure);
- static int sendGenericOkFailOnBool(SocketClient *cli, bool success);
-
- class CryptfsCmd : public VoldCommand {
- public:
- CryptfsCmd();
- virtual ~CryptfsCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- int getSocket();
-};
-
-#endif
diff --git a/Devmapper.cpp b/Devmapper.cpp
index 4b6942d..2510771 100644
--- a/Devmapper.cpp
+++ b/Devmapper.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@@ -28,91 +30,18 @@
#include <linux/kdev_t.h>
-#define LOG_TAG "Vold"
-
-#include <cutils/log.h>
-
-#include <sysutils/SocketClient.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
#include "Devmapper.h"
#define DEVMAPPER_BUFFER_SIZE 4096
-int Devmapper::dumpState(SocketClient *c) {
+using android::base::StringPrintf;
- char *buffer = (char *) malloc(1024 * 64);
- if (!buffer) {
- SLOGE("Error allocating memory (%s)", strerror(errno));
- return -1;
- }
- memset(buffer, 0, (1024 * 64));
-
- char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
- if (!buffer2) {
- SLOGE("Error allocating memory (%s)", strerror(errno));
- free(buffer);
- return -1;
- }
-
- int fd;
- if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Error opening devmapper (%s)", strerror(errno));
- free(buffer);
- free(buffer2);
- return -1;
- }
-
- struct dm_ioctl *io = (struct dm_ioctl *) buffer;
- ioctlInit(io, (1024 * 64), NULL, 0);
-
- if (ioctl(fd, DM_LIST_DEVICES, io)) {
- SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno));
- free(buffer);
- free(buffer2);
- close(fd);
- return -1;
- }
-
- struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
- if (!n->dev) {
- free(buffer);
- free(buffer2);
- close(fd);
- return 0;
- }
-
- unsigned nxt = 0;
- do {
- n = (struct dm_name_list *) (((char *) n) + nxt);
-
- memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
- struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
- ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
- if (ioctl(fd, DM_DEV_STATUS, io2)) {
- if (errno != ENXIO) {
- SLOGE("DM_DEV_STATUS ioctl failed (%s)", strerror(errno));
- }
- io2 = NULL;
- }
-
- char *tmp;
- if (!io2) {
- asprintf(&tmp, "%s %llu:%llu (no status available)", n->name, MAJOR(n->dev), MINOR(n->dev));
- } else {
- asprintf(&tmp, "%s %llu:%llu %d %d 0x%.8x %llu:%llu", n->name, MAJOR(n->dev),
- MINOR(n->dev), io2->target_count, io2->open_count, io2->flags, MAJOR(io2->dev),
- MINOR(io2->dev));
- }
- c->sendMsg(0, tmp, false);
- free(tmp);
- nxt = n->next;
- } while (nxt);
-
- free(buffer);
- free(buffer2);
- close(fd);
- return 0;
-}
+static const char* kVoldPrefix = "vold:";
void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
const char *name, unsigned flags) {
@@ -130,50 +59,20 @@
}
}
-int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
- char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
- if (!buffer) {
- SLOGE("Error allocating memory (%s)", strerror(errno));
- return -1;
- }
-
- int fd;
- if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Error opening devmapper (%s)", strerror(errno));
- free(buffer);
- return -1;
- }
-
- struct dm_ioctl *io = (struct dm_ioctl *) buffer;
-
- ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
- if (ioctl(fd, DM_DEV_STATUS, io)) {
- if (errno != ENXIO) {
- SLOGE("DM_DEV_STATUS ioctl failed for lookup (%s)", strerror(errno));
- }
- free(buffer);
- close(fd);
- return -1;
- }
- close(fd);
-
- unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
- free(buffer);
- snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
- return 0;
-}
-
-int Devmapper::create(const char *name, const char *loopFile, const char *key,
+int Devmapper::create(const char *name_raw, const char *loopFile, const char *key,
unsigned long numSectors, char *ubuffer, size_t len) {
+ auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+ const char* name = name_string.c_str();
+
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
- SLOGE("Error allocating memory (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed malloc";
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Error opening devmapper (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed open";
free(buffer);
return -1;
}
@@ -184,7 +83,7 @@
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_CREATE, io)) {
- SLOGE("Error creating device mapping (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_DEV_CREATE";
free(buffer);
close(fd);
return -1;
@@ -199,7 +98,7 @@
geoParams += strlen(geoParams) + 1;
geoParams = (char *) _align(geoParams, 8);
if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
- SLOGE("Error setting device geometry (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_DEV_SET_GEOMETRY";
free(buffer);
close(fd);
return -1;
@@ -208,7 +107,7 @@
// Retrieve the device number we were allocated
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {
- SLOGE("Error retrieving devmapper status (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_DEV_STATUS";
free(buffer);
close(fd);
return -1;
@@ -239,7 +138,7 @@
tgt->next = cryptParams - buffer;
if (ioctl(fd, DM_TABLE_LOAD, io)) {
- SLOGE("Error loading mapping table (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_TABLE_LOAD";
free(buffer);
close(fd);
return -1;
@@ -249,7 +148,7 @@
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
- SLOGE("Error Resuming (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_DEV_SUSPEND";
free(buffer);
close(fd);
return -1;
@@ -261,16 +160,19 @@
return 0;
}
-int Devmapper::destroy(const char *name) {
+int Devmapper::destroy(const char *name_raw) {
+ auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+ const char* name = name_string.c_str();
+
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
- SLOGE("Error allocating memory (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed malloc";
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Error opening devmapper (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed open";
free(buffer);
return -1;
}
@@ -282,7 +184,7 @@
if (ioctl(fd, DM_DEV_REMOVE, io)) {
if (errno != ENXIO) {
- SLOGE("Error destroying device mapping (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed DM_DEV_REMOVE";
}
free(buffer);
close(fd);
@@ -294,6 +196,76 @@
return 0;
}
+int Devmapper::destroyAll() {
+ ATRACE_NAME("Devmapper::destroyAll");
+ char *buffer = (char *) malloc(1024 * 64);
+ if (!buffer) {
+ PLOG(ERROR) << "Failed malloc";
+ return -1;
+ }
+ memset(buffer, 0, (1024 * 64));
+
+ char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
+ if (!buffer2) {
+ PLOG(ERROR) << "Failed malloc";
+ free(buffer);
+ return -1;
+ }
+
+ int fd;
+ if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
+ PLOG(ERROR) << "Failed open";
+ free(buffer);
+ free(buffer2);
+ return -1;
+ }
+
+ struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+ ioctlInit(io, (1024 * 64), NULL, 0);
+
+ if (ioctl(fd, DM_LIST_DEVICES, io)) {
+ PLOG(ERROR) << "Failed DM_LIST_DEVICES";
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return -1;
+ }
+
+ struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
+ if (!n->dev) {
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return 0;
+ }
+
+ unsigned nxt = 0;
+ do {
+ n = (struct dm_name_list *) (((char *) n) + nxt);
+ auto name = std::string(n->name);
+ if (android::base::StartsWith(name, kVoldPrefix)) {
+ LOG(DEBUG) << "Tearing down stale dm device named " << name;
+
+ memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
+ struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
+ ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
+ if (ioctl(fd, DM_DEV_REMOVE, io2)) {
+ if (errno != ENXIO) {
+ PLOG(WARNING) << "Failed to destroy dm device named " << name;
+ }
+ }
+ } else {
+ LOG(VERBOSE) << "Found unmanaged dm device named " << name;
+ }
+ nxt = n->next;
+ } while (nxt);
+
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return 0;
+}
+
void *Devmapper::_align(void *ptr, unsigned int a)
{
unsigned long agn = --a;
diff --git a/Devmapper.h b/Devmapper.h
index 5b65b53..7bb9786 100644
--- a/Devmapper.h
+++ b/Devmapper.h
@@ -20,15 +20,12 @@
#include <unistd.h>
#include <linux/dm-ioctl.h>
-class SocketClient;
-
class Devmapper {
public:
static int create(const char *name, const char *loopFile, const char *key,
unsigned long numSectors, char *buffer, size_t len);
static int destroy(const char *name);
- static int lookupActive(const char *name, char *buffer, size_t len);
- static int dumpState(SocketClient *c);
+ static int destroyAll();
private:
static void *_align(void *ptr, unsigned int a);
diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp
index 6ef1cb0..16a108c 100644
--- a/EncryptInplace.cpp
+++ b/EncryptInplace.cpp
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <stdint.h>
-#include <stdbool.h>
#include <inttypes.h>
#include <time.h>
#include <sys/types.h>
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index dc2e42a..85ace4a 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -19,6 +19,7 @@
#include "KeyStorage.h"
#include "KeyUtil.h"
#include "Utils.h"
+#include "VoldUtil.h"
#include <algorithm>
#include <map>
@@ -39,6 +40,8 @@
#include <private/android_filesystem_config.h>
+#include "android/os/IVold.h"
+
#include "cryptfs.h"
#define EMULATED_USES_SELINUX 0
@@ -52,6 +55,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
using android::base::StringPrintf;
@@ -59,18 +63,24 @@
using android::vold::kEmptyAuthentication;
using android::vold::KeyBuffer;
-// NOTE: keep in sync with StorageManager
-static constexpr int FLAG_STORAGE_DE = 1 << 0;
-static constexpr int FLAG_STORAGE_CE = 1 << 1;
-
namespace {
+struct PolicyKeyRef {
+ std::string contents_mode;
+ std::string filenames_mode;
+ std::string key_raw_ref;
+};
+
const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
const std::string device_key_path = device_key_dir + "/key";
const std::string device_key_temp = device_key_dir + "/temp";
const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
const std::string user_key_temp = user_key_dir + "/temp";
+const std::string prepare_subdirs_path = "/system/bin/vold_prepare_subdirs";
+
+const std::string systemwide_volume_key_dir =
+ std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys";
bool s_global_de_initialized = false;
@@ -89,8 +99,8 @@
return property_get_bool("persist.sys.emulate_fbe", false);
}
-static const char* escape_null(const char* value) {
- return (value == nullptr) ? "null" : value;
+static const char* escape_empty(const std::string& value) {
+ return value.empty() ? "null" : value.c_str();
}
static std::string get_de_key_path(userid_t user_id) {
@@ -261,19 +271,19 @@
return true;
}
-static bool ensure_policy(const std::string& raw_ref, const std::string& path) {
- const char *contents_mode;
- const char *filenames_mode;
+static void get_data_file_encryption_modes(PolicyKeyRef* key_ref) {
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
+ char const* contents_mode;
+ char const* filenames_mode;
+ fs_mgr_get_file_encryption_modes(rec, &contents_mode, &filenames_mode);
+ key_ref->contents_mode = contents_mode;
+ key_ref->filenames_mode = filenames_mode;
+}
- cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
-
- if (e4crypt_policy_ensure(path.c_str(),
- raw_ref.data(), raw_ref.size(),
- contents_mode, filenames_mode) != 0) {
- LOG(ERROR) << "Failed to set policy on: " << path;
- return false;
- }
- return true;
+static bool ensure_policy(const PolicyKeyRef& key_ref, const std::string& path) {
+ return e4crypt_policy_ensure(path.c_str(), key_ref.key_raw_ref.data(),
+ key_ref.key_raw_ref.size(), key_ref.contents_mode.c_str(),
+ key_ref.filenames_mode.c_str()) == 0;
}
static bool is_numeric(const char* name) {
@@ -304,7 +314,7 @@
LOG(DEBUG) << "Skipping non-de-key " << entry->d_name;
continue;
}
- userid_t user_id = atoi(entry->d_name);
+ userid_t user_id = std::stoi(entry->d_name);
if (s_de_key_raw_refs.count(user_id) == 0) {
auto key_path = de_dir + "/" + entry->d_name;
KeyBuffer key;
@@ -328,23 +338,21 @@
return true;
}
- const char *contents_mode;
- const char *filenames_mode;
- cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
- std::string modestring = std::string(contents_mode) + ":" + filenames_mode;
+ PolicyKeyRef device_ref;
+ if (!android::vold::retrieveAndInstallKey(true, kEmptyAuthentication, device_key_path,
+ device_key_temp, &device_ref.key_raw_ref))
+ return false;
+ get_data_file_encryption_modes(&device_ref);
+ std::string modestring = device_ref.contents_mode + ":" + device_ref.filenames_mode;
std::string mode_filename = std::string("/data") + e4crypt_key_mode;
if (!android::base::WriteStringToFile(modestring, mode_filename)) {
PLOG(ERROR) << "Cannot save type";
return false;
}
- std::string device_key_ref;
- if (!android::vold::retrieveAndInstallKey(true,
- device_key_path, device_key_temp, &device_key_ref)) return false;
-
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
- if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
+ if (!android::base::WriteStringToFile(device_ref.key_raw_ref, ref_filename)) {
PLOG(ERROR) << "Cannot save key reference to:" << ref_filename;
return false;
}
@@ -370,7 +378,7 @@
// We can only safely prepare DE storage here, since CE keys are probably
// entangled with user credentials. The framework will always prepare CE
// storage once CE keys are installed.
- if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
+ if (!e4crypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
return false;
}
@@ -482,8 +490,8 @@
return true;
}
-static bool parse_hex(const char* hex, std::string* result) {
- if (strcmp("!", hex) == 0) {
+static bool parse_hex(const std::string& hex, std::string* result) {
+ if (hex == "!") {
*result = "";
return true;
}
@@ -494,10 +502,55 @@
return true;
}
-bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token_hex,
- const char* secret_hex) {
+static std::string volkey_path(const std::string& misc_path, const std::string& volume_uuid) {
+ return misc_path + "/vold/volume_keys/" + volume_uuid + "/default";
+}
+
+static std::string volume_secdiscardable_path(const std::string& volume_uuid) {
+ return systemwide_volume_key_dir + "/" + volume_uuid + "/secdiscardable";
+}
+
+static bool read_or_create_volkey(const std::string& misc_path, const std::string& volume_uuid,
+ PolicyKeyRef* key_ref) {
+ auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
+ std::string secdiscardable_hash;
+ if (android::vold::pathExists(secdiscardable_path)) {
+ if (!android::vold::readSecdiscardable(secdiscardable_path, &secdiscardable_hash))
+ return false;
+ } else {
+ if (fs_mkdirs(secdiscardable_path.c_str(), 0700) != 0) {
+ PLOG(ERROR) << "Creating directories for: " << secdiscardable_path;
+ return false;
+ }
+ if (!android::vold::createSecdiscardable(secdiscardable_path, &secdiscardable_hash))
+ return false;
+ }
+ auto key_path = volkey_path(misc_path, volume_uuid);
+ if (fs_mkdirs(key_path.c_str(), 0700) != 0) {
+ PLOG(ERROR) << "Creating directories for: " << key_path;
+ return false;
+ }
+ android::vold::KeyAuthentication auth("", secdiscardable_hash);
+ if (!android::vold::retrieveAndInstallKey(true, auth, key_path, key_path + "_tmp",
+ &key_ref->key_raw_ref))
+ return false;
+ key_ref->contents_mode =
+ android::base::GetProperty("ro.crypto.volume.contents_mode", "aes-256-xts");
+ key_ref->filenames_mode =
+ android::base::GetProperty("ro.crypto.volume.filenames_mode", "aes-256-heh");
+ return true;
+}
+
+static bool destroy_volkey(const std::string& misc_path, const std::string& volume_uuid) {
+ auto path = volkey_path(misc_path, volume_uuid);
+ if (!android::vold::pathExists(path)) return true;
+ return android::vold::destroyKey(path);
+}
+
+bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
+ const std::string& secret_hex) {
LOG(DEBUG) << "e4crypt_add_user_key_auth " << user_id << " serial=" << serial
- << " token_present=" << (strcmp(token_hex, "!") != 0);
+ << " token_present=" << (token_hex != "!");
if (!e4crypt_is_native()) return true;
if (s_ephemeral_users.count(user_id) != 0) return true;
std::string token, secret;
@@ -534,10 +587,10 @@
}
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
-bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex,
- const char* secret_hex) {
+bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex,
+ const std::string& secret_hex) {
LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
- << " token_present=" << (strcmp(token_hex, "!") != 0);
+ << " token_present=" << (token_hex != "!");
if (e4crypt_is_native()) {
if (s_ce_key_raw_refs.count(user_id) != 0) {
LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
@@ -557,8 +610,8 @@
// back into a known-good state.
if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
!emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) ||
- !emulated_unlock(android::vold::BuildDataMediaCePath(nullptr, user_id), 0770) ||
- !emulated_unlock(android::vold::BuildDataUserCePath(nullptr, user_id), 0771)) {
+ !emulated_unlock(android::vold::BuildDataMediaCePath("", user_id), 0770) ||
+ !emulated_unlock(android::vold::BuildDataUserCePath("", user_id), 0771)) {
LOG(ERROR) << "Failed to unlock user " << user_id;
return false;
}
@@ -575,8 +628,8 @@
// When in emulation mode, we just use chmod
if (!emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
!emulated_lock(android::vold::BuildDataMiscCePath(user_id)) ||
- !emulated_lock(android::vold::BuildDataMediaCePath(nullptr, user_id)) ||
- !emulated_lock(android::vold::BuildDataUserCePath(nullptr, user_id))) {
+ !emulated_lock(android::vold::BuildDataMediaCePath("", user_id)) ||
+ !emulated_lock(android::vold::BuildDataUserCePath("", user_id))) {
LOG(ERROR) << "Failed to lock user " << user_id;
return false;
}
@@ -585,12 +638,23 @@
return true;
}
-bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
- int flags) {
- LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
+static bool prepare_subdirs(const std::string& action, const std::string& volume_uuid,
+ userid_t user_id, int flags) {
+ if (0 != android::vold::ForkExecvp(
+ std::vector<std::string>{prepare_subdirs_path, action, volume_uuid,
+ std::to_string(user_id), std::to_string(flags)})) {
+ LOG(ERROR) << "vold_prepare_subdirs failed";
+ return false;
+ }
+ return true;
+}
+
+bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
+ int flags) {
+ LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_empty(volume_uuid)
<< ", user " << user_id << ", serial " << serial << ", flags " << flags;
- if (flags & FLAG_STORAGE_DE) {
+ if (flags & android::os::IVold::STORAGE_FLAG_DE) {
// DE_sys key
auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@@ -601,46 +665,63 @@
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
- if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
+ if (volume_uuid.empty()) {
+ if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
- if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
- multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
+ if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
+ multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
#endif
- if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
+ if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
+ if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
+ if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
+ }
if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (e4crypt_is_native()) {
- std::string de_raw_ref;
- if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
- if (!ensure_policy(de_raw_ref, system_de_path)) return false;
- if (!ensure_policy(de_raw_ref, misc_de_path)) return false;
- if (!ensure_policy(de_raw_ref, user_de_path)) return false;
+ PolicyKeyRef de_ref;
+ if (volume_uuid.empty()) {
+ if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_ref.key_raw_ref)) return false;
+ get_data_file_encryption_modes(&de_ref);
+ if (!ensure_policy(de_ref, system_de_path)) return false;
+ if (!ensure_policy(de_ref, misc_de_path)) return false;
+ } else {
+ if (!read_or_create_volkey(misc_de_path, volume_uuid, &de_ref)) return false;
+ }
+ if (!ensure_policy(de_ref, user_de_path)) return false;
}
}
- if (flags & FLAG_STORAGE_CE) {
+ if (flags & android::os::IVold::STORAGE_FLAG_CE) {
// CE_n key
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
- if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
- if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
+ if (volume_uuid.empty()) {
+ if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
+ if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
+ }
if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (e4crypt_is_native()) {
- std::string ce_raw_ref;
- if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
- if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
- if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false;
- if (!ensure_policy(ce_raw_ref, media_ce_path)) return false;
- if (!ensure_policy(ce_raw_ref, user_ce_path)) return false;
+ PolicyKeyRef ce_ref;
+ if (volume_uuid.empty()) {
+ if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_ref.key_raw_ref)) return false;
+ get_data_file_encryption_modes(&ce_ref);
+ if (!ensure_policy(ce_ref, system_ce_path)) return false;
+ if (!ensure_policy(ce_ref, misc_ce_path)) return false;
+ } else {
+ if (!read_or_create_volkey(misc_ce_path, volume_uuid, &ce_ref)) return false;
+ }
+ if (!ensure_policy(ce_ref, media_ce_path)) return false;
+ if (!ensure_policy(ce_ref, user_ce_path)) return false;
+ }
+
+ if (volume_uuid.empty()) {
// Now that credentials have been installed, we can run restorecon
// over these paths
// NOTE: these paths need to be kept in sync with libselinux
@@ -648,16 +729,38 @@
android::vold::RestoreconRecursive(misc_ce_path);
}
}
+ if (!prepare_subdirs("prepare", volume_uuid, user_id, flags)) return false;
return true;
}
-bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags) {
- LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_null(volume_uuid)
+bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags) {
+ LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_empty(volume_uuid)
<< ", user " << user_id << ", flags " << flags;
bool res = true;
- if (flags & FLAG_STORAGE_DE) {
+ res &= prepare_subdirs("destroy", volume_uuid, user_id, flags);
+
+ if (flags & android::os::IVold::STORAGE_FLAG_CE) {
+ // CE_n key
+ auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
+ auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
+ auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
+ auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
+
+ res &= destroy_dir(media_ce_path);
+ res &= destroy_dir(user_ce_path);
+ if (volume_uuid.empty()) {
+ res &= destroy_dir(system_ce_path);
+ res &= destroy_dir(misc_ce_path);
+ } else {
+ if (e4crypt_is_native()) {
+ res &= destroy_volkey(misc_ce_path, volume_uuid);
+ }
+ }
+ }
+
+ if (flags & android::os::IVold::STORAGE_FLAG_DE) {
// DE_sys key
auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@@ -668,7 +771,8 @@
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
- if (volume_uuid == nullptr) {
+ res &= destroy_dir(user_de_path);
+ if (volume_uuid.empty()) {
res &= destroy_dir(system_legacy_path);
#if MANAGE_MISC_DIRS
res &= destroy_dir(misc_legacy_path);
@@ -676,28 +780,52 @@
res &= destroy_dir(profiles_de_path);
res &= destroy_dir(system_de_path);
res &= destroy_dir(misc_de_path);
+ } else {
+ if (e4crypt_is_native()) {
+ res &= destroy_volkey(misc_de_path, volume_uuid);
+ }
}
- res &= destroy_dir(user_de_path);
- }
-
- if (flags & FLAG_STORAGE_CE) {
- // CE_n key
- auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
- auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
- auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
- auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
-
- if (volume_uuid == nullptr) {
- res &= destroy_dir(system_ce_path);
- res &= destroy_dir(misc_ce_path);
- }
- res &= destroy_dir(media_ce_path);
- res &= destroy_dir(user_ce_path);
}
return res;
}
-bool e4crypt_secdiscard(const char* path) {
- return android::vold::runSecdiscardSingle(std::string(path));
+static bool destroy_volume_keys(const std::string& directory_path, const std::string& volume_uuid) {
+ auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(directory_path.c_str()), closedir);
+ if (!dirp) {
+ PLOG(ERROR) << "Unable to open directory: " + directory_path;
+ return false;
+ }
+ bool res = true;
+ for (;;) {
+ errno = 0;
+ auto const entry = readdir(dirp.get());
+ if (!entry) {
+ if (errno) {
+ PLOG(ERROR) << "Unable to read directory: " + directory_path;
+ return false;
+ }
+ break;
+ }
+ if (entry->d_type != DT_DIR || entry->d_name[0] == '.') {
+ LOG(DEBUG) << "Skipping non-user " << entry->d_name;
+ continue;
+ }
+ res &= destroy_volkey(directory_path + "/" + entry->d_name, volume_uuid);
+ }
+ return res;
+}
+
+bool e4crypt_destroy_volume_keys(const std::string& volume_uuid) {
+ bool res = true;
+ LOG(DEBUG) << "e4crypt_destroy_volume_keys for volume " << escape_empty(volume_uuid);
+ auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
+ res &= android::vold::runSecdiscardSingle(secdiscardable_path);
+ res &= destroy_volume_keys("/data/misc_ce", volume_uuid);
+ res &= destroy_volume_keys("/data/misc_de", volume_uuid);
+ return res;
+}
+
+bool e4crypt_secdiscard(const std::string& path) {
+ return android::vold::runSecdiscardSingle(path);
}
diff --git a/Ext4Crypt.h b/Ext4Crypt.h
index e90167b..4226f15 100644
--- a/Ext4Crypt.h
+++ b/Ext4Crypt.h
@@ -14,29 +14,27 @@
* limitations under the License.
*/
-#include <stdbool.h>
-#include <sys/cdefs.h>
+#include <string>
#include <cutils/multiuser.h>
-__BEGIN_DECLS
-
-// General functions
-bool e4crypt_is_native();
bool e4crypt_initialize_global_de();
bool e4crypt_init_user0();
bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
bool e4crypt_destroy_user_key(userid_t user_id);
-bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token,
- const char* secret);
+bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token,
+ const std::string& secret);
bool e4crypt_fixate_newest_user_key_auth(userid_t user_id);
-bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token, const char* secret);
+bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token,
+ const std::string& secret);
bool e4crypt_lock_user_key(userid_t user_id);
-bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial, int flags);
-bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags);
+bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
+ int flags);
+bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags);
-bool e4crypt_secdiscard(const char* path);
-__END_DECLS
+bool e4crypt_destroy_volume_keys(const std::string& volume_uuid);
+
+bool e4crypt_secdiscard(const std::string& path);
diff --git a/TrimTask.cpp b/IdleMaint.cpp
similarity index 66%
rename from TrimTask.cpp
rename to IdleMaint.cpp
index 08e6499..ed6374f 100644
--- a/TrimTask.cpp
+++ b/IdleMaint.cpp
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-#include "TrimTask.h"
-#include "Benchmark.h"
+#include "IdleMaint.h"
#include "Utils.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
-#include <cutils/properties.h>
#include <fs_mgr.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
@@ -34,45 +31,34 @@
#include <sys/wait.h>
#include <fcntl.h>
-/* From a would-be kernel header */
-#define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */
-
-#define BENCHMARK_ENABLED 1
-
using android::base::StringPrintf;
namespace android {
namespace vold {
-static const char* kWakeLock = "TrimTask";
+static const char* kWakeLock = "IdleMaint";
-TrimTask::TrimTask(int flags) : mFlags(flags) {
- // Collect both fstab and vold volumes
- addFromFstab();
-
+static void addFromVolumeManager(std::list<std::string>* paths) {
VolumeManager* vm = VolumeManager::Instance();
std::list<std::string> privateIds;
vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
for (const auto& id : privateIds) {
auto vol = vm->findVolume(id);
if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
- mPaths.push_back(vol->getPath());
+ paths->push_back(vol->getPath());
}
}
}
-TrimTask::~TrimTask() {
-}
-
-void TrimTask::addFromFstab() {
+static void addFromFstab(std::list<std::string>* paths) {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
struct fstab_rec *prev_rec = NULL;
for (int i = 0; i < fstab->num_entries; i++) {
+ auto fs_type = std::string(fstab->recs[i].fs_type);
/* Skip raw partitions */
- if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
- !strcmp(fstab->recs[i].fs_type, "mtd")) {
+ if (fs_type == "emmc" || fs_type == "mtd") {
continue;
}
/* Skip read-only filesystems */
@@ -93,32 +79,31 @@
continue;
}
- mPaths.push_back(fstab->recs[i].mount_point);
+ paths->push_back(fstab->recs[i].mount_point);
prev_rec = &fstab->recs[i];
}
}
-void TrimTask::start() {
- mThread = std::thread(&TrimTask::run, this);
-}
-
-static void notifyResult(const std::string& path, int64_t bytes, int64_t delta) {
- std::string res(path
- + " " + std::to_string(bytes)
- + " " + std::to_string(delta));
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
- ResponseCode::TrimResult, res.c_str(), false);
-}
-
-void TrimTask::run() {
+void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
- for (const auto& path : mPaths) {
+ // Collect both fstab and vold volumes
+ std::list<std::string> paths;
+ addFromFstab(&paths);
+ addFromVolumeManager(&paths);
+
+ for (const auto& path : paths) {
LOG(DEBUG) << "Starting trim of " << path;
+ android::os::PersistableBundle extras;
+ extras.putString(String16("path"), String16(path.c_str()));
+
int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (fd < 0) {
PLOG(WARNING) << "Failed to open " << path;
+ if (listener) {
+ listener->onStatus(-1, extras);
+ }
continue;
}
@@ -127,24 +112,27 @@
range.len = ULLONG_MAX;
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
- if (ioctl(fd, (mFlags & Flags::kDeepTrim) ? FIDTRIM : FITRIM, &range)) {
+ if (ioctl(fd, FITRIM, &range)) {
PLOG(WARNING) << "Trim failed on " << path;
- notifyResult(path, -1, -1);
+ if (listener) {
+ listener->onStatus(-1, extras);
+ }
} else {
- nsecs_t delta = systemTime(SYSTEM_TIME_BOOTTIME) - start;
+ nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
- << " in " << nanoseconds_to_milliseconds(delta) << "ms";
- notifyResult(path, range.len, delta);
+ << " in " << nanoseconds_to_milliseconds(time) << "ms";
+ extras.putLong(String16("bytes"), range.len);
+ extras.putLong(String16("time"), time);
+ if (listener) {
+ listener->onStatus(0, extras);
+ }
}
close(fd);
+ }
- if (mFlags & Flags::kBenchmarkAfter) {
-#if BENCHMARK_ENABLED
- BenchmarkPrivate(path);
-#else
- LOG(DEBUG) << "Benchmark disabled";
-#endif
- }
+ if (listener) {
+ android::os::PersistableBundle extras;
+ listener->onFinished(0, extras);
}
release_wake_lock(kWakeLock);
diff --git a/VoldCommand.h b/IdleMaint.h
similarity index 64%
rename from VoldCommand.h
rename to IdleMaint.h
index e435159..38dadfb 100644
--- a/VoldCommand.h
+++ b/IdleMaint.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-#ifndef _VOLD_COMMAND_H
-#define _VOLD_COMMAND_H
+#ifndef ANDROID_VOLD_IDLE_MAINT_H
+#define ANDROID_VOLD_IDLE_MAINT_H
-#include <sysutils/FrameworkCommand.h>
+#include "android/os/IVoldTaskListener.h"
-class VoldCommand : public FrameworkCommand {
-public:
- explicit VoldCommand(const char *cmd);
- virtual ~VoldCommand() {}
-};
+namespace android {
+namespace vold {
+
+void Trim(const android::sp<android::os::IVoldTaskListener>& listener);
+
+} // namespace vold
+} // namespace android
#endif
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index 20b2391..be43b33 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -89,7 +89,7 @@
return true;
}
-static std::string hashWithPrefix(char const* prefix, const std::string& tohash) {
+static void hashWithPrefix(char const* prefix, const std::string& tohash, std::string* res) {
SHA512_CTX c;
SHA512_Init(&c);
@@ -100,9 +100,8 @@
hashingPrefix.resize(SHA512_CBLOCK);
SHA512_Update(&c, hashingPrefix.data(), hashingPrefix.size());
SHA512_Update(&c, tohash.data(), tohash.size());
- std::string res(SHA512_DIGEST_LENGTH, '\0');
- SHA512_Final(reinterpret_cast<uint8_t*>(&res[0]), &c);
- return res;
+ res->assign(SHA512_DIGEST_LENGTH, '\0');
+ SHA512_Final(reinterpret_cast<uint8_t*>(&(*res)[0]), &c);
}
static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth,
@@ -180,6 +179,30 @@
return true;
}
+static bool readRandomBytesOrLog(size_t count, std::string* out) {
+ auto status = ReadRandomBytes(count, *out);
+ if (status != OK) {
+ LOG(ERROR) << "Random read failed with status: " << status;
+ return false;
+ }
+ return true;
+}
+
+bool createSecdiscardable(const std::string& filename, std::string* hash) {
+ std::string secdiscardable;
+ if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
+ if (!writeStringToFile(secdiscardable, filename)) return false;
+ hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
+ return true;
+}
+
+bool readSecdiscardable(const std::string& filename, std::string* hash) {
+ std::string secdiscardable;
+ if (!readFileToString(filename, &secdiscardable)) return false;
+ hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
+ return true;
+}
+
static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
KeyPurpose purpose,
const AuthorizationSet &keyParams,
@@ -303,20 +326,11 @@
}
static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching,
- const std::string& salt, const std::string& secdiscardable,
+ const std::string& salt, const std::string& secdiscardable_hash,
std::string* appId) {
std::string stretched;
if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false;
- *appId = hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable) + stretched;
- return true;
-}
-
-static bool readRandomBytesOrLog(size_t count, std::string* out) {
- auto status = ReadRandomBytes(count, *out);
- if (status != OK) {
- LOG(ERROR) << "Random read failed with status: " << status;
- return false;
- }
+ *appId = secdiscardable_hash + stretched;
return true;
}
@@ -326,7 +340,8 @@
static bool encryptWithoutKeymaster(const std::string& preKey,
const KeyBuffer& plaintext, std::string* ciphertext) {
- auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
+ std::string key;
+ hashWithPrefix(kHashPrefix_keygen, preKey, &key);
key.resize(AES_KEY_BYTES);
if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
@@ -376,7 +391,8 @@
LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size();
return false;
}
- auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
+ std::string key;
+ hashWithPrefix(kHashPrefix_keygen, preKey, &key);
key.resize(AES_KEY_BYTES);
auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
@@ -430,9 +446,8 @@
return false;
}
if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false;
- std::string secdiscardable;
- if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
- if (!writeStringToFile(secdiscardable, dir + "/" + kFn_secdiscardable)) return false;
+ std::string secdiscardable_hash;
+ if (!createSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
std::string stretching = getStretching(auth);
if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false;
std::string salt;
@@ -444,7 +459,7 @@
if (!writeStringToFile(salt, dir + "/" + kFn_salt)) return false;
}
std::string appId;
- if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
+ if (!generateAppId(auth, stretching, salt, secdiscardable_hash, &appId)) return false;
std::string encryptedKey;
if (auth.usesKeymaster()) {
Keymaster keymaster;
@@ -487,8 +502,8 @@
LOG(ERROR) << "Version mismatch, expected " << kCurrentVersion << " got " << version;
return false;
}
- std::string secdiscardable;
- if (!readFileToString(dir + "/" + kFn_secdiscardable, &secdiscardable)) return false;
+ std::string secdiscardable_hash;
+ if (!readSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
std::string stretching;
if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false;
std::string salt;
@@ -496,7 +511,7 @@
if (!readFileToString(dir + "/" + kFn_salt, &salt)) return false;
}
std::string appId;
- if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
+ if (!generateAppId(auth, stretching, salt, secdiscardable_hash, &appId)) return false;
std::string encryptedMessage;
if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false;
if (auth.usesKeymaster()) {
@@ -519,19 +534,6 @@
return true;
}
-static bool runSecdiscard(const std::string& dir) {
- if (ForkExecvp(
- std::vector<std::string>{kSecdiscardPath, "--",
- dir + "/" + kFn_encrypted_key,
- dir + "/" + kFn_keymaster_key_blob,
- dir + "/" + kFn_secdiscardable,
- }) != 0) {
- LOG(ERROR) << "secdiscard failed";
- return false;
- }
- return true;
-}
-
bool runSecdiscardSingle(const std::string& file) {
if (ForkExecvp(
std::vector<std::string>{kSecdiscardPath, "--",
@@ -553,8 +555,20 @@
bool destroyKey(const std::string& dir) {
bool success = true;
// Try each thing, even if previous things failed.
- success &= deleteKey(dir);
- success &= runSecdiscard(dir);
+ bool uses_km = pathExists(dir + "/" + kFn_keymaster_key_blob);
+ if (uses_km) {
+ success &= deleteKey(dir);
+ }
+ auto secdiscard_cmd = std::vector<std::string>{
+ kSecdiscardPath, "--", dir + "/" + kFn_encrypted_key, dir + "/" + kFn_secdiscardable,
+ };
+ if (uses_km) {
+ secdiscard_cmd.emplace_back(dir + "/" + kFn_keymaster_key_blob);
+ }
+ if (ForkExecvp(secdiscard_cmd) != 0) {
+ LOG(ERROR) << "secdiscard failed";
+ success = false;
+ }
success &= recursiveDeleteKey(dir);
return success;
}
diff --git a/KeyStorage.h b/KeyStorage.h
index 655cd17..786e5b4 100644
--- a/KeyStorage.h
+++ b/KeyStorage.h
@@ -44,6 +44,9 @@
// Checks if path "path" exists.
bool pathExists(const std::string& path);
+bool createSecdiscardable(const std::string& path, std::string* hash);
+bool readSecdiscardable(const std::string& path, std::string* hash);
+
// Create a directory at the named path, and store "key" in it,
// in such a way that it can only be retrieved via Keymaster and
// can be securely deleted.
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index dbc73c1..9885440 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -161,12 +161,13 @@
return success;
}
-bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
- const std::string& tmp_path, std::string* key_ref) {
+bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
+ const std::string& key_path, const std::string& tmp_path,
+ std::string* key_ref) {
KeyBuffer key;
if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path;
- if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
+ if (!retrieveKey(key_path, key_authentication, &key)) return false;
} else {
if (!create_if_absent) {
LOG(ERROR) << "No key found in " << key_path;
@@ -174,8 +175,7 @@
}
LOG(INFO) << "Creating new key in " << key_path;
if (!randomKey(&key)) return false;
- if (!storeKeyAtomically(key_path, tmp_path,
- kEmptyAuthentication, key)) return false;
+ if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
}
if (!installKey(key, key_ref)) {
diff --git a/KeyUtil.h b/KeyUtil.h
index 412b0ae..a85eca1 100644
--- a/KeyUtil.h
+++ b/KeyUtil.h
@@ -18,6 +18,7 @@
#define ANDROID_VOLD_KEYUTIL_H
#include "KeyBuffer.h"
+#include "KeyStorage.h"
#include <string>
#include <memory>
@@ -28,8 +29,9 @@
bool randomKey(KeyBuffer* key);
bool installKey(const KeyBuffer& key, std::string* raw_ref);
bool evictKey(const std::string& raw_ref);
-bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
- const std::string& tmp_path, std::string* key_ref);
+bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
+ const std::string& key_path, const std::string& tmp_path,
+ std::string* key_ref);
bool retrieveKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, KeyBuffer* key);
diff --git a/Keymaster.h b/Keymaster.h
index dc6f1bc..f24a0c0 100644
--- a/Keymaster.h
+++ b/Keymaster.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_VOLD_KEYMASTER_H
#define ANDROID_VOLD_KEYMASTER_H
-#ifdef __cplusplus
-
#include "KeyBuffer.h"
#include <memory>
@@ -127,8 +125,7 @@
} // namespace vold
} // namespace android
-#endif // __cplusplus
-
+// FIXME no longer needed now cryptfs is in C++.
/*
* The following functions provide C bindings to keymaster services
@@ -138,7 +135,6 @@
* The sign_object function signes an object with the given keymaster
* key.
*/
-__BEGIN_DECLS
int keymaster_compatibility_cryptfs_scrypt();
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size,
@@ -156,6 +152,5 @@
uint8_t** signature_buffer,
size_t* signature_buffer_size);
-__END_DECLS
#endif
diff --git a/Loop.cpp b/Loop.cpp
index 6ec5e6d..3736d6a 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -14,8 +14,11 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
#include <stdio.h>
#include <stdlib.h>
+#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@@ -28,213 +31,20 @@
#include <linux/kdev_t.h>
-#define LOG_TAG "Vold"
-
-#include <cutils/log.h>
-
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <utils/Trace.h>
-#include <sysutils/SocketClient.h>
#include "Loop.h"
-#include "Asec.h"
#include "VoldUtil.h"
#include "sehandle.h"
using android::base::StringPrintf;
using android::base::unique_fd;
-int Loop::dumpState(SocketClient *c) {
- int i;
- int fd;
- char filename[256];
-
- for (i = 0; i < LOOP_MAX; i++) {
- struct loop_info64 li;
- int rc;
-
- snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
-
- if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
- if (errno != ENOENT) {
- SLOGE("Unable to open %s (%s)", filename, strerror(errno));
- } else {
- continue;
- }
- return -1;
- }
-
- rc = ioctl(fd, LOOP_GET_STATUS64, &li);
- close(fd);
- if (rc < 0 && errno == ENXIO) {
- continue;
- }
-
- if (rc < 0) {
- SLOGE("Unable to get loop status for %s (%s)", filename,
- strerror(errno));
- return -1;
- }
- char *tmp = NULL;
- asprintf(&tmp, "%s %d %lld:%lld %llu %lld:%lld %lld 0x%x {%s} {%s}", filename, li.lo_number,
- MAJOR(li.lo_device), MINOR(li.lo_device), li.lo_inode, MAJOR(li.lo_rdevice),
- MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_crypt_name,
- li.lo_file_name);
- c->sendMsg(0, tmp, false);
- free(tmp);
- }
- return 0;
-}
-
-int Loop::lookupActive(const char *id, char *buffer, size_t len) {
- int i;
- int fd;
- char filename[256];
-
- memset(buffer, 0, len);
-
- for (i = 0; i < LOOP_MAX; i++) {
- struct loop_info64 li;
- int rc;
-
- snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
-
- if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
- if (errno != ENOENT) {
- SLOGE("Unable to open %s (%s)", filename, strerror(errno));
- } else {
- continue;
- }
- return -1;
- }
-
- rc = ioctl(fd, LOOP_GET_STATUS64, &li);
- if (rc < 0 && errno == ENXIO) {
- close(fd);
- continue;
- }
- close(fd);
-
- if (rc < 0) {
- SLOGE("Unable to get loop status for %s (%s)", filename,
- strerror(errno));
- return -1;
- }
- if (!strncmp((const char*) li.lo_crypt_name, id, LO_NAME_SIZE)) {
- break;
- }
- }
-
- if (i == LOOP_MAX) {
- errno = ENOENT;
- return -1;
- }
- strlcpy(buffer, filename, len);
- return 0;
-}
-
-int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
- int i;
- int fd;
- char filename[256];
-
- for (i = 0; i < LOOP_MAX; i++) {
- struct loop_info64 li;
- int rc;
- char *secontext = NULL;
-
- snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
-
- /*
- * The kernel starts us off with 8 loop nodes, but more
- * are created on-demand if needed.
- */
- mode_t mode = 0660 | S_IFBLK;
- unsigned int dev = (0xff & i) | ((i << 12) & 0xfff00000) | (7 << 8);
-
- if (sehandle) {
- rc = selabel_lookup(sehandle, &secontext, filename, S_IFBLK);
- if (rc == 0)
- setfscreatecon(secontext);
- }
-
- if (mknod(filename, mode, dev) < 0) {
- if (errno != EEXIST) {
- int sverrno = errno;
- SLOGE("Error creating loop device node (%s)", strerror(errno));
- if (secontext) {
- freecon(secontext);
- setfscreatecon(NULL);
- }
- errno = sverrno;
- return -1;
- }
- }
- if (secontext) {
- freecon(secontext);
- setfscreatecon(NULL);
- }
-
- if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Unable to open %s (%s)", filename, strerror(errno));
- return -1;
- }
-
- rc = ioctl(fd, LOOP_GET_STATUS64, &li);
- if (rc < 0 && errno == ENXIO)
- break;
-
- close(fd);
-
- if (rc < 0) {
- SLOGE("Unable to get loop status for %s (%s)", filename,
- strerror(errno));
- return -1;
- }
- }
-
- if (i == LOOP_MAX) {
- SLOGE("Exhausted all loop devices");
- errno = ENOSPC;
- return -1;
- }
-
- strlcpy(loopDeviceBuffer, filename, len);
-
- int file_fd;
-
- if ((file_fd = open(loopFile, O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Unable to open %s (%s)", loopFile, strerror(errno));
- close(fd);
- return -1;
- }
-
- if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
- SLOGE("Error setting up loopback interface (%s)", strerror(errno));
- close(file_fd);
- close(fd);
- return -1;
- }
-
- struct loop_info64 li;
-
- memset(&li, 0, sizeof(li));
- strlcpy((char*) li.lo_crypt_name, id, LO_NAME_SIZE);
- strlcpy((char*) li.lo_file_name, loopFile, LO_NAME_SIZE);
-
- if (ioctl(fd, LOOP_SET_STATUS64, &li) < 0) {
- SLOGE("Error setting loopback status (%s)", strerror(errno));
- close(file_fd);
- close(fd);
- return -1;
- }
-
- close(fd);
- close(file_fd);
-
- return 0;
-}
+static const char* kVoldPrefix = "vold:";
int Loop::create(const std::string& target, std::string& out_device) {
unique_fd ctl_fd(open("/dev/loop-control", O_RDWR | O_CLOEXEC));
@@ -267,6 +77,14 @@
return -errno;
}
+ struct loop_info64 li;
+ memset(&li, 0, sizeof(li));
+ strlcpy((char*) li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
+ if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
+ PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
+ return -errno;
+ }
+
return 0;
}
@@ -275,12 +93,12 @@
device_fd = open(loopDevice, O_RDONLY | O_CLOEXEC);
if (device_fd < 0) {
- SLOGE("Failed to open loop (%d)", errno);
+ PLOG(ERROR) << "Failed to open " << loopDevice;
return -1;
}
if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
- SLOGE("Failed to destroy loop (%d)", errno);
+ PLOG(ERROR) << "Failed to destroy " << loopDevice;
close(device_fd);
return -1;
}
@@ -289,9 +107,52 @@
return 0;
}
-int Loop::destroyByFile(const char * /*loopFile*/) {
- errno = ENOSYS;
- return -1;
+int Loop::destroyAll() {
+ ATRACE_NAME("Loop::destroyAll");
+
+ DIR* dir;
+ struct dirent* de;
+
+ std::string root = "/dev/block/";
+ if (!(dir = opendir(root.c_str()))) {
+ PLOG(ERROR) << "Failed to opendir";
+ return -1;
+ }
+
+ // Poke through all devices looking for loops
+ while ((de = readdir(dir))) {
+ auto test = std::string(de->d_name);
+ if (!android::base::StartsWith(test, "loop")) continue;
+
+ auto path = root + de->d_name;
+ unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC));
+ if (fd.get() == -1) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Failed to open " << path;
+ }
+ continue;
+ }
+
+ struct loop_info64 li;
+ if (ioctl(fd.get(), LOOP_GET_STATUS64, &li) < 0) {
+ PLOG(WARNING) << "Failed to LOOP_GET_STATUS64 " << path;
+ continue;
+ }
+
+ auto id = std::string((char*) li.lo_crypt_name);
+ if (android::base::StartsWith(id, kVoldPrefix)) {
+ LOG(DEBUG) << "Tearing down stale loop device at " << path << " named " << id;
+
+ if (ioctl(fd.get(), LOOP_CLR_FD, 0) < 0) {
+ PLOG(WARNING) << "Failed to LOOP_CLR_FD " << path;
+ }
+ } else {
+ LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id;
+ }
+ }
+
+ closedir(dir);
+ return 0;
}
int Loop::createImageFile(const char *file, unsigned long numSectors) {
@@ -314,22 +175,22 @@
int fd;
if ((fd = open(file, O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Error opening imagefile (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed to open " << file;
return -1;
}
- SLOGD("Attempting to increase size of %s to %lu sectors.", file, numSectors);
+ LOG(DEBUG) << "Attempting to increase " << file << " to " << numSectors;
if (fallocate(fd, 0, 0, numSectors * 512)) {
if (errno == ENOSYS || errno == ENOTSUP) {
- SLOGW("fallocate not found. Falling back to ftruncate.");
+ PLOG(WARNING) << "fallocate not found. Falling back to ftruncate.";
if (ftruncate(fd, numSectors * 512) < 0) {
- SLOGE("Error truncating imagefile (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed to ftruncate";
close(fd);
return -1;
}
} else {
- SLOGE("Error allocating space (%s)", strerror(errno));
+ PLOG(ERROR) << "Failed to fallocate";
close(fd);
return -1;
}
@@ -337,46 +198,3 @@
close(fd);
return 0;
}
-
-int Loop::lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned long *nr_sec) {
- int fd;
- struct asec_superblock buffer;
-
- if ((fd = open(loopDevice, O_RDONLY | O_CLOEXEC)) < 0) {
- SLOGE("Failed to open loopdevice (%s)", strerror(errno));
- destroyByDevice(loopDevice);
- return -1;
- }
-
- get_blkdev_size(fd, nr_sec);
- if (*nr_sec == 0) {
- SLOGE("Failed to get loop size (%s)", strerror(errno));
- destroyByDevice(loopDevice);
- close(fd);
- return -1;
- }
-
- /*
- * Try to read superblock.
- */
- memset(&buffer, 0, sizeof(struct asec_superblock));
- if (lseek(fd, ((*nr_sec - 1) * 512), SEEK_SET) < 0) {
- SLOGE("lseek failed (%s)", strerror(errno));
- close(fd);
- destroyByDevice(loopDevice);
- return -1;
- }
- if (read(fd, &buffer, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
- SLOGE("superblock read failed (%s)", strerror(errno));
- close(fd);
- destroyByDevice(loopDevice);
- return -1;
- }
- close(fd);
-
- /*
- * Superblock successfully read. Copy to caller's struct.
- */
- memcpy(sb, &buffer, sizeof(struct asec_superblock));
- return 0;
-}
diff --git a/Loop.h b/Loop.h
index 5d8f427..130c5b6 100644
--- a/Loop.h
+++ b/Loop.h
@@ -21,22 +21,15 @@
#include <unistd.h>
#include <linux/loop.h>
-class SocketClient;
-
class Loop {
public:
static const int LOOP_MAX = 4096;
public:
- static int lookupActive(const char *id, char *buffer, size_t len);
- static int lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned long *nr_sec);
- static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
static int create(const std::string& file, std::string& out_device);
static int destroyByDevice(const char *loopDevice);
- static int destroyByFile(const char *loopFile);
+ static int destroyAll();
static int createImageFile(const char *file, unsigned long numSectors);
static int resizeImageFile(const char *file, unsigned long numSectors);
-
- static int dumpState(SocketClient *c);
};
#endif
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index 8311813..24047f9 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -42,7 +42,6 @@
#include "Utils.h"
#include "VoldUtil.h"
-extern struct fstab *fstab;
#define DM_CRYPT_BUF_SIZE 4096
#define TABLE_LOAD_RETRIES 10
#define DEFAULT_KEY_TARGET_TYPE "default-key"
@@ -58,7 +57,7 @@
PLOG(ERROR) << "Failed to setexeccon";
return false;
}
- auto mount_rc = fs_mgr_do_mount(fstab, const_cast<char*>(mount_point),
+ auto mount_rc = fs_mgr_do_mount(fstab_default, const_cast<char*>(mount_point),
const_cast<char*>(blk_device), nullptr);
if (setexeccon(nullptr)) {
PLOG(ERROR) << "Failed to clear setexeccon";
@@ -73,7 +72,7 @@
}
static bool read_key(bool create_if_absent, KeyBuffer* key) {
- auto data_rec = fs_mgr_get_crypt_entry(fstab);
+ auto data_rec = fs_mgr_get_crypt_entry(fstab_default);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
@@ -253,7 +252,7 @@
LOG(DEBUG) << "e4crypt_mount_default_encrypted";
KeyBuffer key;
if (!read_key(false, &key)) return false;
- auto data_rec = fs_mgr_get_crypt_entry(fstab);
+ auto data_rec = fs_mgr_get_crypt_entry(fstab_default);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
@@ -283,7 +282,7 @@
KeyBuffer key_ref;
if (!read_key(true, &key_ref)) return false;
- auto data_rec = fs_mgr_get_crypt_entry(fstab);
+ auto data_rec = fs_mgr_get_crypt_entry(fstab_default);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
diff --git a/MoveTask.cpp b/MoveStorage.cpp
similarity index 76%
rename from MoveTask.cpp
rename to MoveStorage.cpp
index c565752..4f5ebe8 100644
--- a/MoveTask.cpp
+++ b/MoveStorage.cpp
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-#include "MoveTask.h"
+#include "MoveStorage.h"
#include "Utils.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
+#include <thread>
+
#include <dirent.h>
#include <sys/wait.h>
@@ -45,21 +46,12 @@
static const char* kWakeLock = "MoveTask";
-MoveTask::MoveTask(const std::shared_ptr<VolumeBase>& from,
- const std::shared_ptr<VolumeBase>& to) :
- mFrom(from), mTo(to) {
-}
-
-MoveTask::~MoveTask() {
-}
-
-void MoveTask::start() {
- mThread = std::thread(&MoveTask::run, this);
-}
-
-static void notifyProgress(int progress) {
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(ResponseCode::MoveStatus,
- StringPrintf("%d", progress).c_str(), false);
+static void notifyProgress(int progress,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
+ if (listener) {
+ android::os::PersistableBundle extras;
+ listener->onStatus(progress, extras);
+ }
}
static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
@@ -85,8 +77,9 @@
return found ? OK : -1;
}
-static status_t execRm(const std::string& path, int startProgress, int stepProgress) {
- notifyProgress(startProgress);
+static status_t execRm(const std::string& path, int startProgress, int stepProgress,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
+ notifyProgress(startProgress, listener);
uint64_t expectedBytes = GetTreeBytes(path);
uint64_t startFreeBytes = GetFreeBytes(path);
@@ -120,15 +113,15 @@
sleep(1);
uint64_t deltaFreeBytes = GetFreeBytes(path) - startFreeBytes;
notifyProgress(startProgress + CONSTRAIN((int)
- ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress));
+ ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
}
return -1;
#endif
}
-static status_t execCp(const std::string& fromPath, const std::string& toPath,
- int startProgress, int stepProgress) {
- notifyProgress(startProgress);
+static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress,
+ int stepProgress, const android::sp<android::os::IVoldTaskListener>& listener) {
+ notifyProgress(startProgress, listener);
uint64_t expectedBytes = GetTreeBytes(fromPath);
uint64_t startFreeBytes = GetFreeBytes(toPath);
@@ -171,7 +164,7 @@
sleep(1);
uint64_t deltaFreeBytes = startFreeBytes - GetFreeBytes(toPath);
notifyProgress(startProgress + CONSTRAIN((int)
- ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress));
+ ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
}
return -1;
#endif
@@ -191,69 +184,80 @@
vol->create();
}
-void MoveTask::run() {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
-
+static status_t moveStorageInternal(const std::shared_ptr<VolumeBase>& from,
+ const std::shared_ptr<VolumeBase>& to,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
std::string fromPath;
std::string toPath;
// TODO: add support for public volumes
- if (mFrom->getType() != VolumeBase::Type::kEmulated) goto fail;
- if (mTo->getType() != VolumeBase::Type::kEmulated) goto fail;
+ if (from->getType() != VolumeBase::Type::kEmulated) goto fail;
+ if (to->getType() != VolumeBase::Type::kEmulated) goto fail;
// Step 1: tear down volumes and mount silently without making
// visible to userspace apps
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
- bringOffline(mFrom);
- bringOffline(mTo);
+ bringOffline(from);
+ bringOffline(to);
}
- fromPath = mFrom->getInternalPath();
- toPath = mTo->getInternalPath();
+ fromPath = from->getInternalPath();
+ toPath = to->getInternalPath();
// Step 2: clean up any stale data
- if (execRm(toPath, 10, 10) != OK) {
+ if (execRm(toPath, 10, 10, listener) != OK) {
goto fail;
}
// Step 3: perform actual copy
- if (execCp(fromPath, toPath, 20, 60) != OK) {
+ if (execCp(fromPath, toPath, 20, 60, listener) != OK) {
goto copy_fail;
}
// NOTE: MountService watches for this magic value to know
// that move was successful
- notifyProgress(82);
+ notifyProgress(82, listener);
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
- bringOnline(mFrom);
- bringOnline(mTo);
+ bringOnline(from);
+ bringOnline(to);
}
// Step 4: clean up old data
- if (execRm(fromPath, 85, 15) != OK) {
+ if (execRm(fromPath, 85, 15, listener) != OK) {
goto fail;
}
- notifyProgress(kMoveSucceeded);
- release_wake_lock(kWakeLock);
- return;
+ notifyProgress(kMoveSucceeded, listener);
+ return OK;
copy_fail:
// if we failed to copy the data we should not leave it laying around
// in target location. Do not check return value, we can not do any
// useful anyway.
- execRm(toPath, 80, 1);
+ execRm(toPath, 80, 1, listener);
fail:
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
- bringOnline(mFrom);
- bringOnline(mTo);
+ bringOnline(from);
+ bringOnline(to);
}
- notifyProgress(kMoveFailedInternalError);
+ notifyProgress(kMoveFailedInternalError, listener);
+ return -1;
+}
+
+void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
+
+ android::os::PersistableBundle extras;
+ status_t res = moveStorageInternal(from, to, listener);
+ if (listener) {
+ listener->onFinished(res, extras);
+ }
+
release_wake_lock(kWakeLock);
- return;
}
} // namespace vold
diff --git a/MoveTask.h b/MoveStorage.h
similarity index 60%
rename from MoveTask.h
rename to MoveStorage.h
index b1777c0..d271704 100644
--- a/MoveTask.h
+++ b/MoveStorage.h
@@ -14,33 +14,17 @@
* limitations under the License.
*/
-#ifndef ANDROID_VOLD_MOVE_TASK_H
-#define ANDROID_VOLD_MOVE_TASK_H
+#ifndef ANDROID_VOLD_MOVE_STORAGE_H
+#define ANDROID_VOLD_MOVE_STORAGE_H
-#include "Utils.h"
-#include "VolumeBase.h"
-
-#include <thread>
+#include "android/os/IVoldTaskListener.h"
+#include "model/VolumeBase.h"
namespace android {
namespace vold {
-class MoveTask {
-public:
- MoveTask(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to);
- virtual ~MoveTask();
-
- void start();
-
-private:
- std::shared_ptr<VolumeBase> mFrom;
- std::shared_ptr<VolumeBase> mTo;
- std::thread mThread;
-
- void run();
-
- DISALLOW_COPY_AND_ASSIGN(MoveTask);
-};
+void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
+ const android::sp<android::os::IVoldTaskListener>& listener);
} // namespace vold
} // namespace android
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index ecda2a0..92131e9 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -19,9 +19,7 @@
#include <errno.h>
#include <string.h>
-#define LOG_TAG "Vold"
-
-#include <cutils/log.h>
+#include <android-base/logging.h>
#include <sysutils/NetlinkEvent.h>
#include "NetlinkHandler.h"
@@ -47,11 +45,11 @@
const char *subsys = evt->getSubsystem();
if (!subsys) {
- SLOGW("No subsystem found in netlink event");
+ LOG(WARNING) << "No subsystem found in netlink event";
return;
}
- if (!strcmp(subsys, "block")) {
+ if (std::string(subsys) == "block") {
vm->handleBlockEvent(evt);
}
}
diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp
index 90e3c6c..409cdc8 100644
--- a/NetlinkManager.cpp
+++ b/NetlinkManager.cpp
@@ -26,9 +26,7 @@
#include <linux/netlink.h>
-#define LOG_TAG "Vold"
-
-#include <cutils/log.h>
+#include <android-base/logging.h>
#include "NetlinkManager.h"
#include "NetlinkHandler.h"
@@ -60,7 +58,7 @@
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
- SLOGE("Unable to create uevent socket: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to create uevent socket";
return -1;
}
@@ -69,23 +67,23 @@
// Try using SO_RCVBUF if that fails.
if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
(setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
- SLOGE("Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
goto out;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- SLOGE("Unable to bind uevent socket: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to bind uevent socket";
goto out;
}
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
- SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to start NetlinkHandler";
goto out;
}
@@ -100,7 +98,7 @@
int status = 0;
if (mHandler->stop()) {
- SLOGE("Unable to stop NetlinkHandler: %s", strerror(errno));
+ PLOG(ERROR) << "Unable to stop NetlinkHandler";
status = -1;
}
delete mHandler;
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..c8dbf77
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,5 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
diff --git a/Process.cpp b/Process.cpp
index 1c0f504..042ba2d 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <string.h>
#include <fcntl.h>
+#include <fts.h>
#include <dirent.h>
#include <ctype.h>
#include <pwd.h>
@@ -27,196 +28,98 @@
#include <sys/stat.h>
#include <signal.h>
-#define LOG_TAG "ProcessKiller"
+#include <fstream>
+#include <unordered_set>
#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
-#include <cutils/log.h>
#include "Process.h"
-using android::base::ReadFileToString;
using android::base::StringPrintf;
-int Process::readSymLink(const char *path, char *link, size_t max) {
- struct stat s;
- int length;
+namespace android {
+namespace vold {
- if (lstat(path, &s) < 0)
- return 0;
- if ((s.st_mode & S_IFMT) != S_IFLNK)
- return 0;
-
- // we have a symlink
- length = readlink(path, link, max- 1);
- if (length <= 0)
- return 0;
- link[length] = 0;
- return 1;
-}
-
-int Process::pathMatchesMountPoint(const char* path, const char* mountPoint) {
- int length = strlen(mountPoint);
- if (length > 1 && strncmp(path, mountPoint, length) == 0) {
- // we need to do extra checking if mountPoint does not end in a '/'
- if (mountPoint[length - 1] == '/')
- return 1;
- // if mountPoint does not have a trailing slash, we need to make sure
- // there is one in the path to avoid partial matches.
- return (path[length] == 0 || path[length] == '/');
- }
-
- return 0;
-}
-
-void Process::getProcessName(int pid, std::string& out_name) {
- if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &out_name)) {
- out_name = "???";
- }
-}
-
-int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint) {
- return checkFileDescriptorSymLinks(pid, mountPoint, NULL, 0);
-}
-
-int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max) {
-
-
- // compute path to process's directory of open files
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "/proc/%d/fd", pid);
- DIR *dir = opendir(path);
- if (!dir)
- return 0;
-
- // remember length of the path
- int parent_length = strlen(path);
- // append a trailing '/'
- path[parent_length++] = '/';
-
- struct dirent* de;
- while ((de = readdir(dir))) {
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")
- || strlen(de->d_name) + parent_length + 1 >= PATH_MAX)
- continue;
-
- // append the file name, after truncating to parent directory
- path[parent_length] = 0;
- strlcat(path, de->d_name, PATH_MAX);
-
- char link[PATH_MAX];
-
- if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) {
- if (openFilename) {
- memset(openFilename, 0, max);
- strlcpy(openFilename, link, max);
+static bool checkMaps(const std::string& path, const std::string& prefix) {
+ bool found = false;
+ std::ifstream infile(path);
+ std::string line;
+ while (std::getline(infile, line)) {
+ std::string::size_type pos = line.find('/');
+ if (pos != std::string::npos) {
+ line = line.substr(pos);
+ if (android::base::StartsWith(line, prefix.c_str())) {
+ LOG(WARNING) << "Found map " << path << " referencing " << line;
+ found = true;
}
- closedir(dir);
- return 1;
}
}
-
- closedir(dir);
- return 0;
+ return found;
}
-int Process::checkFileMaps(int pid, const char *mountPoint) {
- return checkFileMaps(pid, mountPoint, NULL, 0);
-}
-
-int Process::checkFileMaps(int pid, const char *mountPoint, char *openFilename, size_t max) {
- FILE *file;
- char buffer[PATH_MAX + 100];
-
- snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
- file = fopen(buffer, "re");
- if (!file)
- return 0;
-
- while (fgets(buffer, sizeof(buffer), file)) {
- // skip to the path
- const char* path = strchr(buffer, '/');
- if (path && pathMatchesMountPoint(path, mountPoint)) {
- if (openFilename) {
- memset(openFilename, 0, max);
- strlcpy(openFilename, path, max);
- }
- fclose(file);
- return 1;
+static bool checkSymlink(const std::string& path, const std::string& prefix) {
+ std::string res;
+ if (android::base::Readlink(path, &res)) {
+ if (android::base::StartsWith(res, prefix.c_str())) {
+ LOG(WARNING) << "Found symlink " << path << " referencing " << res;
+ return true;
}
}
-
- fclose(file);
- return 0;
+ return false;
}
-int Process::checkSymLink(int pid, const char *mountPoint, const char *name) {
- char path[PATH_MAX];
- char link[PATH_MAX];
+int KillProcessesWithOpenFiles(const std::string& prefix, int signal) {
+ std::unordered_set<pid_t> pids;
- snprintf(path, sizeof(path), "/proc/%d/%s", pid, name);
- if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint))
- return 1;
- return 0;
-}
-
-int Process::getPid(const char *s) {
- int result = 0;
- while (*s) {
- if (!isdigit(*s)) return -1;
- result = 10 * result + (*s++ - '0');
- }
- return result;
-}
-
-extern "C" void vold_killProcessesWithOpenFiles(const char *path, int signal) {
- Process::killProcessesWithOpenFiles(path, signal);
-}
-
-/*
- * Hunt down processes that have files open at the given mount point.
- */
-int Process::killProcessesWithOpenFiles(const char *path, int signal) {
- int count = 0;
- DIR* dir;
- struct dirent* de;
-
- if (!(dir = opendir("/proc"))) {
- SLOGE("opendir failed (%s)", strerror(errno));
- return count;
+ auto proc_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/proc"), closedir);
+ if (!proc_d) {
+ PLOG(ERROR) << "Failed to open proc";
+ return -1;
}
- while ((de = readdir(dir))) {
- int pid = getPid(de->d_name);
- if (pid == -1)
- continue;
+ struct dirent* proc_de;
+ while ((proc_de = readdir(proc_d.get())) != nullptr) {
+ // We only care about valid PIDs
+ pid_t pid;
+ if (proc_de->d_type != DT_DIR) continue;
+ if (!android::base::ParseInt(proc_de->d_name, &pid)) continue;
- std::string name;
- getProcessName(pid, name);
+ // Look for references to prefix
+ bool found = false;
+ auto path = StringPrintf("/proc/%d", pid);
+ found |= checkMaps(path + "/maps", prefix);
+ found |= checkSymlink(path + "/cwd", prefix);
+ found |= checkSymlink(path + "/root", prefix);
+ found |= checkSymlink(path + "/exe", prefix);
- char openfile[PATH_MAX];
-
- if (checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
- SLOGE("Process %s (%d) has open file %s", name.c_str(), pid, openfile);
- } else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
- SLOGE("Process %s (%d) has open filemap for %s", name.c_str(), pid, openfile);
- } else if (checkSymLink(pid, path, "cwd")) {
- SLOGE("Process %s (%d) has cwd within %s", name.c_str(), pid, path);
- } else if (checkSymLink(pid, path, "root")) {
- SLOGE("Process %s (%d) has chroot within %s", name.c_str(), pid, path);
- } else if (checkSymLink(pid, path, "exe")) {
- SLOGE("Process %s (%d) has executable path within %s", name.c_str(), pid, path);
+ auto fd_path = path + "/fd";
+ auto fd_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(fd_path.c_str()), closedir);
+ if (!fd_d) {
+ PLOG(WARNING) << "Failed to open " << fd_path;
} else {
- continue;
+ struct dirent* fd_de;
+ while ((fd_de = readdir(fd_d.get())) != nullptr) {
+ if (fd_de->d_type != DT_LNK) continue;
+ found |= checkSymlink(fd_path + "/" + fd_de->d_name, prefix);
+ }
}
- if (signal != 0) {
- SLOGW("Sending %s to process %d", strsignal(signal), pid);
- kill(pid, signal);
- count++;
+ if (found) {
+ pids.insert(pid);
}
}
- closedir(dir);
- return count;
+ if (signal != 0) {
+ for (const auto& pid : pids) {
+ LOG(WARNING) << "Sending " << strsignal(signal) << " to " << pid;
+ kill(pid, signal);
+ }
+ }
+ return pids.size();
}
+
+} // namespace vold
+} // namespace android
diff --git a/Process.h b/Process.h
index 4ddbdb9..1406782 100644
--- a/Process.h
+++ b/Process.h
@@ -17,28 +17,12 @@
#ifndef _PROCESS_H
#define _PROCESS_H
-#ifdef __cplusplus
+namespace android {
+namespace vold {
-class Process {
-public:
- static int killProcessesWithOpenFiles(const char *path, int signal);
- static int getPid(const char *s);
- static int checkSymLink(int pid, const char *path, const char *name);
- static int checkFileMaps(int pid, const char *path);
- static int checkFileMaps(int pid, const char *path, char *openFilename, size_t max);
- static int checkFileDescriptorSymLinks(int pid, const char *mountPoint);
- static int checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max);
- static void getProcessName(int pid, std::string& out_name);
-private:
- static int readSymLink(const char *path, char *link, size_t max);
- static int pathMatchesMountPoint(const char *path, const char *mountPoint);
-};
+int KillProcessesWithOpenFiles(const std::string& path, int signal);
-extern "C" {
-#endif /* __cplusplus */
- void vold_killProcessesWithOpenFiles(const char *path, int signal);
-#ifdef __cplusplus
-}
-#endif
+} // namespace vold
+} // namespace android
#endif
diff --git a/ResponseCode.cpp b/ResponseCode.cpp
deleted file mode 100644
index d7e778d..0000000
--- a/ResponseCode.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <errno.h>
-#include <string.h>
-
-#define LOG_TAG "Vold"
-
-#include <cutils/log.h>
-
-#include "ResponseCode.h"
-
-int ResponseCode::convertFromErrno() {
- if (errno == ENODEV) {
- return(ResponseCode::OpFailedNoMedia);
- } else if (errno == ENODATA) {
- return(ResponseCode::OpFailedMediaBlank);
- } else if (errno == EIO) {
- return(ResponseCode::OpFailedMediaCorrupt);
- } else if (errno == EBUSY) {
- return(ResponseCode::OpFailedStorageBusy);
- } else if (errno == ENOENT) {
- return(ResponseCode::OpFailedStorageNotFound);
- }
-
- SLOGW("Returning OperationFailed - no handler for errno %d", errno);
- return(ResponseCode::OperationFailed);
-}
diff --git a/ResponseCode.h b/ResponseCode.h
deleted file mode 100644
index f2c533e..0000000
--- a/ResponseCode.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _RESPONSECODE_H
-#define _RESPONSECODE_H
-
-class ResponseCode {
-public:
- // 100 series - Requestion action was initiated; expect another reply
- // before proceeding with a new command.
- static const int ActionInitiated = 100;
-
- static const int VolumeListResult = 110;
- static const int AsecListResult = 111;
- static const int StorageUsersListResult = 112;
- static const int CryptfsGetfieldResult = 113;
-
- // 200 series - Requested action has been successfully completed
- static const int CommandOkay = 200;
- static const int ShareStatusResult = 210;
- static const int AsecPathResult = 211;
- static const int ShareEnabledResult = 212;
- static const int PasswordTypeResult = 213;
-
- // 400 series - The command was accepted but the requested action
- // did not take place.
- static const int OperationFailed = 400;
- static const int OpFailedNoMedia = 401;
- static const int OpFailedMediaBlank = 402;
- static const int OpFailedMediaCorrupt = 403;
- static const int OpFailedVolNotMounted = 404;
- static const int OpFailedStorageBusy = 405;
- static const int OpFailedStorageNotFound = 406;
-
- // 500 series - The command was not accepted and the requested
- // action did not take place.
- static const int CommandSyntaxError = 500;
- static const int CommandParameterError = 501;
- static const int CommandNoPermission = 502;
-
- // 600 series - Unsolicited broadcasts
- static const int UnsolicitedInformational = 600;
- static const int VolumeStateChange = 605;
- static const int VolumeMountFailedBlank = 610;
- static const int VolumeMountFailedDamaged = 611;
- static const int VolumeMountFailedNoMedia = 612;
- static const int VolumeUuidChange = 613;
- static const int VolumeUserLabelChange = 614;
-
- static const int ShareAvailabilityChange = 620;
-
- static const int VolumeDiskInserted = 630;
- static const int VolumeDiskRemoved = 631;
- static const int VolumeBadRemoval = 632;
-
- static const int DiskCreated = 640;
- static const int DiskSizeChanged = 641;
- static const int DiskLabelChanged = 642;
- static const int DiskScanned = 643;
- static const int DiskSysPathChanged = 644;
- static const int DiskDestroyed = 649;
-
- static const int VolumeCreated = 650;
- static const int VolumeStateChanged = 651;
- static const int VolumeFsTypeChanged = 652;
- static const int VolumeFsUuidChanged = 653;
- static const int VolumeFsLabelChanged = 654;
- static const int VolumePathChanged = 655;
- static const int VolumeInternalPathChanged = 656;
- static const int VolumeDestroyed = 659;
-
- static const int MoveStatus = 660;
- static const int BenchmarkResult = 661;
- static const int TrimResult = 662;
-
- static int convertFromErrno();
-};
-#endif
diff --git a/ScryptParameters.h b/ScryptParameters.h
index 1b43ea5..190842b 100644
--- a/ScryptParameters.h
+++ b/ScryptParameters.h
@@ -23,10 +23,6 @@
#define SCRYPT_PROP "ro.crypto.scrypt_params"
#define SCRYPT_DEFAULTS "15:3:1"
-__BEGIN_DECLS
-
bool parse_scrypt_parameters(const char* paramstr, int *Nf, int *rf, int *pf);
-__END_DECLS
-
#endif
diff --git a/TrimTask.h b/TrimTask.h
deleted file mode 100644
index 2ade7b5..0000000
--- a/TrimTask.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef ANDROID_VOLD_TRIM_TASK_H
-#define ANDROID_VOLD_TRIM_TASK_H
-
-#include "Utils.h"
-
-#include <thread>
-#include <list>
-
-namespace android {
-namespace vold {
-
-class TrimTask {
-public:
- explicit TrimTask(int flags);
- virtual ~TrimTask();
-
- enum Flags {
- kDeepTrim = 1 << 0,
- kBenchmarkAfter = 1 << 1,
- };
-
- void start();
-
-private:
- int mFlags;
- std::list<std::string> mPaths;
- std::thread mThread;
-
- void addFromFstab();
- void run();
-
- DISALLOW_COPY_AND_ASSIGN(TrimTask);
-};
-
-} // namespace vold
-} // namespace android
-
-#endif
diff --git a/Utils.cpp b/Utils.cpp
index b6c7bf8..38edcb3 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-#include "sehandle.h"
#include "Utils.h"
+
#include "Process.h"
-#include "VolumeManager.h"
+#include "sehandle.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <logwrap/logwrap.h>
@@ -54,12 +55,19 @@
security_context_t sFsckContext = nullptr;
security_context_t sFsckUntrustedContext = nullptr;
+bool sSleepOnUnmount = true;
+
static const char* kBlkidPath = "/system/bin/blkid";
static const char* kKeyPath = "/data/misc/vold";
static const char* kProcFilesystems = "/proc/filesystems";
+// Lock used to protect process-level SELinux changes from racing with each
+// other between multiple threads.
+static std::mutex kSecurityLock;
+
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
+ std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
status_t res = 0;
@@ -97,6 +105,7 @@
}
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+ std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
char* secontext = nullptr;
@@ -127,22 +136,22 @@
}
// Apps might still be handling eject request, so wait before
// we start sending signals
- if (!VolumeManager::shutting_down) sleep(5);
+ if (sSleepOnUnmount) sleep(5);
- Process::killProcessesWithOpenFiles(cpath, SIGINT);
- if (!VolumeManager::shutting_down) sleep(5);
+ KillProcessesWithOpenFiles(path, SIGINT);
+ if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
- Process::killProcessesWithOpenFiles(cpath, SIGTERM);
- if (!VolumeManager::shutting_down) sleep(5);
+ KillProcessesWithOpenFiles(path, SIGTERM);
+ if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
- Process::killProcessesWithOpenFiles(cpath, SIGKILL);
- if (!VolumeManager::shutting_down) sleep(5);
+ KillProcessesWithOpenFiles(path, SIGKILL);
+ if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
@@ -151,25 +160,24 @@
}
status_t KillProcessesUsingPath(const std::string& path) {
- const char* cpath = path.c_str();
- if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) {
+ if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
return OK;
}
- if (!VolumeManager::shutting_down) sleep(5);
+ if (sSleepOnUnmount) sleep(5);
- if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) {
+ if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) {
return OK;
}
- if (!VolumeManager::shutting_down) sleep(5);
+ if (sSleepOnUnmount) sleep(5);
- if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
+ if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
return OK;
}
- if (!VolumeManager::shutting_down) sleep(5);
+ if (sSleepOnUnmount) sleep(5);
// Send SIGKILL a second time to determine if we've
// actually killed everyone with open files
- if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
+ if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
return OK;
}
PLOG(ERROR) << "Failed to kill processes using " << path;
@@ -184,11 +192,28 @@
return OK;
}
-static status_t readMetadata(const std::string& path, std::string& fsType,
- std::string& fsUuid, std::string& fsLabel, bool untrusted) {
- fsType.clear();
- fsUuid.clear();
- fsLabel.clear();
+bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
+ auto qual = key + "=\"";
+ auto start = raw.find(qual);
+ if (start > 0 && raw[start - 1] != ' ') {
+ start = raw.find(qual, start + 1);
+ }
+
+ if (start == std::string::npos) return false;
+ start += qual.length();
+
+ auto end = raw.find("\"", start);
+ if (end == std::string::npos) return false;
+
+ *value = raw.substr(start, end - start);
+ return true;
+}
+
+static status_t readMetadata(const std::string& path, std::string* fsType,
+ std::string* fsUuid, std::string* fsLabel, bool untrusted) {
+ fsType->clear();
+ fsUuid->clear();
+ fsLabel->clear();
std::vector<std::string> cmd;
cmd.push_back(kBlkidPath);
@@ -209,36 +234,23 @@
return res;
}
- char value[128];
for (const auto& line : output) {
// Extract values from blkid output, if defined
- const char* cline = line.c_str();
- const char* start = strstr(cline, "TYPE=");
- if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
- fsType = value;
- }
-
- start = strstr(cline, "UUID=");
- if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
- fsUuid = value;
- }
-
- start = strstr(cline, "LABEL=");
- if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
- fsLabel = value;
- }
+ FindValue(line, "TYPE", fsType);
+ FindValue(line, "UUID", fsUuid);
+ FindValue(line, "LABEL", fsLabel);
}
return OK;
}
-status_t ReadMetadata(const std::string& path, std::string& fsType,
- std::string& fsUuid, std::string& fsLabel) {
+status_t ReadMetadata(const std::string& path, std::string* fsType,
+ std::string* fsUuid, std::string* fsLabel) {
return readMetadata(path, fsType, fsUuid, fsLabel, false);
}
-status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
- std::string& fsUuid, std::string& fsLabel) {
+status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType,
+ std::string* fsUuid, std::string* fsLabel) {
return readMetadata(path, fsType, fsUuid, fsLabel, true);
}
@@ -247,6 +259,7 @@
}
status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
+ std::lock_guard<std::mutex> lock(kSecurityLock);
size_t argc = args.size();
char** argv = (char**) calloc(argc, sizeof(char*));
for (size_t i = 0; i < argc; i++) {
@@ -258,14 +271,18 @@
}
}
- if (setexeccon(context)) {
- LOG(ERROR) << "Failed to setexeccon";
- abort();
+ if (context) {
+ if (setexeccon(context)) {
+ LOG(ERROR) << "Failed to setexeccon";
+ abort();
+ }
}
status_t res = android_fork_execvp(argc, argv, NULL, false, true);
- if (setexeccon(nullptr)) {
- LOG(ERROR) << "Failed to setexeccon";
- abort();
+ if (context) {
+ if (setexeccon(nullptr)) {
+ LOG(ERROR) << "Failed to setexeccon";
+ abort();
+ }
}
free(argv);
@@ -279,6 +296,7 @@
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output, security_context_t context) {
+ std::lock_guard<std::mutex> lock(kSecurityLock);
std::string cmd;
for (size_t i = 0; i < args.size(); i++) {
cmd += args[i] + " ";
@@ -290,14 +308,18 @@
}
output.clear();
- if (setexeccon(context)) {
- LOG(ERROR) << "Failed to setexeccon";
- abort();
+ if (context) {
+ if (setexeccon(context)) {
+ LOG(ERROR) << "Failed to setexeccon";
+ abort();
+ }
}
FILE* fp = popen(cmd.c_str(), "r"); // NOLINT
- if (setexeccon(nullptr)) {
- LOG(ERROR) << "Failed to setexeccon";
- abort();
+ if (context) {
+ if (setexeccon(nullptr)) {
+ LOG(ERROR) << "Failed to setexeccon";
+ abort();
+ }
}
if (!fp) {
@@ -585,54 +607,54 @@
}
std::string BuildDataSystemLegacyPath(userid_t userId) {
- return StringPrintf("%s/system/users/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/system/users/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataSystemCePath(userid_t userId) {
- return StringPrintf("%s/system_ce/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/system_ce/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataSystemDePath(userid_t userId) {
- return StringPrintf("%s/system_de/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/system_de/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscLegacyPath(userid_t userId) {
- return StringPrintf("%s/misc/user/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/misc/user/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscCePath(userid_t userId) {
- return StringPrintf("%s/misc_ce/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/misc_ce/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscDePath(userid_t userId) {
- return StringPrintf("%s/misc_de/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/misc_de/%u", BuildDataPath("").c_str(), userId);
}
// Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
std::string BuildDataProfilesDePath(userid_t userId) {
- return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath(nullptr).c_str(), userId);
+ return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath("").c_str(), userId);
}
-std::string BuildDataPath(const char* volumeUuid) {
+std::string BuildDataPath(const std::string& volumeUuid) {
// TODO: unify with installd path generation logic
- if (volumeUuid == nullptr) {
+ if (volumeUuid.empty()) {
return "/data";
} else {
CHECK(isValidFilename(volumeUuid));
- return StringPrintf("/mnt/expand/%s", volumeUuid);
+ return StringPrintf("/mnt/expand/%s", volumeUuid.c_str());
}
}
-std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userId) {
+std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/media/%u", data.c_str(), userId);
}
-std::string BuildDataUserCePath(const char* volumeUuid, userid_t userId) {
+std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
- if (volumeUuid == nullptr && userId == 0) {
+ if (volumeUuid.empty() && userId == 0) {
std::string legacy = StringPrintf("%s/data", data.c_str());
struct stat sb;
if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
@@ -643,7 +665,7 @@
return StringPrintf("%s/user/%u", data.c_str(), userId);
}
-std::string BuildDataUserDePath(const char* volumeUuid, userid_t userId) {
+std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/user_de/%u", data.c_str(), userId);
@@ -673,15 +695,27 @@
return OK;
}
-status_t SaneReadLinkAt(int dirfd, const char* path, char* buf, size_t bufsiz) {
- ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
- if (len < 0) {
- return -1;
- } else if (len == (ssize_t) bufsiz) {
- return -1;
- } else {
- buf[len] = '\0';
- return 0;
+bool Readlinkat(int dirfd, const std::string& path, std::string* result) {
+ // Shamelessly borrowed from android::base::Readlink()
+ result->clear();
+
+ // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
+ // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
+ // waste memory to just start there. We add 1 so that we can recognize
+ // whether it actually fit (rather than being truncated to 4095).
+ std::vector<char> buf(4095 + 1);
+ while (true) {
+ ssize_t size = readlinkat(dirfd, path.c_str(), &buf[0], buf.size());
+ // Unrecoverable error?
+ if (size == -1)
+ return false;
+ // It fit! (If size == buf.size(), it may have been truncated.)
+ if (static_cast<size_t>(size) < buf.size()) {
+ result->assign(&buf[0], size);
+ return true;
+ }
+ // Double our buffer and try again.
+ buf.resize(buf.size() * 2);
}
}
diff --git a/Utils.h b/Utils.h
index 82ac440..c5955cc 100644
--- a/Utils.h
+++ b/Utils.h
@@ -19,6 +19,7 @@
#include "KeyBuffer.h"
+#include <android-base/macros.h>
#include <utils/Errors.h>
#include <cutils/multiuser.h>
#include <selinux/selinux.h>
@@ -26,14 +27,6 @@
#include <vector>
#include <string>
-// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
-// declarations in a class.
-#if !defined(DISALLOW_COPY_AND_ASSIGN)
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&) = delete; \
- void operator=(const TypeName&) = delete
-#endif
-
struct DIR;
namespace android {
@@ -45,6 +38,9 @@
extern security_context_t sFsckContext;
extern security_context_t sFsckUntrustedContext;
+// TODO remove this with better solution, b/64143519
+extern bool sSleepOnUnmount;
+
status_t CreateDeviceNode(const std::string& path, dev_t dev);
status_t DestroyDeviceNode(const std::string& path);
@@ -60,13 +56,15 @@
/* Creates bind mount from source to target */
status_t BindMount(const std::string& source, const std::string& target);
+bool FindValue(const std::string& raw, const std::string& key, std::string* value);
+
/* Reads filesystem metadata from device at path */
-status_t ReadMetadata(const std::string& path, std::string& fsType,
- std::string& fsUuid, std::string& fsLabel);
+status_t ReadMetadata(const std::string& path, std::string* fsType,
+ std::string* fsUuid, std::string* fsLabel);
/* Reads filesystem metadata from untrusted device at path */
-status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
- std::string& fsUuid, std::string& fsLabel);
+status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType,
+ std::string* fsUuid, std::string* fsLabel);
/* Returns either WEXITSTATUS() status, or a negative errno */
status_t ForkExecvp(const std::vector<std::string>& args);
@@ -110,16 +108,17 @@
std::string BuildDataMiscDePath(userid_t userid);
std::string BuildDataProfilesDePath(userid_t userid);
-std::string BuildDataPath(const char* volumeUuid);
-std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userid);
-std::string BuildDataUserCePath(const char* volumeUuid, userid_t userid);
-std::string BuildDataUserDePath(const char* volumeUuid, userid_t userid);
+std::string BuildDataPath(const std::string& volumeUuid);
+std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userid);
+std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userid);
+std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userid);
dev_t GetDevice(const std::string& path);
status_t RestoreconRecursive(const std::string& path);
-status_t SaneReadLinkAt(int dirfd, const char* path, char* buf, size_t bufsiz);
+// TODO: promote to android::base
+bool Readlinkat(int dirfd, const std::string& path, std::string* result);
/* Checks if Android is running in QEMU */
bool IsRunningInEmulator();
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
new file mode 100644
index 0000000..d7a6576
--- /dev/null
+++ b/VoldNativeService.cpp
@@ -0,0 +1,753 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "VoldNativeService.h"
+#include "Benchmark.h"
+#include "CheckEncryption.h"
+#include "IdleMaint.h"
+#include "MoveStorage.h"
+#include "Process.h"
+#include "VolumeManager.h"
+
+#include "cryptfs.h"
+#include "Ext4Crypt.h"
+#include "MetadataCrypt.h"
+
+#include <fstream>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <ext4_utils/ext4_crypt.h>
+#include <fs_mgr.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Trace.h>
+
+using android::base::StringPrintf;
+using std::endl;
+
+namespace android {
+namespace vold {
+
+namespace {
+
+constexpr const char* kDump = "android.permission.DUMP";
+
+static binder::Status ok() {
+ return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+ return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+static binder::Status error(const std::string& msg) {
+ PLOG(ERROR) << msg;
+ return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
+}
+
+static binder::Status translate(int status) {
+ if (status == 0) {
+ return binder::Status::ok();
+ } else {
+ return binder::Status::fromServiceSpecificError(status);
+ }
+}
+
+static binder::Status translateBool(bool status) {
+ if (status) {
+ return binder::Status::ok();
+ } else {
+ return binder::Status::fromServiceSpecificError(status);
+ }
+}
+
+binder::Status checkPermission(const char* permission) {
+ pid_t pid;
+ uid_t uid;
+
+ if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
+ reinterpret_cast<int32_t*>(&uid))) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
+ }
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid == expectedUid || uid == AID_ROOT) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+ }
+}
+
+binder::Status checkArgumentId(const std::string& id) {
+ if (id.empty()) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID");
+ }
+ for (const char& c : id) {
+ if (!std::isalnum(c) && c != ':' && c != ',') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("ID %s is malformed", id.c_str()));
+ }
+ }
+ return ok();
+}
+
+binder::Status checkArgumentPath(const std::string& path) {
+ if (path.empty()) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path");
+ }
+ if (path[0] != '/') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Path %s is relative", path.c_str()));
+ }
+ if ((path + '/').find("/../") != std::string::npos) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Path %s is shady", path.c_str()));
+ }
+ for (const char& c : path) {
+ if (c == '\0' || c == '\n') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Path %s is malformed", path.c_str()));
+ }
+ }
+ return ok();
+}
+
+binder::Status checkArgumentHex(const std::string& hex) {
+ // Empty hex strings are allowed
+ for (const char& c : hex) {
+ if (!std::isxdigit(c) && c != ':' && c != '-') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Hex %s is malformed", hex.c_str()));
+ }
+ }
+ return ok();
+}
+
+#define ENFORCE_UID(uid) { \
+ binder::Status status = checkUid((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_ID(id) { \
+ binder::Status status = checkArgumentId((id)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_PATH(path) { \
+ binder::Status status = checkArgumentPath((path)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_HEX(hex) { \
+ binder::Status status = checkArgumentHex((hex)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define ACQUIRE_LOCK \
+ std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock()); \
+ ATRACE_CALL();
+
+#define ACQUIRE_CRYPT_LOCK \
+ std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock()); \
+ ATRACE_CALL();
+
+} // namespace
+
+status_t VoldNativeService::start() {
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+ status_t ret = BinderService<VoldNativeService>::publish();
+ if (ret != android::OK) {
+ return ret;
+ }
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ return android::OK;
+}
+
+status_t VoldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+ auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
+ const binder::Status dump_permission = checkPermission(kDump);
+ if (!dump_permission.isOk()) {
+ out << dump_permission.toString8() << endl;
+ return PERMISSION_DENIED;
+ }
+
+ ACQUIRE_LOCK;
+ out << "vold is happy!" << endl;
+ out.flush();
+ return NO_ERROR;
+}
+
+binder::Status VoldNativeService::setListener(
+ const android::sp<android::os::IVoldListener>& listener) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ VolumeManager::Instance()->setListener(listener);
+ return ok();
+}
+
+binder::Status VoldNativeService::monitor() {
+ ENFORCE_UID(AID_SYSTEM);
+
+ // Simply acquire/release each lock for watchdog
+ {
+ ACQUIRE_LOCK;
+ }
+ {
+ ACQUIRE_CRYPT_LOCK;
+ }
+
+ return ok();
+}
+
+binder::Status VoldNativeService::reset() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->reset());
+}
+
+binder::Status VoldNativeService::shutdown() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->shutdown());
+}
+
+binder::Status VoldNativeService::mountAll() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ struct fstab* fstab = fs_mgr_read_fstab_default();
+ int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
+ fs_mgr_free_fstab(fstab);
+ return translate(res);
+}
+
+binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserAdded(userId, userSerial));
+}
+
+binder::Status VoldNativeService::onUserRemoved(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserRemoved(userId));
+}
+
+binder::Status VoldNativeService::onUserStarted(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserStarted(userId));
+}
+
+binder::Status VoldNativeService::onUserStopped(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserStopped(userId));
+}
+
+binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType,
+ int32_t ratio) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(diskId);
+ ACQUIRE_LOCK;
+
+ auto disk = VolumeManager::Instance()->findDisk(diskId);
+ if (disk == nullptr) {
+ return error("Failed to find disk " + diskId);
+ }
+ switch (partitionType) {
+ case PARTITION_TYPE_PUBLIC: return translate(disk->partitionPublic());
+ case PARTITION_TYPE_PRIVATE: return translate(disk->partitionPrivate());
+ case PARTITION_TYPE_MIXED: return translate(disk->partitionMixed(ratio));
+ default: return error("Unknown type " + std::to_string(partitionType));
+ }
+}
+
+binder::Status VoldNativeService::forgetPartition(const std::string& partGuid,
+ const std::string& fsUuid) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_HEX(partGuid);
+ CHECK_ARGUMENT_HEX(fsUuid);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->forgetPartition(partGuid, fsUuid));
+}
+
+binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
+ int32_t mountUserId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+
+ vol->setMountFlags(mountFlags);
+ vol->setMountUserId(mountUserId);
+
+ int res = vol->mount();
+ if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
+ VolumeManager::Instance()->setPrimary(vol);
+ }
+ return translate(res);
+}
+
+binder::Status VoldNativeService::unmount(const std::string& volId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+ return translate(vol->unmount());
+}
+
+binder::Status VoldNativeService::format(const std::string& volId, const std::string& fsType) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+ return translate(vol->format(fsType));
+}
+
+static binder::Status pathForVolId(const std::string& volId, std::string* path) {
+ if (volId == "private" || volId == "null") {
+ *path = "/data";
+ } else {
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+ if (vol->getType() != VolumeBase::Type::kPrivate) {
+ return error("Volume " + volId + " not private");
+ }
+ if (vol->getState() != VolumeBase::State::kMounted) {
+ return error("Volume " + volId + " not mounted");
+ }
+ *path = vol->getPath();
+ if (path->empty()) {
+ return error("Volume " + volId + " missing path");
+ }
+ }
+ return ok();
+}
+
+binder::Status VoldNativeService::benchmark(
+ const std::string& volId, const android::sp<android::os::IVoldTaskListener>& listener) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ std::string path;
+ auto status = pathForVolId(volId, &path);
+ if (!status.isOk()) return status;
+
+ std::thread([=]() {
+ android::vold::Benchmark(path, listener);
+ }).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::checkEncryption(const std::string& volId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ std::string path;
+ auto status = pathForVolId(volId, &path);
+ if (!status.isOk()) return status;
+ return translate(android::vold::CheckEncryption(path));
+}
+
+binder::Status VoldNativeService::moveStorage(const std::string& fromVolId,
+ const std::string& toVolId, const android::sp<android::os::IVoldTaskListener>& listener) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(fromVolId);
+ CHECK_ARGUMENT_ID(toVolId);
+ ACQUIRE_LOCK;
+
+ auto fromVol = VolumeManager::Instance()->findVolume(fromVolId);
+ auto toVol = VolumeManager::Instance()->findVolume(toVolId);
+ if (fromVol == nullptr) {
+ return error("Failed to find volume " + fromVolId);
+ } else if (toVol == nullptr) {
+ return error("Failed to find volume " + toVolId);
+ }
+
+ std::thread([=]() {
+ android::vold::MoveStorage(fromVol, toVol, listener);
+ }).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ std::string tmp;
+ switch (remountMode) {
+ case REMOUNT_MODE_NONE: tmp = "none"; break;
+ case REMOUNT_MODE_DEFAULT: tmp = "default"; break;
+ case REMOUNT_MODE_READ: tmp = "read"; break;
+ case REMOUNT_MODE_WRITE: tmp = "write"; break;
+ default: return error("Unknown mode " + std::to_string(remountMode));
+ }
+ return translate(VolumeManager::Instance()->remountUid(uid, tmp));
+}
+
+binder::Status VoldNativeService::mkdirs(const std::string& path) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(path);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->mkdirs(path));
+}
+
+binder::Status VoldNativeService::createObb(const std::string& sourcePath,
+ const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(sourcePath);
+ CHECK_ARGUMENT_HEX(sourceKey);
+ ACQUIRE_LOCK;
+
+ return translate(
+ VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return));
+}
+
+binder::Status VoldNativeService::destroyObb(const std::string& volId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->destroyObb(volId));
+}
+
+binder::Status VoldNativeService::fstrim(int32_t fstrimFlags,
+ const android::sp<android::os::IVoldTaskListener>& listener) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ std::thread([=]() {
+ android::vold::Trim(listener);
+ }).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+ android::base::unique_fd* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return));
+}
+
+binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId));
+}
+
+binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_check_passwd(password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeRestart() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&cryptfs_restart).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_crypto_complete();
+ return ok();
+}
+
+static int fdeEnableInternal(int32_t passwordType, const std::string& password,
+ int32_t encryptionFlags) {
+ bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0;
+
+ std::string how;
+ if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) {
+ how = "inplace";
+ } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) {
+ how = "wipe";
+ } else {
+ LOG(ERROR) << "Missing encryption flag";
+ return -1;
+ }
+
+ for (int tries = 0; tries < 2; ++tries) {
+ int rc;
+ if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) {
+ rc = cryptfs_enable_default(how.c_str(), noUi);
+ } else {
+ rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi);
+ }
+
+ if (rc == 0) {
+ return 0;
+ } else if (tries == 0) {
+ KillProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
+ }
+ }
+
+ return -1;
+}
+
+binder::Status VoldNativeService::fdeEnable(int32_t passwordType,
+ const std::string& password, int32_t encryptionFlags) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ if (e4crypt_is_native()) {
+ if (passwordType != PASSWORD_TYPE_DEFAULT) {
+ return error("Unexpected password type");
+ }
+ if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) {
+ return error("Unexpected flags");
+ }
+ return translateBool(e4crypt_enable_crypto());
+ }
+
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&fdeEnableInternal, passwordType, password, encryptionFlags).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType,
+ const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_changepw(passwordType, password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_verify_passwd(password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeGetField(const std::string& key,
+ std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ char buf[PROPERTY_VALUE_MAX];
+ if (cryptfs_getfield(key.c_str(), buf, sizeof(buf)) != CRYPTO_GETFIELD_OK) {
+ return error(StringPrintf("Failed to read field %s", key.c_str()));
+ } else {
+ *_aidl_return = buf;
+ return ok();
+ }
+}
+
+binder::Status VoldNativeService::fdeSetField(const std::string& key,
+ const std::string& value) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_setfield(key.c_str(), value.c_str()));
+}
+
+binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_get_password_type();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ const char* res = cryptfs_get_password();
+ if (res != nullptr) {
+ *_aidl_return = res;
+ }
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeClearPassword() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ cryptfs_clear_password();
+ return ok();
+}
+
+binder::Status VoldNativeService::fbeEnable() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_initialize_global_de());
+}
+
+binder::Status VoldNativeService::mountDefaultEncrypted() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ if (e4crypt_is_native()) {
+ return translateBool(e4crypt_mount_metadata_encrypted());
+ } else {
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&cryptfs_mount_default_encrypted).detach();
+ return ok();
+ }
+}
+
+binder::Status VoldNativeService::initUser0() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_init_user0());
+}
+
+binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_isConvertibleToFBE() != 0;
+ return ok();
+}
+
+binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial,
+ bool ephemeral) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_vold_create_user_key(userId, userSerial, ephemeral));
+}
+
+binder::Status VoldNativeService::destroyUserKey(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_destroy_user_key(userId));
+}
+
+binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token, secret));
+}
+
+binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_fixate_newest_user_key_auth(userId));
+}
+
+binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_unlock_user_key(userId, userSerial, token, secret));
+}
+
+binder::Status VoldNativeService::lockUserKey(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_lock_user_key(userId));
+}
+
+binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t userSerial, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::string empty_string = "";
+ auto uuid_ = uuid ? *uuid : empty_string;
+ CHECK_ARGUMENT_HEX(uuid_);
+
+ ACQUIRE_CRYPT_LOCK;
+ return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags));
+}
+
+binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::string empty_string = "";
+ auto uuid_ = uuid ? *uuid : empty_string;
+ CHECK_ARGUMENT_HEX(uuid_);
+
+ ACQUIRE_CRYPT_LOCK;
+ return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags));
+}
+
+binder::Status VoldNativeService::secdiscard(const std::string& path) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(path);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_secdiscard(path));
+}
+
+} // namespace vold
+} // namespace android
diff --git a/VoldNativeService.h b/VoldNativeService.h
new file mode 100644
index 0000000..7ca72e5
--- /dev/null
+++ b/VoldNativeService.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _VOLD_NATIVE_SERVICE_H_
+#define _VOLD_NATIVE_SERVICE_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/BinderService.h>
+
+#include "android/os/BnVold.h"
+
+namespace android {
+namespace vold {
+
+class VoldNativeService : public BinderService<VoldNativeService>, public os::BnVold {
+public:
+ static status_t start();
+ static char const* getServiceName() { return "vold"; }
+ virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+ binder::Status setListener(const android::sp<android::os::IVoldListener>& listener);
+
+ binder::Status monitor();
+ binder::Status reset();
+ binder::Status shutdown();
+ binder::Status mountAll();
+
+ binder::Status onUserAdded(int32_t userId, int32_t userSerial);
+ binder::Status onUserRemoved(int32_t userId);
+ binder::Status onUserStarted(int32_t userId);
+ binder::Status onUserStopped(int32_t userId);
+
+ binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
+ binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid);
+
+ binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId);
+ binder::Status unmount(const std::string& volId);
+ binder::Status format(const std::string& volId, const std::string& fsType);
+ binder::Status benchmark(const std::string& volId,
+ const android::sp<android::os::IVoldTaskListener>& listener);
+ binder::Status checkEncryption(const std::string& volId);
+
+ binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId,
+ const android::sp<android::os::IVoldTaskListener>& listener);
+
+ binder::Status remountUid(int32_t uid, int32_t remountMode);
+
+ binder::Status mkdirs(const std::string& path);
+
+ binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
+ int32_t ownerGid, std::string* _aidl_return);
+ binder::Status destroyObb(const std::string& volId);
+
+ binder::Status fstrim(int32_t fstrimFlags,
+ const android::sp<android::os::IVoldTaskListener>& listener);
+
+ binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+ android::base::unique_fd* _aidl_return);
+ binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
+
+ binder::Status fdeCheckPassword(const std::string& password);
+ binder::Status fdeRestart();
+ binder::Status fdeComplete(int32_t* _aidl_return);
+ binder::Status fdeEnable(int32_t passwordType,
+ const std::string& password, int32_t encryptionFlags);
+ binder::Status fdeChangePassword(int32_t passwordType,
+ const std::string& password);
+ binder::Status fdeVerifyPassword(const std::string& password);
+ binder::Status fdeGetField(const std::string& key, std::string* _aidl_return);
+ binder::Status fdeSetField(const std::string& key, const std::string& value);
+ binder::Status fdeGetPasswordType(int32_t* _aidl_return);
+ binder::Status fdeGetPassword(std::string* _aidl_return);
+ binder::Status fdeClearPassword();
+
+ binder::Status fbeEnable();
+
+ binder::Status mountDefaultEncrypted();
+ binder::Status initUser0();
+ binder::Status isConvertibleToFbe(bool* _aidl_return);
+
+ binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral);
+ binder::Status destroyUserKey(int32_t userId);
+
+ binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret);
+ binder::Status fixateNewestUserKeyAuth(int32_t userId);
+
+ binder::Status unlockUserKey(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret);
+ binder::Status lockUserKey(int32_t userId);
+
+ binder::Status prepareUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t userSerial, int32_t flags);
+ binder::Status destroyUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags);
+
+ binder::Status secdiscard(const std::string& path);
+};
+
+} // namespace vold
+} // namespace android
+
+#endif // _VOLD_NATIVE_SERVICE_H_
diff --git a/VoldUtil.c b/VoldUtil.cpp
similarity index 95%
rename from VoldUtil.c
rename to VoldUtil.cpp
index e5bc912..afe8b53 100644
--- a/VoldUtil.c
+++ b/VoldUtil.cpp
@@ -17,6 +17,8 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
+struct fstab *fstab_default;
+
void get_blkdev_size(int fd, unsigned long* nr_sec) {
if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) {
*nr_sec = 0;
diff --git a/VoldUtil.h b/VoldUtil.h
index 5738382..fd66672 100644
--- a/VoldUtil.h
+++ b/VoldUtil.h
@@ -17,12 +17,13 @@
#ifndef _VOLDUTIL_H
#define _VOLDUTIL_H
+#include <fstab/fstab.h>
#include <sys/cdefs.h>
+extern struct fstab *fstab_default;
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-__BEGIN_DECLS
void get_blkdev_size(int fd, unsigned long* nr_sec);
-__END_DECLS
#endif
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index c3c95f6..e078c0d 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <fts.h>
#include <mntent.h>
#include <stdio.h>
#include <stdlib.h>
@@ -32,15 +33,14 @@
#include <linux/kdev_t.h>
-#define LOG_TAG "Vold"
-
-#include <openssl/md5.h>
-
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
#include <cutils/fs.h>
-#include <cutils/log.h>
+#include <utils/Trace.h>
#include <selinux/android.h>
@@ -48,49 +48,24 @@
#include <private/android_filesystem_config.h>
-#include "Benchmark.h"
-#include "EmulatedVolume.h"
-#include "VolumeManager.h"
-#include "NetlinkManager.h"
-#include "ResponseCode.h"
+#include <ext4_utils/ext4_crypt.h>
+
+#include "Devmapper.h"
+#include "Ext4Crypt.h"
#include "Loop.h"
+#include "NetlinkManager.h"
+#include "Process.h"
+#include "Utils.h"
+#include "VoldUtil.h"
+#include "VolumeManager.h"
+#include "cryptfs.h"
#include "fs/Ext4.h"
#include "fs/Vfat.h"
-#include "Utils.h"
-#include "Devmapper.h"
-#include "Process.h"
-#include "Asec.h"
-#include "VoldUtil.h"
-#include "cryptfs.h"
-
-#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
-
-#define ROUND_UP_POWER_OF_2(number, po2) (((!!((number) & ((1U << (po2)) - 1))) << (po2))\
- + ((number) & (~((1U << (po2)) - 1))))
+#include "model/EmulatedVolume.h"
+#include "model/ObbVolume.h"
using android::base::StringPrintf;
-
-/*
- * Path to external storage where *only* root can access ASEC image files
- */
-const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec";
-
-/*
- * Path to internal storage where *only* root can access ASEC image files
- */
-const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec";
-
-/*
- * Path to where secure containers are mounted
- */
-const char *VolumeManager::ASECDIR = "/mnt/asec";
-
-/*
- * Path to where OBBs are mounted
- */
-const char *VolumeManager::LOOPDIR = "/mnt/obb";
-
-bool VolumeManager::shutting_down = false;
+using android::base::unique_fd;
static const char* kPathUserMount = "/mnt/user";
static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
@@ -104,107 +79,6 @@
static const unsigned int kMajorBlockExperimentalMin = 240;
static const unsigned int kMajorBlockExperimentalMax = 254;
-/* writes superblock at end of file or device given by name */
-static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
- int sbfd = open(name, O_RDWR | O_CLOEXEC);
- if (sbfd < 0) {
- SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
- return -1;
- }
-
- if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
- SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
- close(sbfd);
- return -1;
- }
-
- if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
- SLOGE("Failed to write superblock (%s)", strerror(errno));
- close(sbfd);
- return -1;
- }
- close(sbfd);
- return 0;
-}
-
-static unsigned long adjustSectorNumExt4(unsigned long numSectors) {
- // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
- // preventing costly operations or unexpected ENOSPC error.
- // Ext4::format() uses default block size without clustering.
- unsigned long clusterSectors = 4096 / 512;
- unsigned long reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
- numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
- return ROUND_UP_POWER_OF_2(numSectors, 3);
-}
-
-static unsigned long adjustSectorNumFAT(unsigned long numSectors) {
- /*
- * Add some headroom
- */
- unsigned long fatSize = (((numSectors * 4) / 512) + 1) * 2;
- numSectors += fatSize + 2;
- /*
- * FAT is aligned to 32 kb with 512b sectors.
- */
- return ROUND_UP_POWER_OF_2(numSectors, 6);
-}
-
-static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
- if (Loop::lookupActive(idHash, buffer, len)) {
- if (Loop::create(idHash, asecFileName, buffer, len)) {
- SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
- return -1;
- }
- if (debug) {
- SLOGD("New loop device created at %s", buffer);
- }
- } else {
- if (debug) {
- SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
- }
- }
- return 0;
-}
-
-static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , unsigned long numImgSectors, bool* createdDMDevice, bool debug) {
- if (strcmp(key, "none")) {
- if (Devmapper::lookupActive(idHash, buffer, len)) {
- if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
- buffer, len)) {
- SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
- return -1;
- }
- if (debug) {
- SLOGD("New devmapper instance created at %s", buffer);
- }
- } else {
- if (debug) {
- SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
- }
- }
- *createdDMDevice = true;
- } else {
- strlcpy(buffer, loopDevice, len);
- *createdDMDevice = false;
- }
- return 0;
-}
-
-static void waitForDevMapper(const char *dmDevice) {
- /*
- * Wait for the device mapper node to be created. Sometimes it takes a
- * while. Wait for up to 1 second. We could also inspect incoming uevents,
- * but that would take more effort.
- */
- int tries = 25;
- while (tries--) {
- if (!access(dmDevice, F_OK) || errno != ENOENT) {
- break;
- }
- usleep(40 * 1000);
- }
-}
-
VolumeManager *VolumeManager::sInstance = NULL;
VolumeManager *VolumeManager::Instance() {
@@ -215,52 +89,15 @@
VolumeManager::VolumeManager() {
mDebug = false;
- mActiveContainers = new AsecIdCollection();
- mBroadcaster = NULL;
- mUmsSharingCount = 0;
- mSavedDirtyRatio = -1;
- // set dirty ratio to 0 when UMS is active
- mUmsDirtyRatio = 0;
+ mNextObbId = 0;
}
VolumeManager::~VolumeManager() {
- delete mActiveContainers;
-}
-
-char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
- static const char* digits = "0123456789abcdef";
-
- unsigned char sig[MD5_DIGEST_LENGTH];
-
- if (buffer == NULL) {
- SLOGE("Destination buffer is NULL");
- errno = ESPIPE;
- return NULL;
- } else if (id == NULL) {
- SLOGE("Source buffer is NULL");
- errno = ESPIPE;
- return NULL;
- } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
- SLOGE("Target hash buffer size < %d bytes (%zu)",
- MD5_ASCII_LENGTH_PLUS_NULL, len);
- errno = ESPIPE;
- return NULL;
- }
-
- MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
-
- char *p = buffer;
- for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
- *p++ = digits[sig[i] >> 4];
- *p++ = digits[sig[i] & 0x0F];
- }
- *p = '\0';
-
- return buffer;
}
int VolumeManager::updateVirtualDisk() {
- if (property_get_bool(kPropVirtualDisk, false)) {
+ ATRACE_NAME("VolumeManager::updateVirtualDisk");
+ if (android::base::GetBoolProperty(kPropVirtualDisk, false)) {
if (access(kPathVirtualDisk, F_OK) != 0) {
Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
}
@@ -314,10 +151,15 @@
}
int VolumeManager::start() {
+ ATRACE_NAME("VolumeManager::start");
+
// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
unmountAll();
+ Devmapper::destroyAll();
+ Loop::destroyAll();
+
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
@@ -352,8 +194,8 @@
if (devType != "disk") return;
- int major = atoi(evt->findParam("MAJOR"));
- int minor = atoi(evt->findParam("MINOR"));
+ int major = std::stoi(evt->findParam("MAJOR"));
+ int minor = std::stoi(evt->findParam("MINOR"));
dev_t device = makedev(major, minor);
switch (evt->getAction()) {
@@ -438,6 +280,11 @@
return vol;
}
}
+ for (const auto& vol : mObbVolumes) {
+ if (vol->getId() == id) {
+ return vol;
+ }
+ }
return nullptr;
}
@@ -449,39 +296,25 @@
}
}
-nsecs_t VolumeManager::benchmarkPrivate(const std::string& id) {
- std::string path;
- if (id == "private" || id == "null") {
- path = "/data";
- } else {
- auto vol = findVolume(id);
- if (vol != nullptr && vol->getState() == android::vold::VolumeBase::State::kMounted) {
- path = vol->getPath();
- }
- }
-
- if (path.empty()) {
- LOG(WARNING) << "Failed to find volume for " << id;
- return -1;
- }
-
- return android::vold::BenchmarkPrivate(path);
-}
-
-int VolumeManager::forgetPartition(const std::string& partGuid) {
+int VolumeManager::forgetPartition(const std::string& partGuid, const std::string& fsUuid) {
std::string normalizedGuid;
if (android::vold::NormalizeHex(partGuid, normalizedGuid)) {
LOG(WARNING) << "Invalid GUID " << partGuid;
return -1;
}
+ bool success = true;
std::string keyPath = android::vold::BuildKeyPath(normalizedGuid);
if (unlink(keyPath.c_str()) != 0) {
LOG(ERROR) << "Failed to unlink " << keyPath;
- return -1;
+ success = false;
}
-
- return 0;
+ if (e4crypt_is_native()) {
+ if (!e4crypt_destroy_volume_keys(fsUuid)) {
+ success = false;
+ }
+ }
+ return success ? 0 : -1;
}
int VolumeManager::linkPrimary(userid_t userId) {
@@ -494,13 +327,12 @@
std::string target(StringPrintf("/mnt/user/%d/primary", userId));
if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
if (errno != ENOENT) {
- SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno));
+ PLOG(WARNING) << "Failed to unlink " << target;
}
}
LOG(DEBUG) << "Linking " << source << " to " << target;
if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
- SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(),
- strerror(errno));
+ PLOG(WARNING) << "Failed to link";
return -errno;
}
return 0;
@@ -543,12 +375,10 @@
return 0;
}
-static int unmount_tree(const char* path) {
- size_t path_len = strlen(path);
-
+static int unmount_tree(const std::string& prefix) {
FILE* fp = setmntent("/proc/mounts", "r");
if (fp == NULL) {
- ALOGE("Error opening /proc/mounts: %s", strerror(errno));
+ PLOG(ERROR) << "Failed to open /proc/mounts";
return -errno;
}
@@ -557,15 +387,16 @@
std::list<std::string> toUnmount;
mntent* mentry;
while ((mentry = getmntent(fp)) != NULL) {
- if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
- toUnmount.push_front(std::string(mentry->mnt_dir));
+ auto test = std::string(mentry->mnt_dir) + "/";
+ if (android::base::StartsWith(test, prefix.c_str())) {
+ toUnmount.push_front(test);
}
}
endmntent(fp);
for (const auto& path : toUnmount) {
if (umount2(path.c_str(), MNT_DETACH)) {
- ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
+ PLOG(ERROR) << "Failed to unmount " << path;
}
}
return 0;
@@ -576,8 +407,8 @@
DIR* dir;
struct dirent* de;
- char rootName[PATH_MAX];
- char pidName[PATH_MAX];
+ std::string rootName;
+ std::string pidName;
int pidFd;
int nsFd;
struct stat sb;
@@ -589,8 +420,8 @@
}
// Figure out root namespace to compare against below
- if (android::vold::SaneReadLinkAt(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
- PLOG(ERROR) << "Failed to readlink";
+ if (!android::vold::Readlinkat(dirfd(dir), "1/ns/mnt", &rootName)) {
+ PLOG(ERROR) << "Failed to read root namespace";
closedir(dir);
return -1;
}
@@ -618,11 +449,11 @@
// Matches so far, but refuse to touch if in root namespace
LOG(DEBUG) << "Found matching PID " << de->d_name;
- if (android::vold::SaneReadLinkAt(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
+ if (!android::vold::Readlinkat(pidFd, "ns/mnt", &pidName)) {
PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
goto next;
}
- if (!strcmp(rootName, pidName)) {
+ if (rootName == pidName) {
LOG(WARNING) << "Skipping due to root namespace";
goto next;
}
@@ -640,7 +471,7 @@
_exit(1);
}
- unmount_tree("/storage");
+ unmount_tree("/storage/");
std::string storageSource;
if (mode == "default") {
@@ -716,19 +547,20 @@
if (mInternalEmulated == nullptr) {
return 0; // already shutdown
}
- shutting_down = true;
+ android::vold::sSleepOnUnmount = false;
mInternalEmulated->destroy();
mInternalEmulated = nullptr;
for (const auto& disk : mDisks) {
disk->destroy();
}
mDisks.clear();
- shutting_down = false;
+ android::vold::sSleepOnUnmount = true;
return 0;
}
int VolumeManager::unmountAll() {
std::lock_guard<std::mutex> lock(mLock);
+ ATRACE_NAME("VolumeManager::unmountAll()");
// First, try gracefully unmounting all known devices
if (mInternalEmulated != nullptr) {
@@ -742,7 +574,7 @@
// force unmount those just to be safe.
FILE* fp = setmntent("/proc/mounts", "r");
if (fp == NULL) {
- SLOGE("Error opening /proc/mounts: %s", strerror(errno));
+ PLOG(ERROR) << "Failed to open /proc/mounts";
return -errno;
}
@@ -751,1219 +583,242 @@
std::list<std::string> toUnmount;
mntent* mentry;
while ((mentry = getmntent(fp)) != NULL) {
- if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
- || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
- toUnmount.push_front(std::string(mentry->mnt_dir));
+ auto test = std::string(mentry->mnt_dir);
+ if (android::base::StartsWith(test, "/mnt/")
+ || android::base::StartsWith(test, "/storage/")) {
+ toUnmount.push_front(test);
}
}
endmntent(fp);
for (const auto& path : toUnmount) {
- SLOGW("Tearing down stale mount %s", path.c_str());
+ LOG(DEBUG) << "Tearing down stale mount " << path;
android::vold::ForceUnmount(path);
}
return 0;
}
-int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
- char idHash[33];
- if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
- return -1;
- }
-
- memset(mountPath, 0, mountPathLen);
- int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash);
- if ((written < 0) || (written >= mountPathLen)) {
- errno = EINVAL;
- return -1;
- }
-
- if (access(mountPath, F_OK)) {
- errno = ENOENT;
- return -1;
- }
-
- return 0;
-}
-
-int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
- char asecFileName[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- memset(buffer, 0, maxlen);
- if (access(asecFileName, F_OK)) {
- errno = ENOENT;
- return -1;
- }
-
- int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (written >= maxlen)) {
- SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
- char asecFileName[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- memset(buffer, 0, maxlen);
- if (access(asecFileName, F_OK)) {
- errno = ENOENT;
- return -1;
- }
-
- int written = snprintf(buffer, maxlen, "%s", asecFileName);
- if ((written < 0) || (written >= maxlen)) {
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-int VolumeManager::createAsec(const char *id, unsigned long numSectors, const char *fstype,
- const char *key, const int ownerUid, bool isExternal) {
- struct asec_superblock sb;
- memset(&sb, 0, sizeof(sb));
-
- if (!isLegalAsecId(id)) {
- SLOGE("createAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- const bool wantFilesystem = strcmp(fstype, "none");
- bool usingExt4 = false;
- if (wantFilesystem) {
- usingExt4 = !strcmp(fstype, "ext4");
- if (usingExt4) {
- sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
- } else if (strcmp(fstype, "fat")) {
- SLOGE("Invalid filesystem type %s", fstype);
- errno = EINVAL;
- return -1;
- }
- }
-
- sb.magic = ASEC_SB_MAGIC;
- sb.ver = ASEC_SB_VER;
-
- if (numSectors < ((1024*1024)/512)) {
- SLOGE("Invalid container size specified (%lu sectors)", numSectors);
- errno = EINVAL;
- return -1;
- }
-
- char asecFileName[255];
-
- if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
- asecFileName, strerror(errno));
- errno = EADDRINUSE;
- return -1;
- }
-
- const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT;
-
- int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
- if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
- errno = EINVAL;
- return -1;
- }
-
- if (!access(asecFileName, F_OK)) {
- SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
- asecFileName, strerror(errno));
- errno = EADDRINUSE;
- return -1;
- }
-
- unsigned long numImgSectors;
- if (usingExt4)
- numImgSectors = adjustSectorNumExt4(numSectors);
- else
- numImgSectors = adjustSectorNumFAT(numSectors);
-
- // Add +1 for our superblock which is at the end
- if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
- SLOGE("ASEC image file creation failed (%s)", strerror(errno));
- return -1;
- }
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- unlink(asecFileName);
- return -1;
- }
-
- char loopDevice[255];
- if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
- SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
- unlink(asecFileName);
- return -1;
- }
-
- char dmDevice[255];
- bool cleanupDm = false;
-
- if (strcmp(key, "none")) {
- // XXX: This is all we support for now
- sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
- if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
- sizeof(dmDevice))) {
- SLOGE("ASEC device mapping failed (%s)", strerror(errno));
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
- cleanupDm = true;
- } else {
- sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
- strlcpy(dmDevice, loopDevice, sizeof(dmDevice));
- }
-
- /*
- * Drop down the superblock at the end of the file
- */
- if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
-
- if (wantFilesystem) {
- int formatStatus;
- char mountPoint[255];
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC fs format failed: couldn't construct mountPoint");
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
-
- if (usingExt4) {
- formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint);
- } else {
- formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors);
- }
-
- if (formatStatus < 0) {
- SLOGE("ASEC fs format failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
-
- if (mkdir(mountPoint, 0000)) {
- if (errno != EEXIST) {
- SLOGE("Mountpoint creation failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
- }
-
- int mountStatus;
- if (usingExt4) {
- mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint,
- false, false, false);
- } else {
- mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint,
- false, false, false, ownerUid, 0, 0000, false);
- }
-
- if (mountStatus) {
- SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- unlink(asecFileName);
- return -1;
- }
-
- if (usingExt4) {
- int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
- if (dirfd >= 0) {
- if (fchown(dirfd, ownerUid, AID_SYSTEM)
- || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
- SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
- }
- close(dirfd);
- }
- }
- } else {
- SLOGI("Created raw secure container %s (no filesystem)", id);
- }
-
- mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
- return 0;
-}
-
-int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const char *key) {
- char asecFileName[255];
- char mountPoint[255];
- bool cleanupDm = false;
-
- if (!isLegalAsecId(id)) {
- SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
- return -1;
- }
-
- if (isMountpointMounted(mountPoint)) {
- SLOGE("ASEC %s mounted. Unmount before resizing", id);
- errno = EBUSY;
- return -1;
- }
-
- struct asec_superblock sb;
- int fd;
- unsigned long oldNumSec = 0;
-
- if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
- SLOGE("Failed to open ASEC file (%s)", strerror(errno));
- return -1;
- }
-
- struct stat info;
- if (fstat(fd, &info) < 0) {
- SLOGE("Failed to get file size (%s)", strerror(errno));
- close(fd);
- return -1;
- }
-
- oldNumSec = info.st_size / 512;
-
- /*
- * Try to read superblock.
- */
- memset(&sb, 0, sizeof(struct asec_superblock));
- if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
- SLOGE("lseek failed (%s)", strerror(errno));
- close(fd);
- return -1;
- }
- if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
- SLOGE("superblock read failed (%s)", strerror(errno));
- close(fd);
- return -1;
- }
- close(fd);
-
- if (mDebug) {
- SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
- }
- if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
- SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
- errno = EMEDIUMTYPE;
- return -1;
- }
-
- unsigned long numImgSectors;
- if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
- SLOGE("Only ext4 partitions are supported for resize");
- errno = EINVAL;
- return -1;
- } else {
- numImgSectors = adjustSectorNumExt4(numSectors);
- }
-
- /*
- * add one block for the superblock
- */
- SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
- if (oldNumSec == numImgSectors + 1) {
- SLOGW("Size unchanged; ignoring resize request");
- return 0;
- } else if (oldNumSec > numImgSectors + 1) {
- SLOGE("Only growing is currently supported.");
- close(fd);
- return -1;
- }
-
- if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
- SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
- return -1;
- }
-
- /*
- * Drop down a copy of the superblock at the end of the file
- */
- if (writeSuperBlock(asecFileName, &sb, numImgSectors))
- goto fail;
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- goto fail;
- }
-
- char loopDevice[255];
- if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
- goto fail;
-
- char dmDevice[255];
-
- if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
- Loop::destroyByDevice(loopDevice);
- goto fail;
- }
-
- /*
- * Wait for the device mapper node to be created.
- */
- waitForDevMapper(dmDevice);
-
- if (android::vold::ext4::Resize(dmDevice, numImgSectors)) {
- SLOGE("Unable to resize %s (%s)", id, strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- goto fail;
- }
-
- return 0;
-fail:
- Loop::resizeImageFile(asecFileName, oldNumSec);
- return -1;
-}
-
-int VolumeManager::finalizeAsec(const char *id) {
- char asecFileName[255];
- char loopDevice[255];
- char mountPoint[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- return -1;
- }
-
- if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
- SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
- return -1;
- }
-
- unsigned long nr_sec = 0;
- struct asec_superblock sb;
-
- if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC finalize failed: couldn't construct mountPoint");
- return -1;
- }
-
- int result = 0;
- if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
- result = android::vold::ext4::Mount(loopDevice, mountPoint,
- true, true, true);
- } else {
- result = android::vold::vfat::Mount(loopDevice, mountPoint,
- true, true, true, 0, 0, 0227, false);
- }
-
- if (result) {
- SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
- return -1;
- }
-
- if (mDebug) {
- SLOGD("ASEC %s finalized", id);
- }
- return 0;
-}
-
-int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
- char asecFileName[255];
- char loopDevice[255];
- char mountPoint[255];
-
- if (gid < AID_APP) {
- SLOGE("Group ID is not in application range");
- return -1;
- }
-
- if (!isLegalAsecId(id)) {
- SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- return -1;
- }
-
- if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
- SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
- return -1;
- }
-
- unsigned long nr_sec = 0;
- struct asec_superblock sb;
-
- if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
- return -1;
- }
-
- int result = 0;
- if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
- return 0;
- }
-
- int ret = android::vold::ext4::Mount(loopDevice, mountPoint,
- false /* read-only */,
- true /* remount */,
- false /* executable */);
- if (ret) {
- SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
- return -1;
- }
-
- char *paths[] = { mountPoint, NULL };
-
- FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
- if (fts) {
- // Traverse the entire hierarchy and chown to system UID.
- for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
- // We don't care about the lost+found directory.
- if (!strcmp(ftsent->fts_name, "lost+found")) {
- continue;
- }
-
- /*
- * There can only be one file marked as private right now.
- * This should be more robust, but it satisfies the requirements
- * we have for right now.
- */
- const bool privateFile = !strcmp(ftsent->fts_name, filename);
-
- int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
- if (fd < 0) {
- SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
- result = -1;
- continue;
- }
-
- result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
-
- if (ftsent->fts_info & FTS_D) {
- result |= fchmod(fd, 0755);
- } else if (ftsent->fts_info & FTS_F) {
- result |= fchmod(fd, privateFile ? 0640 : 0644);
- }
-
- if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
- SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
- result |= -1;
- }
-
- close(fd);
- }
- fts_close(fts);
-
- // Finally make the directory readable by everyone.
- int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
- if (dirfd < 0 || fchmod(dirfd, 0755)) {
- SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
- result |= -1;
- }
- close(dirfd);
- } else {
- result |= -1;
- }
-
- result |= android::vold::ext4::Mount(loopDevice, mountPoint,
- true /* read-only */,
- true /* remount */,
- true /* execute */);
-
- if (result) {
- SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
- return -1;
- }
-
- if (mDebug) {
- SLOGD("ASEC %s permissions fixed", id);
- }
- return 0;
-}
-
-int VolumeManager::renameAsec(const char *id1, const char *id2) {
- char asecFilename1[255];
- char *asecFilename2;
- char mountPoint[255];
-
- const char *dir;
-
- if (!isLegalAsecId(id1)) {
- SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
- errno = EINVAL;
- return -1;
- }
-
- if (!isLegalAsecId(id2)) {
- SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
- SLOGE("Couldn't find ASEC %s", id1);
- return -1;
- }
-
- asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("Rename failed: couldn't construct mountpoint");
- goto out_err;
- }
-
- if (isMountpointMounted(mountPoint)) {
- SLOGW("Rename attempt when src mounted");
- errno = EBUSY;
- goto out_err;
- }
-
- written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("Rename failed: couldn't construct mountpoint2");
- goto out_err;
- }
-
- if (isMountpointMounted(mountPoint)) {
- SLOGW("Rename attempt when dst mounted");
- errno = EBUSY;
- goto out_err;
- }
-
- if (!access(asecFilename2, F_OK)) {
- SLOGE("Rename attempt when dst exists");
- errno = EADDRINUSE;
- goto out_err;
- }
-
- if (rename(asecFilename1, asecFilename2)) {
- SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
- goto out_err;
- }
-
- free(asecFilename2);
- return 0;
-
-out_err:
- free(asecFilename2);
- return -1;
-}
-
-#define UNMOUNT_RETRIES 5
-#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
-int VolumeManager::unmountAsec(const char *id, bool force) {
- char asecFileName[255];
- char mountPoint[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
- return -1;
- }
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- return -1;
- }
-
- return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
-}
-
-int VolumeManager::unmountObb(const char *fileName, bool force) {
- char mountPoint[255];
-
- char idHash[33];
- if (!asecHash(fileName, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
- return -1;
- }
-
- return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
-}
-
-int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
- const char *fileName, const char *mountPoint, bool force) {
- if (!isMountpointMounted(mountPoint)) {
- SLOGE("Unmount request for %s when not mounted", id);
- errno = ENOENT;
- return -1;
- }
-
- int i, rc;
- for (i = 1; i <= UNMOUNT_RETRIES; i++) {
- rc = umount(mountPoint);
- if (!rc) {
- break;
- }
- if (rc && (errno == EINVAL || errno == ENOENT)) {
- SLOGI("Container %s unmounted OK", id);
- rc = 0;
- break;
- }
- SLOGW("%s unmount attempt %d failed (%s)",
- id, i, strerror(errno));
-
- int signal = 0; // default is to just complain
-
- if (force) {
- if (i > (UNMOUNT_RETRIES - 2))
- signal = SIGKILL;
- else if (i > (UNMOUNT_RETRIES - 3))
- signal = SIGTERM;
- }
-
- Process::killProcessesWithOpenFiles(mountPoint, signal);
- usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
- }
-
- if (rc) {
- errno = EBUSY;
- SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
- return -1;
- }
-
- int retries = 10;
-
- while(retries--) {
- if (!rmdir(mountPoint)) {
- break;
- }
-
- SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
- usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
- }
-
- if (!retries) {
- SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
- }
-
- for (i=1; i <= UNMOUNT_RETRIES; i++) {
- if (Devmapper::destroy(idHash) && errno != ENXIO) {
- SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
- usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
- continue;
- } else {
- break;
- }
- }
-
- char loopDevice[255];
- if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
- Loop::destroyByDevice(loopDevice);
- } else {
- SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
- }
-
- AsecIdCollection::iterator it;
- for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
- ContainerData* cd = *it;
- if (!strcmp(cd->id, id)) {
- free(*it);
- mActiveContainers->erase(it);
- break;
- }
- }
- if (it == mActiveContainers->end()) {
- SLOGW("mActiveContainers is inconsistent!");
- }
- return 0;
-}
-
-int VolumeManager::destroyAsec(const char *id, bool force) {
- char asecFileName[255];
- char mountPoint[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
- return -1;
- }
-
- if (isMountpointMounted(mountPoint)) {
- if (mDebug) {
- SLOGD("Unmounting container before destroy");
- }
- if (unmountAsec(id, force)) {
- SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
- return -1;
- }
- }
-
- if (unlink(asecFileName)) {
- SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
- return -1;
- }
-
- if (mDebug) {
- SLOGD("ASEC %s destroyed", id);
- }
- return 0;
-}
-
-/*
- * Legal ASEC ids consist of alphanumeric characters, '-',
- * '_', or '.'. ".." is not allowed. The first or last character
- * of the ASEC id cannot be '.' (dot).
- */
-bool VolumeManager::isLegalAsecId(const char *id) const {
- size_t i;
- size_t len = strlen(id);
-
- if (len == 0) {
- return false;
- }
- if ((id[0] == '.') || (id[len - 1] == '.')) {
- return false;
- }
-
- for (i = 0; i < len; i++) {
- if (id[i] == '.') {
- // i=0 is guaranteed never to have a dot. See above.
- if (id[i-1] == '.') return false;
- continue;
- }
- if (id[i] == '_' || id[i] == '-') continue;
- if (id[i] >= 'a' && id[i] <= 'z') continue;
- if (id[i] >= 'A' && id[i] <= 'Z') continue;
- if (id[i] >= '0' && id[i] <= '9') continue;
- return false;
- }
-
- return true;
-}
-
-bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
- int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
- if (dirfd < 0) {
- SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
- return false;
- }
-
- struct stat sb;
- bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0)
- && S_ISREG(sb.st_mode);
-
- close(dirfd);
-
- return ret;
-}
-
-int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
- const char **directory) const {
- char *asecName;
-
- if (!isLegalAsecId(id)) {
- SLOGE("findAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (asprintf(&asecName, "%s.asec", id) < 0) {
- SLOGE("Couldn't allocate string to write ASEC name");
- return -1;
- }
-
- const char *dir;
- if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) {
- dir = VolumeManager::SEC_ASECDIR_INT;
- } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) {
- dir = VolumeManager::SEC_ASECDIR_EXT;
- } else {
- free(asecName);
- return -1;
- }
-
- if (directory != NULL) {
- *directory = dir;
- }
-
- if (asecPath != NULL) {
- int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
- if ((written < 0) || (size_t(written) >= asecPathLen)) {
- SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
- free(asecName);
- return -1;
- }
- }
-
- free(asecName);
- return 0;
-}
-
-int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
- char asecFileName[255];
- char mountPoint[255];
-
- if (!isLegalAsecId(id)) {
- SLOGE("mountAsec: Invalid asec id \"%s\"", id);
- errno = EINVAL;
- return -1;
- }
-
- if (findAsec(id, asecFileName, sizeof(asecFileName))) {
- SLOGE("Couldn't find ASEC %s", id);
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
- return -1;
- }
-
- if (isMountpointMounted(mountPoint)) {
- SLOGE("ASEC %s already mounted", id);
- errno = EBUSY;
- return -1;
- }
-
- char idHash[33];
- if (!asecHash(id, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
- return -1;
- }
-
- char loopDevice[255];
- if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
- return -1;
-
- char dmDevice[255];
- bool cleanupDm = false;
-
- unsigned long nr_sec = 0;
- struct asec_superblock sb;
-
- if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
- return -1;
- }
-
- if (mDebug) {
- SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
- }
- if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
- SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
- Loop::destroyByDevice(loopDevice);
- errno = EMEDIUMTYPE;
- return -1;
- }
- nr_sec--; // We don't want the devmapping to extend onto our superblock
-
- if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
-
- if (mkdir(mountPoint, 0000)) {
- if (errno != EEXIST) {
- SLOGE("Mountpoint creation failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
- }
-
- /*
- * Wait for the device mapper node to be created.
- */
- waitForDevMapper(dmDevice);
-
- int result;
- if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
- result = android::vold::ext4::Mount(dmDevice, mountPoint,
- readOnly, false, readOnly);
- } else {
- result = android::vold::vfat::Mount(dmDevice, mountPoint,
- readOnly, false, readOnly, ownerUid, 0, 0222, false);
- }
-
- if (result) {
- SLOGE("ASEC mount failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
-
- mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
- if (mDebug) {
- SLOGD("ASEC %s mounted", id);
- }
- return 0;
-}
-
-/**
- * Mounts an image file <code>img</code>.
- */
-int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
- char mountPoint[255];
-
- char idHash[33];
- if (!asecHash(img, idHash, sizeof(idHash))) {
- SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
- return -1;
- }
-
- int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
- if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
- SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
- return -1;
- }
-
- if (isMountpointMounted(mountPoint)) {
- SLOGE("Image %s already mounted", img);
- errno = EBUSY;
- return -1;
- }
-
- char loopDevice[255];
- if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
- return -1;
-
- char dmDevice[255];
- bool cleanupDm = false;
- int fd;
- unsigned long nr_sec = 0;
-
- if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
- SLOGE("Failed to open loopdevice (%s)", strerror(errno));
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
-
- get_blkdev_size(fd, &nr_sec);
- if (nr_sec == 0) {
- SLOGE("Failed to get loop size (%s)", strerror(errno));
- Loop::destroyByDevice(loopDevice);
- close(fd);
- return -1;
- }
-
- close(fd);
-
- if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) {
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
-
- if (mkdir(mountPoint, 0755)) {
- if (errno != EEXIST) {
- SLOGE("Mountpoint creation failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
- }
-
- /*
- * Wait for the device mapper node to be created.
- */
- waitForDevMapper(dmDevice);
-
- if (android::vold::vfat::Mount(dmDevice, mountPoint,
- true, false, true, 0, ownerGid, 0227, false)) {
- SLOGE("Image mount failed (%s)", strerror(errno));
- if (cleanupDm) {
- Devmapper::destroy(idHash);
- }
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
-
- mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
- if (mDebug) {
- SLOGD("Image %s mounted", img);
- }
- return 0;
-}
-
-int VolumeManager::listMountedObbs(SocketClient* cli) {
- FILE *fp = setmntent("/proc/mounts", "r");
- if (fp == NULL) {
- SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
- return -1;
- }
-
- // Create a string to compare against that has a trailing slash
- int loopDirLen = strlen(VolumeManager::LOOPDIR);
- char loopDir[loopDirLen + 2];
- strlcpy(loopDir, VolumeManager::LOOPDIR, sizeof(loopDir));
- loopDir[loopDirLen++] = '/';
- loopDir[loopDirLen] = '\0';
-
- mntent* mentry;
- while ((mentry = getmntent(fp)) != NULL) {
- if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
- int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- struct loop_info64 li;
- if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
- cli->sendMsg(ResponseCode::AsecListResult,
- (const char*) li.lo_file_name, false);
- }
- close(fd);
- }
- }
- }
- endmntent(fp);
- return 0;
-}
-
-extern "C" int vold_unmountAll(void) {
- VolumeManager *vm = VolumeManager::Instance();
- return vm->unmountAll();
-}
-
-bool VolumeManager::isMountpointMounted(const char *mp)
-{
- FILE *fp = setmntent("/proc/mounts", "r");
- if (fp == NULL) {
- SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
- return false;
- }
-
- bool found_mp = false;
- mntent* mentry;
- while ((mentry = getmntent(fp)) != NULL) {
- if (strcmp(mentry->mnt_dir, mp) == 0) {
- found_mp = true;
- break;
- }
- }
- endmntent(fp);
- return found_mp;
-}
-
-int VolumeManager::mkdirs(char* path) {
+int VolumeManager::mkdirs(const std::string& path) {
// Only offer to create directories for paths managed by vold
- if (strncmp(path, "/storage/", 9) == 0) {
+ if (android::base::StartsWith(path, "/storage/")) {
// fs_mkdirs() does symlink checking and relative path enforcement
- return fs_mkdirs(path, 0700);
+ return fs_mkdirs(path.c_str(), 0700);
} else {
- SLOGE("Failed to find mounted volume for %s", path);
+ LOG(ERROR) << "Failed to find mounted volume for " << path;
return -EINVAL;
}
}
+
+static size_t kAppFuseMaxMountPointName = 32;
+
+static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
+ if (name.size() > kAppFuseMaxMountPointName) {
+ LOG(ERROR) << "AppFuse mount name is too long.";
+ return -EINVAL;
+ }
+ for (size_t i = 0; i < name.size(); i++) {
+ if (!isalnum(name[i])) {
+ LOG(ERROR) << "AppFuse mount name contains invalid character.";
+ return -EINVAL;
+ }
+ }
+ *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
+ return android::OK;
+}
+
+static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
+ // Remove existing mount.
+ android::vold::ForceUnmount(path);
+
+ const auto opts = android::base::StringPrintf(
+ "fd=%i,"
+ "rootmode=40000,"
+ "default_permissions,"
+ "allow_other,"
+ "user_id=%d,group_id=%d,"
+ "context=\"u:object_r:app_fuse_file:s0\","
+ "fscontext=u:object_r:app_fusefs:s0",
+ device_fd,
+ uid,
+ uid);
+
+ const int result = TEMP_FAILURE_RETRY(mount(
+ "/dev/fuse", path.c_str(), "fuse",
+ MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
+ if (result != 0) {
+ PLOG(ERROR) << "Failed to mount " << path;
+ return -errno;
+ }
+
+ return android::OK;
+}
+
+static android::status_t runCommandInNamespace(const std::string& command,
+ uid_t uid,
+ pid_t pid,
+ const std::string& path,
+ int device_fd) {
+ if (DEBUG_APPFUSE) {
+ LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
+ << " in namespace " << uid;
+ }
+
+ unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (dir.get() == -1) {
+ PLOG(ERROR) << "Failed to open /proc";
+ return -errno;
+ }
+
+ // Obtains process file descriptor.
+ const std::string pid_str = android::base::StringPrintf("%d", pid);
+ const unique_fd pid_fd(
+ openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (pid_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open /proc/" << pid;
+ return -errno;
+ }
+
+ // Check UID of process.
+ {
+ struct stat sb;
+ const int result = fstat(pid_fd.get(), &sb);
+ if (result == -1) {
+ PLOG(ERROR) << "Failed to stat /proc/" << pid;
+ return -errno;
+ }
+ if (sb.st_uid != AID_SYSTEM) {
+ LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
+ << ", actual=" << sb.st_uid;
+ return -EPERM;
+ }
+ }
+
+ // Matches so far, but refuse to touch if in root namespace
+ {
+ std::string rootName;
+ std::string pidName;
+ if (!android::vold::Readlinkat(dir.get(), "1/ns/mnt", &rootName)
+ || !android::vold::Readlinkat(pid_fd.get(), "ns/mnt", &pidName)) {
+ PLOG(ERROR) << "Failed to read namespaces";
+ return -EPERM;
+ }
+ if (rootName == pidName) {
+ LOG(ERROR) << "Don't mount appfuse in root namespace";
+ return -EPERM;
+ }
+ }
+
+ // We purposefully leave the namespace open across the fork
+ unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
+ if (ns_fd.get() < 0) {
+ PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
+ return -errno;
+ }
+
+ int child = fork();
+ if (child == 0) {
+ if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
+ PLOG(ERROR) << "Failed to setns";
+ _exit(-errno);
+ }
+
+ if (command == "mount") {
+ _exit(mountInNamespace(uid, device_fd, path));
+ } else if (command == "unmount") {
+ // If it's just after all FD opened on mount point are closed, umount2 can fail with
+ // EBUSY. To avoid the case, specify MNT_DETACH.
+ if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
+ errno != EINVAL && errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unmount directory.";
+ _exit(-errno);
+ }
+ if (rmdir(path.c_str()) != 0) {
+ PLOG(ERROR) << "Failed to remove the mount directory.";
+ _exit(-errno);
+ }
+ _exit(android::OK);
+ } else {
+ LOG(ERROR) << "Unknown appfuse command " << command;
+ _exit(-EPERM);
+ }
+ }
+
+ if (child == -1) {
+ PLOG(ERROR) << "Failed to folk child process";
+ return -errno;
+ }
+
+ android::status_t status;
+ TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+
+ return status;
+}
+
+int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
+ int32_t ownerGid, std::string* outVolId) {
+ int id = mNextObbId++;
+
+ auto vol = std::shared_ptr<android::vold::VolumeBase>(
+ new android::vold::ObbVolume(id, sourcePath, sourceKey, ownerGid));
+ vol->create();
+
+ mObbVolumes.push_back(vol);
+ *outVolId = vol->getId();
+ return android::OK;
+}
+
+int VolumeManager::destroyObb(const std::string& volId) {
+ auto i = mObbVolumes.begin();
+ while (i != mObbVolumes.end()) {
+ if ((*i)->getId() == volId) {
+ (*i)->destroy();
+ i = mObbVolumes.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ return android::OK;
+}
+
+int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId,
+ android::base::unique_fd* device_fd) {
+ std::string name = std::to_string(mountId);
+
+ // Check mount point name.
+ std::string path;
+ if (getMountPath(uid, name, &path) != android::OK) {
+ LOG(ERROR) << "Invalid mount point name";
+ return -1;
+ }
+
+ // Create directories.
+ const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
+ if (result != android::OK) {
+ PLOG(ERROR) << "Failed to prepare directory " << path;
+ return -1;
+ }
+
+ // Open device FD.
+ device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
+ if (device_fd->get() == -1) {
+ PLOG(ERROR) << "Failed to open /dev/fuse";
+ return -1;
+ }
+
+ // Mount.
+ return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
+}
+
+int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
+ std::string name = std::to_string(mountId);
+
+ // Check mount point name.
+ std::string path;
+ if (getMountPath(uid, name, &path) != android::OK) {
+ LOG(ERROR) << "Invalid mount point name";
+ return -1;
+ }
+
+ return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
+}
diff --git a/VolumeManager.h b/VolumeManager.h
index 537aebe..5baa7ce 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -21,76 +21,40 @@
#include <fnmatch.h>
#include <stdlib.h>
-#ifdef __cplusplus
-
#include <list>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
+#include <android-base/unique_fd.h>
#include <cutils/multiuser.h>
#include <utils/List.h>
#include <utils/Timers.h>
-#include <sysutils/SocketListener.h>
#include <sysutils/NetlinkEvent.h>
-#include "Disk.h"
-#include "VolumeBase.h"
+#include "android/os/IVoldListener.h"
-/* The length of an MD5 hash when encoded into ASCII hex characters */
-#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
+#include "model/Disk.h"
+#include "model/VolumeBase.h"
-typedef enum { ASEC, OBB } container_type_t;
-
-class ContainerData {
-public:
- ContainerData(char* _id, container_type_t _type)
- : id(_id)
- , type(_type)
- {}
-
- ~ContainerData() {
- if (id != NULL) {
- free(id);
- id = NULL;
- }
- }
-
- char *id;
- container_type_t type;
-};
-
-typedef android::List<ContainerData*> AsecIdCollection;
+#define DEBUG_APPFUSE 0
class VolumeManager {
-public:
- static const char *SEC_ASECDIR_EXT;
- static const char *SEC_ASECDIR_INT;
- static const char *ASECDIR;
- static const char *LOOPDIR;
-
- //TODO remove this with better solution, b/64143519
- static bool shutting_down;
-
private:
static VolumeManager *sInstance;
- SocketListener *mBroadcaster;
-
- AsecIdCollection *mActiveContainers;
bool mDebug;
- // for adjusting /proc/sys/vm/dirty_ratio when UMS is active
- int mUmsSharingCount;
- int mSavedDirtyRatio;
- int mUmsDirtyRatio;
-
public:
virtual ~VolumeManager();
// TODO: pipe all requests through VM to avoid exposing this lock
std::mutex& getLock() { return mLock; }
+ std::mutex& getCryptLock() { return mCryptLock; }
+
+ void setListener(android::sp<android::os::IVoldListener> listener) { mListener = listener; }
+ android::sp<android::os::IVoldListener> getListener() { return mListener; }
int start();
int stop();
@@ -123,9 +87,7 @@
void listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list);
- nsecs_t benchmarkPrivate(const std::string& id);
-
- int forgetPartition(const std::string& partGuid);
+ int forgetPartition(const std::string& partGuid, const std::string& fsUuid);
int onUserAdded(userid_t userId, int userSerialNumber);
int onUserRemoved(userid_t userId);
@@ -143,52 +105,11 @@
/* Unmount all volumes, usually for encryption */
int unmountAll();
- /* ASEC */
- int findAsec(const char *id, char *asecPath = NULL, size_t asecPathLen = 0,
- const char **directory = NULL) const;
- int createAsec(const char *id, unsigned long numSectors, const char *fstype,
- const char *key, const int ownerUid, bool isExternal);
- int resizeAsec(const char *id, unsigned long numSectors, const char *key);
- int finalizeAsec(const char *id);
-
- /**
- * Fixes ASEC permissions on a filesystem that has owners and permissions.
- * This currently means EXT4-based ASEC containers.
- *
- * There is a single file that can be marked as "private" and will not have
- * world-readable permission. The group for that file will be set to the gid
- * supplied.
- *
- * Returns 0 on success.
- */
- int fixupAsecPermissions(const char *id, gid_t gid, const char* privateFilename);
- int destroyAsec(const char *id, bool force);
- int mountAsec(const char *id, const char *key, int ownerUid, bool readOnly);
- int unmountAsec(const char *id, bool force);
- int renameAsec(const char *id1, const char *id2);
- int getAsecMountPath(const char *id, char *buffer, int maxlen);
- int getAsecFilesystemPath(const char *id, char *buffer, int maxlen);
-
- /* Loopback images */
- int listMountedObbs(SocketClient* cli);
- int mountObb(const char *fileName, const char *key, int ownerUid);
- int unmountObb(const char *fileName, bool force);
- int getObbMountPath(const char *id, char *buffer, int maxlen);
-
- /* Shared between ASEC and Loopback images */
- int unmountLoopImage(const char *containerId, const char *loopId,
- const char *fileName, const char *mountPoint, bool force);
-
int updateVirtualDisk();
int setDebug(bool enable);
- void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
- SocketListener *getBroadcaster() { return mBroadcaster; }
-
static VolumeManager *Instance();
- static char *asecHash(const char *id, char *buffer, size_t len);
-
/*
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that
@@ -196,21 +117,29 @@
* is treated as filename and ignored, unless the path ends with "/". Also
* ensures that path belongs to a volume managed by vold.
*/
- int mkdirs(char* path);
+ int mkdirs(const std::string& path);
+
+ int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
+ std::string* outVolId);
+ int destroyObb(const std::string& volId);
+
+ int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
+ int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
private:
VolumeManager();
void readInitialState();
- bool isMountpointMounted(const char *mp);
- bool isAsecInDirectory(const char *dir, const char *asec) const;
- bool isLegalAsecId(const char *id) const;
int linkPrimary(userid_t userId);
std::mutex mLock;
+ std::mutex mCryptLock;
+
+ android::sp<android::os::IVoldListener> mListener;
std::list<std::shared_ptr<DiskSource>> mDiskSources;
std::list<std::shared_ptr<android::vold::Disk>> mDisks;
+ std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
std::unordered_map<userid_t, int> mAddedUsers;
std::unordered_set<userid_t> mStartedUsers;
@@ -219,14 +148,8 @@
std::shared_ptr<android::vold::Disk> mVirtualDisk;
std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
std::shared_ptr<android::vold::VolumeBase> mPrimary;
-};
-extern "C" {
-#endif /* __cplusplus */
-#define UNMOUNT_NOT_MOUNTED_ERR (-2)
- int vold_unmountAll(void);
-#ifdef __cplusplus
-}
-#endif
+ int mNextObbId;
+};
#endif
diff --git a/bench/benchgen.py b/bench/benchgen.py
index c852169..f119804 100644
--- a/bench/benchgen.py
+++ b/bench/benchgen.py
@@ -157,6 +157,7 @@
#include <fcntl.h>
#include <algorithm>
+#include <functional>
#include <string>
#include <Utils.h>
@@ -164,7 +165,8 @@
namespace android {
namespace vold {
-static status_t BenchmarkRun() {
+static status_t BenchmarkRun(std::function<bool(int)> checkpoint) {
+
"""
print >>bench, "char* buf = (char*) malloc(%d);" % (bufsize)
@@ -175,13 +177,19 @@
events = sorted(events, key=lambda e: e.time)
active = set()
defined = set()
+ i = 0
+ total = len(events)
for e in events:
+ i += 1
+ if i % 256 == 0:
+ print >>bench, "if (!checkpoint(%d)) return -1;" % (50 + ((i * 50) / total))
+
if e.call == "openat":
fd, f, handle = extract_file(e, e.ret)
if f:
active.add(handle)
if handle not in defined:
- print >>bench, "int ",
+ print >>bench, "int",
defined.add(handle)
create_mode = ''
if 'O_CREAT' in e.args[2]:
@@ -297,11 +305,17 @@
return OK;
}
-static status_t BenchmarkCreate() {
+static status_t BenchmarkCreate(std::function<bool(int)> checkpoint) {
status_t res = 0;
res |= CreateFile("stub", 0);
"""
+ i = 0
+ total = len(files.values())
for f in files.values():
+ i += 1
+ if i % 12 == 0:
+ print >>bench, "if (!checkpoint(%d)) return -1;" % ((i * 50) / total)
+
print >>bench, 'res |= CreateFile("file%s", %d);' % (f.ident, f.size)
print >>bench, """
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
new file mode 100644
index 0000000..5d182c9
--- /dev/null
+++ b/binder/android/os/IVold.aidl
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.os;
+
+import android.os.IVoldListener;
+import android.os.IVoldTaskListener;
+
+/** {@hide} */
+interface IVold {
+ void setListener(IVoldListener listener);
+
+ void monitor();
+ void reset();
+ void shutdown();
+ void mountAll();
+
+ void onUserAdded(int userId, int userSerial);
+ void onUserRemoved(int userId);
+ void onUserStarted(int userId);
+ void onUserStopped(int userId);
+
+ void partition(@utf8InCpp String diskId, int partitionType, int ratio);
+ void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid);
+
+ void mount(@utf8InCpp String volId, int mountFlags, int mountUserId);
+ void unmount(@utf8InCpp String volId);
+ void format(@utf8InCpp String volId, @utf8InCpp String fsType);
+ void benchmark(@utf8InCpp String volId, IVoldTaskListener listener);
+ void checkEncryption(@utf8InCpp String volId);
+
+ void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId,
+ IVoldTaskListener listener);
+
+ void remountUid(int uid, int remountMode);
+
+ void mkdirs(@utf8InCpp String path);
+
+ @utf8InCpp String createObb(@utf8InCpp String sourcePath,
+ @utf8InCpp String sourceKey, int ownerGid);
+ void destroyObb(@utf8InCpp String volId);
+
+ void fstrim(int fstrimFlags, IVoldTaskListener listener);
+
+ FileDescriptor mountAppFuse(int uid, int pid, int mountId);
+ void unmountAppFuse(int uid, int pid, int mountId);
+
+ void fdeCheckPassword(@utf8InCpp String password);
+ void fdeRestart();
+ int fdeComplete();
+ void fdeEnable(int passwordType, @utf8InCpp String password, int encryptionFlags);
+ void fdeChangePassword(int passwordType, @utf8InCpp String password);
+ void fdeVerifyPassword(@utf8InCpp String password);
+ @utf8InCpp String fdeGetField(@utf8InCpp String key);
+ void fdeSetField(@utf8InCpp String key, @utf8InCpp String value);
+ int fdeGetPasswordType();
+ @utf8InCpp String fdeGetPassword();
+ void fdeClearPassword();
+
+ void fbeEnable();
+
+ void mountDefaultEncrypted();
+ void initUser0();
+ boolean isConvertibleToFbe();
+
+ void createUserKey(int userId, int userSerial, boolean ephemeral);
+ void destroyUserKey(int userId);
+
+ void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret);
+ void fixateNewestUserKeyAuth(int userId);
+
+ void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret);
+ void lockUserKey(int userId);
+
+ void prepareUserStorage(@nullable @utf8InCpp String uuid, int userId, int userSerial, int storageFlags);
+ void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags);
+
+ void secdiscard(@utf8InCpp String path);
+
+ const int ENCRYPTION_FLAG_WIPE = 1;
+ const int ENCRYPTION_FLAG_IN_PLACE = 2;
+ const int ENCRYPTION_FLAG_NO_UI = 4;
+
+ const int ENCRYPTION_STATE_NONE = 1;
+ const int ENCRYPTION_STATE_OK = 0;
+ const int ENCRYPTION_STATE_ERROR_UNKNOWN = -1;
+ const int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2;
+ const int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3;
+ const int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
+
+ const int FSTRIM_FLAG_DEEP_TRIM = 1;
+
+ const int MOUNT_FLAG_PRIMARY = 1;
+ const int MOUNT_FLAG_VISIBLE = 2;
+
+ const int PARTITION_TYPE_PUBLIC = 0;
+ const int PARTITION_TYPE_PRIVATE = 1;
+ const int PARTITION_TYPE_MIXED = 2;
+
+ const int PASSWORD_TYPE_PASSWORD = 0;
+ const int PASSWORD_TYPE_DEFAULT = 1;
+ const int PASSWORD_TYPE_PIN = 2;
+ const int PASSWORD_TYPE_PATTERN = 3;
+
+ const int STORAGE_FLAG_DE = 1;
+ const int STORAGE_FLAG_CE = 2;
+
+ const int REMOUNT_MODE_NONE = 0;
+ const int REMOUNT_MODE_DEFAULT = 1;
+ const int REMOUNT_MODE_READ = 2;
+ const int REMOUNT_MODE_WRITE = 3;
+
+ const int VOLUME_STATE_UNMOUNTED = 0;
+ const int VOLUME_STATE_CHECKING = 1;
+ const int VOLUME_STATE_MOUNTED = 2;
+ const int VOLUME_STATE_MOUNTED_READ_ONLY = 3;
+ const int VOLUME_STATE_FORMATTING = 4;
+ const int VOLUME_STATE_EJECTING = 5;
+ const int VOLUME_STATE_UNMOUNTABLE = 6;
+ const int VOLUME_STATE_REMOVED = 7;
+ const int VOLUME_STATE_BAD_REMOVAL = 8;
+
+ const int VOLUME_TYPE_PUBLIC = 0;
+ const int VOLUME_TYPE_PRIVATE = 1;
+ const int VOLUME_TYPE_EMULATED = 2;
+ const int VOLUME_TYPE_ASEC = 3;
+ const int VOLUME_TYPE_OBB = 4;
+}
diff --git a/binder/android/os/IVoldListener.aidl b/binder/android/os/IVoldListener.aidl
new file mode 100644
index 0000000..0dcfc04
--- /dev/null
+++ b/binder/android/os/IVoldListener.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+oneway interface IVoldListener {
+ void onDiskCreated(@utf8InCpp String diskId, int flags);
+ void onDiskScanned(@utf8InCpp String diskId);
+ void onDiskMetadataChanged(@utf8InCpp String diskId,
+ long sizeBytes, @utf8InCpp String label, @utf8InCpp String sysPath);
+ void onDiskDestroyed(@utf8InCpp String diskId);
+
+ void onVolumeCreated(@utf8InCpp String volId,
+ int type, @utf8InCpp String diskId, @utf8InCpp String partGuid);
+ void onVolumeStateChanged(@utf8InCpp String volId, int state);
+ void onVolumeMetadataChanged(@utf8InCpp String volId,
+ @utf8InCpp String fsType, @utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
+ void onVolumePathChanged(@utf8InCpp String volId,
+ @utf8InCpp String path);
+ void onVolumeInternalPathChanged(@utf8InCpp String volId,
+ @utf8InCpp String internalPath);
+ void onVolumeDestroyed(@utf8InCpp String volId);
+}
diff --git a/VoldCommand.cpp b/binder/android/os/IVoldTaskListener.aidl
similarity index 65%
rename from VoldCommand.cpp
rename to binder/android/os/IVoldTaskListener.aidl
index 3c0d58d..e2bac04 100644
--- a/VoldCommand.cpp
+++ b/binder/android/os/IVoldTaskListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,8 +14,12 @@
* limitations under the License.
*/
-#include "VoldCommand.h"
+package android.os;
-VoldCommand::VoldCommand(const char *cmd) :
- FrameworkCommand(cmd) {
+import android.os.PersistableBundle;
+
+/** {@hide} */
+oneway interface IVoldTaskListener {
+ void onStatus(int status, in PersistableBundle extras);
+ void onFinished(int status, in PersistableBundle extras);
}
diff --git a/cryptfs.cpp b/cryptfs.cpp
index eb89e1b..7302c44 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -38,7 +38,7 @@
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <errno.h>
-#include <ext4_utils/ext4.h>
+#include <ext4_utils/ext4_crypt.h>
#include <ext4_utils/ext4_utils.h>
#include <linux/kdev_t.h>
#include <fs_mgr.h>
@@ -191,8 +191,6 @@
static int password_expiry_time = 0;
static const int password_max_age_seconds = 60;
-extern struct fstab *fstab;
-
enum class RebootType {reboot, recovery, shutdown};
static void cryptfs_reboot(RebootType rt)
{
@@ -295,7 +293,7 @@
int rc = -1;
if (!cached_data) {
- fs_mgr_get_crypt_info(fstab, key_loc, real_blkdev, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab_default, key_loc, real_blkdev, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
if ( (fd = open(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
@@ -1279,10 +1277,10 @@
if (kill) {
if (i == (WAIT_UNMOUNT_COUNT - 3)) {
SLOGW("sending SIGHUP to processes with open files\n");
- vold_killProcessesWithOpenFiles(mountpoint, SIGTERM);
+ android::vold::KillProcessesWithOpenFiles(mountpoint, SIGTERM);
} else if (i == (WAIT_UNMOUNT_COUNT - 2)) {
SLOGW("sending SIGKILL to processes with open files\n");
- vold_killProcessesWithOpenFiles(mountpoint, SIGKILL);
+ android::vold::KillProcessesWithOpenFiles(mountpoint, SIGKILL);
}
}
@@ -1293,7 +1291,7 @@
SLOGD("unmounting %s succeeded\n", mountpoint);
rc = 0;
} else {
- vold_killProcessesWithOpenFiles(mountpoint, 0);
+ android::vold::KillProcessesWithOpenFiles(mountpoint, 0);
SLOGE("unmounting %s failed: %s\n", mountpoint, strerror(err));
rc = -1;
}
@@ -1419,8 +1417,8 @@
*/
char ro_prop[PROPERTY_VALUE_MAX];
property_get("ro.crypto.readonly", ro_prop, "");
- if (strlen(ro_prop) > 0 && atoi(ro_prop)) {
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT);
+ if (strlen(ro_prop) > 0 && std::stoi(ro_prop)) {
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
rec->flags |= MS_RDONLY;
}
@@ -1436,7 +1434,7 @@
SLOGE("Failed to setexeccon");
return -1;
}
- while ((mount_rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT,
+ while ((mount_rc = fs_mgr_do_mount(fstab_default, DATA_MNT_POINT,
crypto_blkdev, 0))
!= 0) {
if (mount_rc == FS_MGR_DOMNT_BUSY) {
@@ -1517,7 +1515,7 @@
}
if (get_crypt_ftr_and_key(&crypt_ftr)) {
- fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab_default, key_loc, 0, sizeof(key_loc));
/*
* Only report this error if key_loc is a file and it exists.
@@ -1585,7 +1583,7 @@
}
}
- fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev));
// Create crypto block device - all (non fatal) code paths
// need it
@@ -1617,7 +1615,7 @@
snprintf(tmp_mount_point, sizeof(tmp_mount_point), "%s/tmp_mnt",
mount_point);
mkdir(tmp_mount_point, 0755);
- if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
+ if (fs_mgr_do_mount(fstab_default, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
SLOGE("Error temp mounting decrypted block device\n");
delete_crypto_blk_dev(label);
@@ -1813,7 +1811,7 @@
return rc;
}
-int cryptfs_verify_passwd(char *passwd)
+int cryptfs_verify_passwd(const char *passwd)
{
struct crypt_mnt_ftr crypt_ftr;
/* Allocate enough space for a 256 bit key, but we may use less */
@@ -1912,7 +1910,6 @@
int rc = -1;
if (type == EXT4_FS) {
-#ifdef TARGET_USES_MKE2FS
args[0] = "/system/bin/mke2fs";
args[1] = "-M";
args[2] = "/data";
@@ -1924,16 +1921,6 @@
snprintf(size_str, sizeof(size_str), "%" PRId64, size / (4096 / 512));
args[8] = size_str;
num_args = 9;
-#else
- args[0] = "/system/bin/make_ext4fs";
- args[1] = "-a";
- args[2] = "/data";
- args[3] = "-l";
- snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512);
- args[4] = size_str;
- args[5] = crypto_blkdev;
- num_args = 6;
-#endif
SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n",
args[0], args[1], args[2], args[3], args[4], args[5]);
} else if (type == F2FS_FS) {
@@ -2027,7 +2014,7 @@
tot_encryption_size = crypt_ftr->fs_size;
if (how == CRYPTO_ENABLE_WIPE) {
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT);
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
int fs_type = get_fs_type(rec);
if (fs_type < 0) {
SLOGE("cryptfs_enable: unsupported fs type %s\n", rec->fs_type);
@@ -2064,7 +2051,12 @@
return rc;
}
-int cryptfs_enable_internal(char *howarg, int crypt_type, const char *passwd,
+static int vold_unmountAll(void) {
+ VolumeManager* vm = VolumeManager::Instance();
+ return vm->unmountAll();
+}
+
+int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd,
int no_ui)
{
int how = 0;
@@ -2127,8 +2119,8 @@
}
// TODO refactor fs_mgr_get_crypt_info to get both in one call
- fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
- fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab_default, key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab_default, 0, real_blkdev, sizeof(real_blkdev));
/* Get the size of the real block device */
fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
@@ -2423,12 +2415,12 @@
return -1;
}
-int cryptfs_enable(char *howarg, int type, char *passwd, int no_ui)
+int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui)
{
return cryptfs_enable_internal(howarg, type, passwd, no_ui);
}
-int cryptfs_enable_default(char *howarg, int no_ui)
+int cryptfs_enable_default(const char *howarg, int no_ui)
{
return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT,
DEFAULT_PASSWORD, no_ui);
@@ -2559,30 +2551,23 @@
* Test if key is part of the multi-entry (field, index) sequence. Return non-zero if key is in the
* sequence and its index is greater than or equal to index. Return 0 otherwise.
*/
-static int match_multi_entry(const char *key, const char *field, unsigned index) {
- unsigned int field_len;
- unsigned int key_index;
- field_len = strlen(field);
+int match_multi_entry(const char *key, const char *field, unsigned index) {
+ std::string key_ = key;
+ std::string field_ = field;
- if (index == 0) {
- // The first key in a multi-entry field is just the filedname itself.
- if (!strcmp(key, field)) {
- return 1;
- }
+ std::string parsed_field;
+ unsigned parsed_index;
+
+ std::string::size_type split = key_.find_last_of('_');
+ if (split == std::string::npos) {
+ parsed_field = key_;
+ parsed_index = 0;
+ } else {
+ parsed_field = key_.substr(0, split);
+ parsed_index = std::stoi(key_.substr(split + 1));
}
- // Match key against "%s_%d" % (field, index)
- if (strlen(key) < field_len + 1 + 1) {
- // Need at least a '_' and a digit.
- return 0;
- }
- if (strncmp(key, field, field_len)) {
- // If the key does not begin with field, it's not a match.
- return 0;
- }
- if (1 != sscanf(&key[field_len],"_%d", &key_index)) {
- return 0;
- }
- return key_index >= index;
+
+ return parsed_field == field_ && parsed_index >= index;
}
/*
@@ -2883,79 +2868,6 @@
int cryptfs_isConvertibleToFBE()
{
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT);
+ struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
return fs_mgr_is_convertible_to_fbe(rec) ? 1 : 0;
}
-
-int cryptfs_create_default_ftr(struct crypt_mnt_ftr* crypt_ftr, __attribute__((unused))int key_length)
-{
- if (cryptfs_init_crypt_mnt_ftr(crypt_ftr)) {
- SLOGE("Failed to initialize crypt_ftr");
- return -1;
- }
-
- if (create_encrypted_random_key(DEFAULT_PASSWORD, crypt_ftr->master_key,
- crypt_ftr->salt, crypt_ftr)) {
- SLOGE("Cannot create encrypted master key\n");
- return -1;
- }
-
- //crypt_ftr->keysize = key_length / 8;
- return 0;
-}
-
-int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password,
- unsigned char* master_key)
-{
- int rc;
-
- unsigned char* intermediate_key = 0;
- size_t intermediate_key_size = 0;
-
- if (password == 0 || *password == 0) {
- password = DEFAULT_PASSWORD;
- }
-
- rc = decrypt_master_key(password, master_key, ftr, &intermediate_key,
- &intermediate_key_size);
-
- if (rc) {
- SLOGE("Can't calculate intermediate key");
- return rc;
- }
-
- int N = 1 << ftr->N_factor;
- int r = 1 << ftr->r_factor;
- int p = 1 << ftr->p_factor;
-
- unsigned char scrypted_intermediate_key[sizeof(ftr->scrypted_intermediate_key)];
-
- rc = crypto_scrypt(intermediate_key, intermediate_key_size,
- ftr->salt, sizeof(ftr->salt), N, r, p,
- scrypted_intermediate_key,
- sizeof(scrypted_intermediate_key));
-
- free(intermediate_key);
-
- if (rc) {
- SLOGE("Can't scrypt intermediate key");
- return rc;
- }
-
- return memcmp(scrypted_intermediate_key, ftr->scrypted_intermediate_key,
- intermediate_key_size);
-}
-
-int cryptfs_set_password(struct crypt_mnt_ftr* ftr, const char* password,
- const unsigned char* master_key)
-{
- return encrypt_master_key(password, ftr->salt, master_key, ftr->master_key,
- ftr);
-}
-
-void cryptfs_get_file_encryption_modes(const char **contents_mode_ret,
- const char **filenames_mode_ret)
-{
- struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT);
- fs_mgr_get_file_encryption_modes(rec, contents_mode_ret, filenames_mode_ret);
-}
diff --git a/cryptfs.h b/cryptfs.h
index d20d96d..767270f 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef ANDROID_VOLD_CRYPTFS_H
+#define ANDROID_VOLD_CRYPTFS_H
+
/* This structure starts 16,384 bytes before the end of a hardware
* partition that is encrypted, or in a separate partition. It's location
* is specified by a property set in init.<device>.rc.
@@ -218,42 +221,28 @@
#define PERSIST_DEL_KEY_ERROR_OTHER (-1)
#define PERSIST_DEL_KEY_ERROR_NO_FIELD (-2)
-#ifdef __cplusplus
-extern "C" {
-#endif
+int match_multi_entry(const char* key, const char* field, unsigned index);
+int wait_and_unmount(const char* mountpoint, bool kill);
- int wait_and_unmount(const char *mountpoint, bool kill);
+typedef int (*kdf_func)(const char* passwd, const unsigned char* salt, unsigned char* ikey,
+ void* params);
- typedef int (*kdf_func)(const char *passwd, const unsigned char *salt,
- unsigned char *ikey, void *params);
+int cryptfs_crypto_complete(void);
+int cryptfs_check_passwd(const char* pw);
+int cryptfs_verify_passwd(const char* pw);
+int cryptfs_restart(void);
+int cryptfs_enable(const char* flag, int type, const char* passwd, int no_ui);
+int cryptfs_changepw(int type, const char* newpw);
+int cryptfs_enable_default(const char* flag, int no_ui);
+int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key,
+ int keysize, char* out_crypto_blkdev);
+int cryptfs_revert_ext_volume(const char* label);
+int cryptfs_getfield(const char* fieldname, char* value, int len);
+int cryptfs_setfield(const char* fieldname, const char* value);
+int cryptfs_mount_default_encrypted(void);
+int cryptfs_get_password_type(void);
+const char* cryptfs_get_password(void);
+void cryptfs_clear_password(void);
+int cryptfs_isConvertibleToFBE(void);
- int cryptfs_crypto_complete(void);
- int cryptfs_check_passwd(const char *pw);
- int cryptfs_verify_passwd(char *newpw);
- int cryptfs_restart(void);
- int cryptfs_enable(char *flag, int type, char *passwd, int no_ui);
- int cryptfs_changepw(int type, const char *newpw);
- int cryptfs_enable_default(char *flag, int no_ui);
- int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
- const unsigned char* key, int keysize, char* out_crypto_blkdev);
- int cryptfs_revert_ext_volume(const char* label);
- int cryptfs_getfield(const char *fieldname, char *value, int len);
- int cryptfs_setfield(const char *fieldname, const char *value);
- int cryptfs_mount_default_encrypted(void);
- int cryptfs_get_password_type(void);
- const char* cryptfs_get_password(void);
- void cryptfs_clear_password(void);
- int cryptfs_isConvertibleToFBE(void);
-
- // Functions for file encryption to use to inherit our encryption logic
- int cryptfs_create_default_ftr(struct crypt_mnt_ftr* ftr, int key_length);
- int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password,
- unsigned char* master_key);
- int cryptfs_set_password(struct crypt_mnt_ftr* ftr, const char* password,
- const unsigned char* master_key);
- void cryptfs_get_file_encryption_modes(const char **contents_mode_ret,
- const char **filenames_mode_ret);
-
-#ifdef __cplusplus
-}
-#endif
+#endif /* ANDROID_VOLD_CRYPTFS_H */
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 0cf4f9e..89b8414 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -42,6 +42,7 @@
#include <android-base/stringprintf.h>
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <ext4_utils/ext4_crypt.h>
#include <logwrap/logwrap.h>
#include <selinux/selinux.h>
@@ -145,7 +146,7 @@
rc = mount(c_source, c_target, "ext4", flags, NULL);
if (rc && errno == EROFS) {
- SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
+ LOG(ERROR) << source << " appears to be a read only filesystem - retrying mount RO";
flags |= MS_RDONLY;
rc = mount(c_source, c_target, "ext4", flags, NULL);
}
diff --git a/fs/Vfat.cpp b/fs/Vfat.cpp
index dc1fe33..538178e 100644
--- a/fs/Vfat.cpp
+++ b/fs/Vfat.cpp
@@ -35,12 +35,8 @@
#include <linux/kdev_t.h>
-#define LOG_TAG "Vold"
-
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
#include <selinux/selinux.h>
#include <logwrap/logwrap.h>
@@ -65,11 +61,6 @@
}
status_t Check(const std::string& source) {
- if (access(kFsckPath, X_OK)) {
- SLOGW("Skipping fs checks\n");
- return 0;
- }
-
int pass = 1;
int rc = 0;
do {
@@ -83,38 +74,37 @@
rc = ForkExecvp(cmd, sFsckUntrustedContext);
if (rc < 0) {
- SLOGE("Filesystem check failed due to logwrap error");
+ LOG(ERROR) << "Filesystem check failed due to logwrap error";
errno = EIO;
return -1;
}
switch(rc) {
case 0:
- SLOGI("Filesystem check completed OK");
+ LOG(INFO) << "Filesystem check completed OK";
return 0;
case 2:
- SLOGE("Filesystem check failed (not a FAT filesystem)");
+ LOG(ERROR) << "Filesystem check failed (not a FAT filesystem)";
errno = ENODATA;
return -1;
case 4:
if (pass++ <= 3) {
- SLOGW("Filesystem modified - rechecking (pass %d)",
- pass);
+ LOG(WARNING) << "Filesystem modified - rechecking (pass " << pass << ")";
continue;
}
- SLOGE("Failing check after too many rechecks");
+ LOG(ERROR) << "Failing check after too many rechecks";
errno = EIO;
return -1;
case 8:
- SLOGE("Filesystem check failed (no filesystem)");
+ LOG(ERROR) << "Filesystem check failed (no filesystem)";
errno = ENODATA;
return -1;
default:
- SLOGE("Filesystem check failed (unknown exit code %d)", rc);
+ LOG(ERROR) << "Filesystem check failed (unknown exit code " << rc << ")";
errno = EIO;
return -1;
}
@@ -128,7 +118,6 @@
bool createLost) {
int rc;
unsigned long flags;
- char mountData[255];
const char* c_source = source.c_str();
const char* c_target = target.c_str();
@@ -139,31 +128,29 @@
flags |= (ro ? MS_RDONLY : 0);
flags |= (remount ? MS_REMOUNT : 0);
- snprintf(mountData, sizeof(mountData),
+ auto mountData = android::base::StringPrintf(
"utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
ownerUid, ownerGid, permMask, permMask);
- rc = mount(c_source, c_target, "vfat", flags, mountData);
+ rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
if (rc && errno == EROFS) {
- SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
+ LOG(ERROR) << source << " appears to be a read only filesystem - retrying mount RO";
flags |= MS_RDONLY;
- rc = mount(c_source, c_target, "vfat", flags, mountData);
+ rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
}
if (rc == 0 && createLost) {
- char *lost_path;
- asprintf(&lost_path, "%s/LOST.DIR", c_target);
- if (access(lost_path, F_OK)) {
+ auto lost_path = android::base::StringPrintf("%s/LOST.DIR", target.c_str());
+ if (access(lost_path.c_str(), F_OK)) {
/*
* Create a LOST.DIR in the root so we have somewhere to put
* lost cluster chains (fsck_msdos doesn't currently do this)
*/
- if (mkdir(lost_path, 0755)) {
- SLOGE("Unable to create LOST.DIR (%s)", strerror(errno));
+ if (mkdir(lost_path.c_str(), 0755)) {
+ PLOG(ERROR) << "Unable to create LOST.DIR";
}
}
- free(lost_path);
}
return rc;
@@ -189,16 +176,16 @@
int rc = ForkExecvp(cmd);
if (rc < 0) {
- SLOGE("Filesystem format failed due to logwrap error");
+ LOG(ERROR) << "Filesystem format failed due to logwrap error";
errno = EIO;
return -1;
}
if (rc == 0) {
- SLOGI("Filesystem formatted OK");
+ LOG(INFO) << "Filesystem formatted OK";
return 0;
} else {
- SLOGE("Format failed (unknown exit code %d)", rc);
+ LOG(ERROR) << "Format failed (unknown exit code " << rc << ")";
errno = EIO;
return -1;
}
diff --git a/main.cpp b/main.cpp
index 30c839e..01a2168 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-#include "Disk.h"
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "model/Disk.h"
#include "VolumeManager.h"
-#include "CommandListener.h"
-#include "CryptCommandListener.h"
#include "NetlinkManager.h"
+#include "VoldNativeService.h"
+#include "VoldUtil.h"
#include "cryptfs.h"
#include "sehandle.h"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/klog.h>
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
+#include <utils/Trace.h>
#include <stdio.h>
#include <stdlib.h>
@@ -43,8 +45,6 @@
static void coldboot(const char *path);
static void parse_args(int argc, char** argv);
-struct fstab *fstab;
-
struct selabel_handle *sehandle;
using android::base::StringPrintf;
@@ -53,6 +53,8 @@
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+ ATRACE_BEGIN("main");
+
LOG(INFO) << "Vold 3.0 (the awakening) firing up";
LOG(VERBOSE) << "Detected support for:"
@@ -61,8 +63,6 @@
<< (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager *vm;
- CommandListener *cl;
- CryptCommandListener *ccl;
NetlinkManager *nm;
parse_args(argc, argv);
@@ -72,10 +72,6 @@
selinux_android_set_sehandle(sehandle);
}
- // Quickly throw a CLOEXEC on the socket we just inherited from init
- fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
- fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);
-
mkdir("/dev/block/vold", 0755);
/* For when cryptfs checks and mounts an encrypted filesystem */
@@ -92,15 +88,10 @@
exit(1);
}
- if (property_get_bool("vold.debug", false)) {
+ if (android::base::GetBoolProperty("vold.debug", false)) {
vm->setDebug(true);
}
- cl = new CommandListener();
- ccl = new CryptCommandListener();
- vm->setBroadcaster((SocketListener *) cl);
- nm->setBroadcaster((SocketListener *) cl);
-
if (vm->start()) {
PLOG(ERROR) << "Unable to start VolumeManager";
exit(1);
@@ -113,39 +104,35 @@
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
+ ATRACE_BEGIN("VoldNativeService::start");
+ if (android::vold::VoldNativeService::start() != android::OK) {
+ LOG(ERROR) << "Unable to start VoldNativeService";
+ exit(1);
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("NetlinkManager::start");
if (nm->start()) {
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
-
- /*
- * Now that we're up, we can respond to commands
- */
- if (cl->startListener()) {
- PLOG(ERROR) << "Unable to start CommandListener";
- exit(1);
- }
-
- if (ccl->startListener()) {
- PLOG(ERROR) << "Unable to start CryptCommandListener";
- exit(1);
- }
+ ATRACE_END();
// This call should go after listeners are started to avoid
// a deadlock between vold and init (see b/34278978 for details)
- property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
- property_set("vold.has_quota", has_quota ? "1" : "0");
+ android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0");
+ android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0");
// Do coldboot here so it won't block booting,
// also the cold boot is needed in case we have flash drive
// connected before Vold launched
coldboot("/sys/block");
- // Eventually we'll become the monitoring thread
- while(1) {
- pause();
- }
- LOG(ERROR) << "Vold exiting";
+ ATRACE_END();
+
+ android::IPCThreadState::self()->joinThreadPool();
+ LOG(INFO) << "vold shutting down";
+
exit(0);
}
@@ -209,6 +196,7 @@
}
static void coldboot(const char *path) {
+ ATRACE_NAME("coldboot");
DIR *d = opendir(path);
if(d) {
do_coldboot(d, 0);
@@ -217,8 +205,10 @@
}
static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
+ ATRACE_NAME("process_config");
+
+ fstab_default = fs_mgr_read_fstab_default();
+ if (!fstab_default) {
PLOG(ERROR) << "Failed to open default fstab";
return -1;
}
@@ -226,27 +216,28 @@
/* Loop through entries looking for ones that vold manages */
*has_adoptable = false;
*has_quota = false;
- for (int i = 0; i < fstab->num_entries; i++) {
- if (fs_mgr_is_quota(&fstab->recs[i])) {
+ for (int i = 0; i < fstab_default->num_entries; i++) {
+ auto rec = &fstab_default->recs[i];
+ if (fs_mgr_is_quota(rec)) {
*has_quota = true;
}
- if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
- if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
+ if (fs_mgr_is_voldmanaged(rec)) {
+ if (fs_mgr_is_nonremovable(rec)) {
LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
continue;
}
- std::string sysPattern(fstab->recs[i].blk_device);
- std::string nickname(fstab->recs[i].label);
+ std::string sysPattern(rec->blk_device);
+ std::string nickname(rec->label);
int flags = 0;
- if (fs_mgr_is_encryptable(&fstab->recs[i])) {
+ if (fs_mgr_is_encryptable(rec)) {
flags |= android::vold::Disk::Flags::kAdoptable;
*has_adoptable = true;
}
- if (fs_mgr_is_noemulatedsd(&fstab->recs[i])
- || property_get_bool("vold.debug.default_primary", false)) {
+ if (fs_mgr_is_noemulatedsd(rec)
+ || android::base::GetBoolProperty("vold.debug.default_primary", false)) {
flags |= android::vold::Disk::Flags::kDefaultPrimary;
}
diff --git a/Disk.cpp b/model/Disk.cpp
similarity index 84%
rename from Disk.cpp
rename to model/Disk.cpp
index 9c22400..14de74f 100644
--- a/Disk.cpp
+++ b/model/Disk.cpp
@@ -20,14 +20,15 @@
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include "Ext4Crypt.h"
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
-#include <android-base/logging.h>
-#include <diskconfig/diskconfig.h>
+#include <android-base/strings.h>
+#include <android-base/parseint.h>
+#include <ext4_utils/ext4_crypt.h>
#include <vector>
#include <fcntl.h>
@@ -151,7 +152,10 @@
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
- notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
+
+ auto listener = VolumeManager::Instance()->getListener();
+ if (listener) listener->onDiskCreated(getId(), mFlags);
+
readMetadata();
readPartitions();
return OK;
@@ -161,7 +165,10 @@
CHECK(mCreated);
destroyAllVolumes();
mCreated = false;
- notifyEvent(ResponseCode::DiskDestroyed);
+
+ auto listener = VolumeManager::Instance()->getListener();
+ if (listener) listener->onDiskDestroyed(getId());
+
return OK;
}
@@ -257,7 +264,11 @@
PLOG(WARNING) << "Failed to read manufacturer from " << path;
return -errno;
}
- uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);
+ int64_t manfid;
+ if (!android::base::ParseInt(tmp, &manfid)) {
+ PLOG(WARNING) << "Failed to parse manufacturer " << tmp;
+ return -EINVAL;
+ }
// Our goal here is to give the user a meaningful label, ideally
// matching whatever is silk-screened on the card. To reduce
// user confusion, this list doesn't contain white-label manfid.
@@ -281,14 +292,15 @@
}
}
- notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));
- notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
- notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
+ auto listener = VolumeManager::Instance()->getListener();
+ if (listener) listener->onDiskMetadataChanged(getId(),
+ mSize, mLabel, mSysPath);
+
return OK;
}
status_t Disk::readPartitions() {
- int8_t maxMinors = getMaxMinors();
+ int maxMinors = getMaxMinors();
if (maxMinors < 0) {
return -ENOTSUP;
}
@@ -306,7 +318,10 @@
status_t res = ForkExecvp(cmd, output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
- notifyEvent(ResponseCode::DiskScanned);
+
+ auto listener = VolumeManager::Instance()->getListener();
+ if (listener) listener->onDiskScanned(getId());
+
mJustPartitioned = false;
return res;
}
@@ -314,31 +329,40 @@
Table table = Table::kUnknown;
bool foundParts = false;
for (const auto& line : output) {
- char* cline = (char*) line.c_str();
- char* token = strtok(cline, kSgdiskToken);
- if (token == nullptr) continue;
+ auto split = android::base::Split(line, kSgdiskToken);
+ auto it = split.begin();
+ if (it == split.end()) continue;
- if (!strcmp(token, "DISK")) {
- const char* type = strtok(nullptr, kSgdiskToken);
- if (!strcmp(type, "mbr")) {
+ if (*it == "DISK") {
+ if (++it == split.end()) continue;
+ if (*it == "mbr") {
table = Table::kMbr;
- } else if (!strcmp(type, "gpt")) {
+ } else if (*it == "gpt") {
table = Table::kGpt;
+ } else {
+ LOG(WARNING) << "Invalid partition table " << *it;
+ continue;
}
- } else if (!strcmp(token, "PART")) {
+ } else if (*it == "PART") {
foundParts = true;
- int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);
- if (i <= 0 || i > maxMinors) {
- LOG(WARNING) << mId << " is ignoring partition " << i
- << " beyond max supported devices";
+
+ if (++it == split.end()) continue;
+ int i = 0;
+ if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {
+ LOG(WARNING) << "Invalid partition number " << *it;
continue;
}
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
if (table == Table::kMbr) {
- const char* type = strtok(nullptr, kSgdiskToken);
+ if (++it == split.end()) continue;
+ int type = 0;
+ if (!android::base::ParseInt("0x" + *it, &type)) {
+ LOG(WARNING) << "Invalid partition type " << *it;
+ continue;
+ }
- switch (strtol(type, nullptr, 16)) {
+ switch (type) {
case 0x06: // FAT16
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
@@ -347,12 +371,14 @@
break;
}
} else if (table == Table::kGpt) {
- const char* typeGuid = strtok(nullptr, kSgdiskToken);
- const char* partGuid = strtok(nullptr, kSgdiskToken);
+ if (++it == split.end()) continue;
+ auto typeGuid = *it;
+ if (++it == split.end()) continue;
+ auto partGuid = *it;
- if (!strcasecmp(typeGuid, kGptBasicData)) {
+ if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
- } else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {
+ } else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) {
createPrivateVolume(partDevice, partGuid);
}
}
@@ -365,14 +391,16 @@
std::string fsType;
std::string unused;
- if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {
+ if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK) {
createPublicVolume(mDevice);
} else {
LOG(WARNING) << mId << " failed to identify, giving up";
}
}
- notifyEvent(ResponseCode::DiskScanned);
+ auto listener = VolumeManager::Instance()->getListener();
+ if (listener) listener->onDiskScanned(getId());
+
mJustPartitioned = false;
return OK;
}
@@ -387,7 +415,6 @@
status_t Disk::partitionPublic() {
int res;
- // TODO: improve this code
destroyAllVolumes();
mJustPartitioned = true;
@@ -403,41 +430,21 @@
LOG(WARNING) << "Failed to zap; status " << res;
}
- struct disk_info dinfo;
- memset(&dinfo, 0, sizeof(dinfo));
+ // Now let's build the new MBR table. We heavily rely on sgdisk to
+ // force optimal alignment on the created partitions.
+ cmd.clear();
+ cmd.push_back(kSgdiskPath);
+ cmd.push_back("--new=0:0:-0");
+ cmd.push_back("--typecode=0:0c00");
+ cmd.push_back("--gpttombr=1");
+ cmd.push_back(mDevPath);
- if (!(dinfo.part_lst = (struct part_info *) malloc(
- MAX_NUM_PARTS * sizeof(struct part_info)))) {
- return -1;
+ if ((res = ForkExecvp(cmd)) != 0) {
+ LOG(ERROR) << "Failed to partition; status " << res;
+ return res;
}
- memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
- dinfo.device = strdup(mDevPath.c_str());
- dinfo.scheme = PART_SCHEME_MBR;
- dinfo.sect_size = 512;
- dinfo.skip_lba = 2048;
- dinfo.num_lba = 0;
- dinfo.num_parts = 1;
-
- struct part_info *pinfo = &dinfo.part_lst[0];
-
- pinfo->name = strdup("android_sdcard");
- pinfo->flags |= PART_ACTIVE_FLAG;
- pinfo->type = PC_PART_TYPE_FAT32;
- pinfo->len_kb = -1;
-
- int rc = apply_disk_config(&dinfo, 0);
- if (rc) {
- LOG(ERROR) << "Failed to apply disk configuration: " << rc;
- goto out;
- }
-
-out:
- free(pinfo->name);
- free(dinfo.device);
- free(dinfo.part_lst);
-
- return rc;
+ return OK;
}
status_t Disk::partitionPrivate() {
@@ -534,16 +541,6 @@
return OK;
}
-void Disk::notifyEvent(int event) {
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
- getId().c_str(), false);
-}
-
-void Disk::notifyEvent(int event, const std::string& value) {
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
- StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
-}
-
int Disk::getMaxMinors() {
// Figure out maximum partition devices supported
unsigned int majorId = major(mDevice);
@@ -554,7 +551,7 @@
LOG(ERROR) << "Failed to read max minors";
return -errno;
}
- return atoi(tmp.c_str());
+ return std::stoi(tmp);
}
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
@@ -570,7 +567,7 @@
LOG(ERROR) << "Failed to read max minors";
return -errno;
}
- return atoi(tmp.c_str());
+ return std::stoi(tmp);
}
default: {
if (isVirtioBlkDevice(majorId)) {
diff --git a/Disk.h b/model/Disk.h
similarity index 97%
rename from Disk.h
rename to model/Disk.h
index 77ec7df..63acf6a 100644
--- a/Disk.h
+++ b/model/Disk.h
@@ -79,9 +79,6 @@
status_t partitionPrivate();
status_t partitionMixed(int8_t ratio);
- void notifyEvent(int msg);
- void notifyEvent(int msg, const std::string& value);
-
private:
/* ID that uniquely references this disk */
std::string mId;
diff --git a/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
similarity index 92%
rename from EmulatedVolume.cpp
rename to model/EmulatedVolume.cpp
index 21b290a..d40cf3f 100644
--- a/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
+#include <utils/Timers.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -100,9 +101,16 @@
return -errno;
}
+ nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
while (before == GetDevice(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
+
+ nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
+ if (nanoseconds_to_milliseconds(now - start) > 5000) {
+ LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
+ return -ETIMEDOUT;
+ }
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
diff --git a/EmulatedVolume.h b/model/EmulatedVolume.h
similarity index 100%
rename from EmulatedVolume.h
rename to model/EmulatedVolume.h
diff --git a/model/ObbVolume.cpp b/model/ObbVolume.cpp
new file mode 100644
index 0000000..709c7a3
--- /dev/null
+++ b/model/ObbVolume.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 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 "fs/Vfat.h"
+#include "Devmapper.h"
+#include "Loop.h"
+#include "ObbVolume.h"
+#include "Utils.h"
+#include "VoldUtil.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <private/android_filesystem_config.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/wait.h>
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace vold {
+
+ObbVolume::ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+ gid_t ownerGid) : VolumeBase(Type::kObb) {
+ setId(StringPrintf("obb:%d", id));
+ mSourcePath = sourcePath;
+ mSourceKey = sourceKey;
+ mOwnerGid = ownerGid;
+}
+
+ObbVolume::~ObbVolume() {
+}
+
+status_t ObbVolume::doCreate() {
+ if (Loop::create(mSourcePath, mLoopPath)) {
+ PLOG(ERROR) << getId() << " failed to create loop";
+ return -1;
+ }
+
+ if (!mSourceKey.empty()) {
+ unsigned long nr_sec = 0;
+ {
+ unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC));
+ if (loop_fd.get() == -1) {
+ PLOG(ERROR) << getId() << " failed to open loop";
+ return -1;
+ }
+
+ get_blkdev_size(loop_fd.get(), &nr_sec);
+ if (nr_sec == 0) {
+ PLOG(ERROR) << getId() << " failed to get loop size";
+ return -1;
+ }
+ }
+
+ char tmp[PATH_MAX];
+ if (Devmapper::create(getId().c_str(), mLoopPath.c_str(), mSourceKey.c_str(), nr_sec,
+ tmp, PATH_MAX)) {
+ PLOG(ERROR) << getId() << " failed to create dm";
+ return -1;
+ }
+ mDmPath = tmp;
+ mMountPath = mDmPath;
+ } else {
+ mMountPath = mLoopPath;
+ }
+ return OK;
+}
+
+status_t ObbVolume::doDestroy() {
+ if (!mDmPath.empty() && Devmapper::destroy(getId().c_str())) {
+ PLOG(WARNING) << getId() << " failed to destroy dm";
+ }
+ if (!mLoopPath.empty() && Loop::destroyByDevice(mLoopPath.c_str())) {
+ PLOG(WARNING) << getId() << " failed to destroy loop";
+ }
+ mDmPath.clear();
+ mLoopPath.clear();
+ return OK;
+}
+
+status_t ObbVolume::doMount() {
+ auto path = StringPrintf("/mnt/obb/%s", getId().c_str());
+ setPath(path);
+
+ if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
+ PLOG(ERROR) << getId() << " failed to create mount point";
+ return -1;
+ }
+ if (android::vold::vfat::Mount(mMountPath, path,
+ true, false, true, 0, mOwnerGid, 0227, false)) {
+ PLOG(ERROR) << getId() << " failed to mount";
+ return -1;
+ }
+ return OK;
+}
+
+status_t ObbVolume::doUnmount() {
+ auto path = getPath();
+
+ KillProcessesUsingPath(path);
+ ForceUnmount(path);
+ rmdir(path.c_str());
+
+ return OK;
+}
+
+} // namespace vold
+} // namespace android
diff --git a/model/ObbVolume.h b/model/ObbVolume.h
new file mode 100644
index 0000000..5ec0cde
--- /dev/null
+++ b/model/ObbVolume.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_VOLD_OBB_VOLUME_H
+#define ANDROID_VOLD_OBB_VOLUME_H
+
+#include "VolumeBase.h"
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace vold {
+
+/*
+ * OBB container.
+ */
+class ObbVolume : public VolumeBase {
+public:
+ ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+ gid_t ownerGid);
+ virtual ~ObbVolume();
+
+protected:
+ status_t doCreate() override;
+ status_t doDestroy() override;
+ status_t doMount() override;
+ status_t doUnmount() override;
+
+private:
+ std::string mSourcePath;
+ std::string mSourceKey;
+ gid_t mOwnerGid;
+
+ std::string mLoopPath;
+ std::string mDmPath;
+ std::string mMountPath;
+
+ DISALLOW_COPY_AND_ASSIGN(ObbVolume);
+};
+
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/PrivateVolume.cpp b/model/PrivateVolume.cpp
similarity index 95%
rename from PrivateVolume.cpp
rename to model/PrivateVolume.cpp
index e66e04d..48d041b 100644
--- a/PrivateVolume.cpp
+++ b/model/PrivateVolume.cpp
@@ -20,7 +20,6 @@
#include "EmulatedVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include "cryptfs.h"
#include <android-base/stringprintf.h>
@@ -54,10 +53,11 @@
}
status_t PrivateVolume::readMetadata() {
- status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel);
- notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
- notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
- notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
+ status_t res = ReadMetadata(mDmDevPath, &mFsType, &mFsUuid, &mFsLabel);
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
+
return res;
}
diff --git a/PrivateVolume.h b/model/PrivateVolume.h
similarity index 100%
rename from PrivateVolume.h
rename to model/PrivateVolume.h
diff --git a/PublicVolume.cpp b/model/PublicVolume.cpp
similarity index 92%
rename from PublicVolume.cpp
rename to model/PublicVolume.cpp
index f976c4a..98c897f 100644
--- a/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -18,12 +18,12 @@
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
+#include <utils/Timers.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -52,10 +52,11 @@
}
status_t PublicVolume::readMetadata() {
- status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
- notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
- notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
- notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
+ status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
+
return res;
}
@@ -186,9 +187,16 @@
return -errno;
}
+ nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
while (before == GetDevice(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
+
+ nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
+ if (nanoseconds_to_milliseconds(now - start) > 5000) {
+ LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
+ return -ETIMEDOUT;
+ }
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
diff --git a/PublicVolume.h b/model/PublicVolume.h
similarity index 100%
rename from PublicVolume.h
rename to model/PublicVolume.h
diff --git a/VolumeBase.cpp b/model/VolumeBase.cpp
similarity index 86%
rename from VolumeBase.cpp
rename to model/VolumeBase.cpp
index 3f27d87..429f134 100644
--- a/VolumeBase.cpp
+++ b/model/VolumeBase.cpp
@@ -17,7 +17,6 @@
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
-#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
@@ -44,7 +43,9 @@
void VolumeBase::setState(State state) {
mState = state;
- notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState));
}
status_t VolumeBase::setDiskId(const std::string& diskId) {
@@ -114,7 +115,10 @@
}
mPath = path;
- notifyEvent(ResponseCode::VolumePathChanged, mPath);
+
+ auto listener = getListener();
+ if (listener) listener->onVolumePathChanged(getId(), mPath);
+
return OK;
}
@@ -125,20 +129,19 @@
}
mInternalPath = internalPath;
- notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath);
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath);
+
return OK;
}
-void VolumeBase::notifyEvent(int event) {
- if (mSilent) return;
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
- getId().c_str(), false);
-}
-
-void VolumeBase::notifyEvent(int event, const std::string& value) {
- if (mSilent) return;
- VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
- StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
+android::sp<android::os::IVoldListener> VolumeBase::getListener() {
+ if (mSilent) {
+ return nullptr;
+ } else {
+ return VolumeManager::Instance()->getListener();
+ }
}
void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
@@ -163,8 +166,11 @@
mCreated = true;
status_t res = doCreate();
- notifyEvent(ResponseCode::VolumeCreated,
- StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeCreated(getId(),
+ static_cast<int32_t>(mType), mDiskId, mPartGuid);
+
setState(State::kUnmounted);
return res;
}
@@ -183,7 +189,10 @@
setState(State::kRemoved);
}
- notifyEvent(ResponseCode::VolumeDestroyed);
+
+ auto listener = getListener();
+ if (listener) listener->onVolumeDestroyed(getId());
+
status_t res = doDestroy();
mCreated = false;
return res;
diff --git a/VolumeBase.h b/model/VolumeBase.h
similarity index 97%
rename from VolumeBase.h
rename to model/VolumeBase.h
index d417019..4aa8b02 100644
--- a/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_VOLD_VOLUME_BASE_H
#define ANDROID_VOLD_VOLUME_BASE_H
+#include "android/os/IVoldListener.h"
#include "Utils.h"
#include <cutils/multiuser.h>
@@ -114,8 +115,7 @@
status_t setPath(const std::string& path);
status_t setInternalPath(const std::string& internalPath);
- void notifyEvent(int msg);
- void notifyEvent(int msg, const std::string& value);
+ android::sp<android::os::IVoldListener> getListener();
private:
/* ID that uniquely references volume while alive */
diff --git a/secontext.h b/secontext.h
index 08ad48e..f5339c8 100644
--- a/secontext.h
+++ b/secontext.h
@@ -18,8 +18,6 @@
#include <selinux/selinux.h>
-__BEGIN_DECLS
security_context_t secontextFsck();
-__END_DECLS
#endif
diff --git a/tests/Android.bp b/tests/Android.bp
new file mode 100644
index 0000000..a070178
--- /dev/null
+++ b/tests/Android.bp
@@ -0,0 +1,14 @@
+cc_test {
+ name: "vold_tests",
+ defaults: [
+ "vold_default_flags",
+ "vold_default_libs",
+ ],
+
+ srcs: [
+ "CryptfsScryptHidlizationEquivalence_test.cpp",
+ "Utils_test.cpp",
+ "cryptfs_test.cpp",
+ ],
+ static_libs: ["libvold"],
+}
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 5b8ff09..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_C_INCLUDES := \
- system/core/fs_mgr/include
-
-LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
-
-LOCAL_SRC_FILES := VolumeManager_test.cpp
-LOCAL_MODULE := vold_tests
-LOCAL_MODULE_TAGS := eng tests
-
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-# LOCAL_C_INCLUDES := \
- system/core/fs_mgr/include
-
-LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
-LOCAL_SHARED_LIBRARIES := \
- libutils \
- libbase \
- libhardware \
- libhardware_legacy \
- libhwbinder \
- libhidlbase \
- libkeystore_binder \
- android.hardware.keymaster@3.0
-
-LOCAL_SRC_FILES := CryptfsScryptHidlizationEquivalence_test.cpp
-LOCAL_MODULE := vold_cryptfs_scrypt_hidlization_equivalence_test
-LOCAL_MODULE_TAGS := eng tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/tests/CryptfsScryptHidlizationEquivalence_test.cpp b/tests/CryptfsScryptHidlizationEquivalence_test.cpp
index 91ddb2b..3a6c029 100644
--- a/tests/CryptfsScryptHidlizationEquivalence_test.cpp
+++ b/tests/CryptfsScryptHidlizationEquivalence_test.cpp
@@ -369,6 +369,7 @@
return keymaster_compatibility_cryptfs_scrypt();
}
+#if 0
/* Create a new keymaster key and store it in this footer */
static int keymaster_create_key_new(struct crypt_mnt_ftr *ftr)
{
@@ -390,6 +391,7 @@
}
return 0;
}
+#endif
/* This signs the given object using the keymaster key. */
static int keymaster_sign_object_new(struct crypt_mnt_ftr *ftr,
diff --git a/tests/Utils_test.cpp b/tests/Utils_test.cpp
new file mode 100644
index 0000000..ab9809e
--- /dev/null
+++ b/tests/Utils_test.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "../Utils.h"
+
+namespace android {
+namespace vold {
+
+class UtilsTest : public testing::Test {
+};
+
+TEST_F(UtilsTest, FindValueTest) {
+ std::string tmp;
+
+ ASSERT_FALSE(FindValue("", "KEY", &tmp));
+ ASSERT_FALSE(FindValue("BADKEY=\"VALUE\"", "KEY", &tmp));
+
+ ASSERT_TRUE(FindValue("KEY=\"VALUE\"", "KEY", &tmp));
+ ASSERT_EQ("VALUE", tmp);
+
+ ASSERT_TRUE(FindValue("FOO=\"BAR\" KEY=\"VALUE VALUE\" BAR=\"BAZ\"", "KEY", &tmp));
+ ASSERT_EQ("VALUE VALUE", tmp);
+
+ ASSERT_TRUE(FindValue("BADKEY=\"VALUE\" KEY=\"BAZ\"", "KEY", &tmp));
+ ASSERT_EQ("BAZ", tmp);
+}
+
+}
+}
diff --git a/tests/VolumeManager_test.cpp b/tests/VolumeManager_test.cpp
deleted file mode 100644
index c0c1fa5..0000000
--- a/tests/VolumeManager_test.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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 <errno.h>
-
-#define LOG_TAG "VolumeManager_test"
-#include <utils/Log.h>
-#include <openssl/md5.h>
-#include "../VolumeManager.h"
-
-#include <gtest/gtest.h>
-
-namespace android {
-
-class VolumeManagerTest : public testing::Test {
-protected:
- virtual void SetUp() {
- }
-
- virtual void TearDown() {
- }
-};
-
-TEST_F(VolumeManagerTest, AsecHashTests) {
- char buffer[MD5_ASCII_LENGTH_PLUS_NULL];
- char* dst = reinterpret_cast<char*>(&buffer);
-
- const char* src1 = "";
- const char* exp1 = "d41d8cd98f00b204e9800998ecf8427e";
-
- EXPECT_TRUE(VolumeManager::asecHash(exp1, (char*)NULL, sizeof(buffer)) == NULL && errno == ESPIPE)
- << "Should return NULL and set errno to ESPIPE when destination buffer is NULL";
- EXPECT_TRUE(VolumeManager::asecHash(exp1, dst, 0) == NULL && errno == ESPIPE)
- << "Should return NULL and set errno to ESPIPE when destination buffer length is 0";
- EXPECT_TRUE(VolumeManager::asecHash((const char*)NULL, dst, sizeof(buffer)) == NULL && errno == ESPIPE)
- << "Should return NULL and set errno to ESPIPE when source buffer is NULL";
-
- EXPECT_FALSE(VolumeManager::asecHash(src1, dst, sizeof(buffer)) == NULL)
- << "Should not return NULL on valid source, destination, and destination size";
- EXPECT_STREQ(exp1, dst)
- << "MD5 summed output should match";
-
- const char* src2 = "android";
- const char* exp2 = "c31b32364ce19ca8fcd150a417ecce58";
- EXPECT_FALSE(VolumeManager::asecHash(src2, dst, sizeof(buffer)) == NULL)
- << "Should not return NULL on valid source, destination, and destination size";
- EXPECT_STREQ(exp2, dst)
- << "MD5 summed output should match";
-}
-
-}
diff --git a/tests/cryptfs_test.cpp b/tests/cryptfs_test.cpp
new file mode 100644
index 0000000..6875c0f
--- /dev/null
+++ b/tests/cryptfs_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "../cryptfs.h"
+
+namespace android {
+
+class CryptfsTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(CryptfsTest, MatchMultiEntryTest) {
+ ASSERT_NE(0, match_multi_entry("foo", "foo", 0));
+ ASSERT_NE(0, match_multi_entry("foo_0", "foo", 0));
+ ASSERT_NE(0, match_multi_entry("foo_1", "foo", 0));
+ ASSERT_NE(0, match_multi_entry("foo_2", "foo", 0));
+
+ ASSERT_EQ(0, match_multi_entry("foo", "foo", 1));
+ ASSERT_EQ(0, match_multi_entry("foo_0", "foo", 1));
+ ASSERT_NE(0, match_multi_entry("foo_1", "foo", 1));
+ ASSERT_NE(0, match_multi_entry("foo_2", "foo", 1));
+
+ ASSERT_EQ(0, match_multi_entry("foo", "foo", 2));
+ ASSERT_EQ(0, match_multi_entry("foo_0", "foo", 2));
+ ASSERT_EQ(0, match_multi_entry("foo_1", "foo", 2));
+ ASSERT_NE(0, match_multi_entry("foo_2", "foo", 2));
+
+ ASSERT_EQ(0, match_multi_entry("food", "foo", 0));
+ ASSERT_EQ(0, match_multi_entry("foo", "food", 0));
+ ASSERT_EQ(0, match_multi_entry("foo", "bar", 0));
+ ASSERT_EQ(0, match_multi_entry("foo_2", "bar", 0));
+}
+
+}
diff --git a/vdc.cpp b/vdc.cpp
index 7ab5fcc..19eb379 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -24,158 +24,91 @@
#include <stdlib.h>
#include <poll.h>
-#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
+#include "android/os/IVold.h"
+
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
-#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
static void usage(char *progname);
-static int do_monitor(int sock, int stop_after_cmd);
-static int do_cmd(int sock, int argc, char **argv);
-static constexpr int kCommandTimeoutMs = 20 * 1000;
+static android::sp<android::IBinder> getServiceAggressive() {
+ android::sp<android::IBinder> res;
+ auto sm = android::defaultServiceManager();
+ auto name = android::String16("vold");
+ for (int i = 0; i < 500; i++) {
+ res = sm->checkService(name);
+ if (res) {
+ LOG(VERBOSE) << "Waited " << (i * 10) << "ms for vold";
+ break;
+ }
+ usleep(10000); // 10ms
+ }
+ return res;
+}
-int main(int argc, char **argv) {
- int sock;
- int wait_for_socket;
- char *progname;
+static void checkStatus(android::binder::Status status) {
+ if (status.isOk()) return;
+ LOG(ERROR) << "Failed: " << status.toString8().string();
+ exit(ENOTTY);
+}
- progname = argv[0];
-
+int main(int argc, char** argv) {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
if (getppid() == 1) {
// If init is calling us then it's during boot and we should log to kmsg
android::base::InitLogging(argv, &android::base::KernelLogger);
} else {
android::base::InitLogging(argv, &android::base::StderrLogger);
}
+ std::vector<std::string> args(argv + 1, argv + argc);
- wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0;
- if (wait_for_socket) {
- argv++;
- argc--;
+ if (args.size() > 0 && args[0] == "--wait") {
+ // Just ignore the --wait flag
+ args.erase(args.begin());
}
- if (argc < 2) {
- usage(progname);
+ if (args.size() < 2) {
+ usage(argv[0]);
exit(5);
}
-
- const char* sockname = "vold";
- if (!strcmp(argv[1], "cryptfs")) {
- sockname = "cryptd";
+ android::sp<android::IBinder> binder = getServiceAggressive();
+ if (!binder) {
+ LOG(ERROR) << "Failed to obtain vold Binder";
+ exit(EINVAL);
}
+ auto vold = android::interface_cast<android::os::IVold>(binder);
- while ((sock = socket_local_client(sockname,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM)) < 0) {
- if (!wait_for_socket) {
- PLOG(ERROR) << "Error connecting to " << sockname;
- exit(4);
- } else {
- usleep(10000);
- }
- }
-
- if (!strcmp(argv[1], "monitor")) {
- exit(do_monitor(sock, 0));
+ if (args[0] == "cryptfs" && args[1] == "enablefilecrypto") {
+ checkStatus(vold->fbeEnable());
+ } else if (args[0] == "cryptfs" && args[1] == "init_user0") {
+ checkStatus(vold->initUser0());
+ } else if (args[0] == "cryptfs" && args[1] == "enablecrypto") {
+ int passwordType = android::os::IVold::PASSWORD_TYPE_DEFAULT;
+ int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_IN_PLACE
+ | android::os::IVold::ENCRYPTION_FLAG_NO_UI;
+ checkStatus(vold->fdeEnable(passwordType, "", encryptionFlags));
+ } else if (args[0] == "cryptfs" && args[1] == "mountdefaultencrypted") {
+ checkStatus(vold->mountDefaultEncrypted());
+ } else if (args[0] == "volume" && args[1] == "shutdown") {
+ checkStatus(vold->shutdown());
+ } else if (args[0] == "cryptfs" && args[1] == "checkEncryption" && args.size() == 3) {
+ checkStatus(vold->checkEncryption(args[2]));
} else {
- exit(do_cmd(sock, argc, argv));
+ LOG(ERROR) << "Raw commands are no longer supported";
+ exit(EINVAL);
}
-}
-
-static int do_cmd(int sock, int argc, char **argv) {
- int seq = getpid();
-
- std::string cmd(android::base::StringPrintf("%d ", seq));
- for (int i = 1; i < argc; i++) {
- if (!strchr(argv[i], ' ')) {
- cmd.append(argv[i]);
- } else {
- cmd.push_back('\"');
- cmd.append(argv[i]);
- cmd.push_back('\"');
- }
-
- if (i < argc - 1) {
- cmd.push_back(' ');
- }
- }
-
- if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
- PLOG(ERROR) << "Failed to write command";
- return errno;
- }
-
- return do_monitor(sock, seq);
-}
-
-static int do_monitor(int sock, int stop_after_seq) {
- char buffer[4096];
- int timeout = kCommandTimeoutMs;
-
- if (stop_after_seq == 0) {
- LOG(INFO) << "Connected to vold";
- timeout = -1;
- }
-
- while (1) {
- struct pollfd poll_sock = { sock, POLLIN, 0 };
- int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, timeout));
- if (rc == 0) {
- LOG(ERROR) << "Timeout waiting for " << stop_after_seq;
- return ETIMEDOUT;
- } else if (rc < 0) {
- PLOG(ERROR) << "Failed during poll";
- return errno;
- }
-
- if (!(poll_sock.revents & POLLIN)) {
- LOG(INFO) << "No data; trying again";
- continue;
- }
-
- memset(buffer, 0, sizeof(buffer));
- rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (rc == 0) {
- LOG(ERROR) << "Lost connection, did vold crash?";
- return ECONNRESET;
- } else if (rc < 0) {
- PLOG(ERROR) << "Error reading data";
- return errno;
- }
-
- int offset = 0;
- for (int i = 0; i < rc; i++) {
- if (buffer[i] == '\0') {
- char* res = buffer + offset;
- fprintf(stdout, "%s\n", res);
-
- int code = atoi(strtok(res, " "));
- if (code >= 200 && code < 600) {
- int seq = atoi(strtok(nullptr, " "));
- if (seq == stop_after_seq) {
- if (code == 200) {
- return 0;
- } else {
- return code;
- }
- }
- }
-
- offset = i + 1;
- }
- }
- }
- return EIO;
+ return 0;
}
static void usage(char *progname) {
- LOG(INFO) << "Usage: " << progname << " [--wait] <monitor>|<cmd> [arg1] [arg2...]";
+ LOG(INFO) << "Usage: " << progname << " [--wait] <system> <subcommand> [args...]";
}
diff --git a/vold.rc b/vold.rc
index 87e2fd8..c27aeda 100644
--- a/vold.rc
+++ b/vold.rc
@@ -2,9 +2,6 @@
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
- socket vold stream 0660 root mount
- socket cryptd stream 0660 root mount
ioprio be 2
writepid /dev/cpuset/foreground/tasks
shutdown critical
-
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
new file mode 100644
index 0000000..02bedde
--- /dev/null
+++ b/vold_prepare_subdirs.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * Tool to create a directory with the right SELinux context applied, or
+ * apply the context if it's absent. Also fixes mode, uid, gid.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+
+#include <cutils/fs.h>
+#include <selinux/android.h>
+
+#include "Utils.h"
+#include "android/os/IVold.h"
+
+static void usage(const char* progname) {
+ std::cerr << "Usage: " << progname << " [ prepare | destroy ] <volume_uuid> <user_id> <flags>"
+ << std::endl;
+ exit(-1);
+}
+
+static bool small_int(const std::string& s) {
+ return !s.empty() && s.size() < 7 && s.find_first_not_of("0123456789") == std::string::npos;
+}
+
+static bool valid_uuid(const std::string& s) {
+ return s.size() < 40 && s.find_first_not_of("0123456789abcdefABCDEF-_") == std::string::npos;
+}
+
+static bool prepare_dir(struct selabel_handle* sehandle, mode_t mode, uid_t uid, gid_t gid,
+ const std::string& path) {
+ auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
+ auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
+ char* tmp_secontext;
+ if (sehandle && selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
+ secontext.reset(tmp_secontext);
+ }
+ LOG(DEBUG) << "Setting up mode " << std::oct << mode << std::dec << " uid " << uid << " gid "
+ << gid << " context " << secontext.get() << " on path: " << path;
+ if (secontext) {
+ if (setfscreatecon(secontext.get()) != 0) {
+ PLOG(ERROR) << "Unable to read setfscreatecon for: " << path;
+ return false;
+ }
+ }
+ if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
+ return false;
+ }
+ if (secontext) {
+ char* tmp_oldsecontext = nullptr;
+ if (lgetfilecon(path.c_str(), &tmp_oldsecontext) < 0) {
+ PLOG(ERROR) << "Unable to read secontext for: " << path;
+ return false;
+ }
+ auto oldsecontext = std::unique_ptr<char, void (*)(char*)>(tmp_oldsecontext, freecon);
+ if (strcmp(secontext.get(), oldsecontext.get()) != 0) {
+ LOG(INFO) << "Relabelling from " << ((char*)oldsecontext.get()) << " to "
+ << ((char*)secontext.get()) << ": " << path;
+ if (lsetfilecon(path.c_str(), secontext.get()) != 0) {
+ PLOG(ERROR) << "Relabelling failed for: " << path;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool rmrf_contents(const std::string& path) {
+ auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(path.c_str()), closedir);
+ if (!dirp) {
+ PLOG(ERROR) << "Unable to open directory: " << path;
+ return false;
+ }
+ bool res = true;
+ for (;;) {
+ errno = 0;
+ auto const entry = readdir(dirp.get());
+ if (!entry) {
+ if (errno) {
+ PLOG(ERROR) << "readdir failed on: " << path;
+ return false;
+ }
+ return res;
+ }
+ if (entry->d_name[0] == '.') continue;
+ auto subdir = path + "/" + entry->d_name;
+ if (0 !=
+ android::vold::ForkExecvp(std::vector<std::string>{"/system/bin/rm", "-rf", subdir})) {
+ LOG(ERROR) << "rm -rf failed on " << subdir;
+ res = false;
+ }
+ }
+}
+
+static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
+ struct selabel_handle* sehandle = selinux_android_file_context_handle();
+
+ if (volume_uuid.empty()) {
+ if (flags & android::os::IVold::STORAGE_FLAG_DE) {
+ auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
+ if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/vold")) return false;
+ if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/storaged")) return false;
+ }
+ if (flags & android::os::IVold::STORAGE_FLAG_CE) {
+ auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
+ if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/vold")) return false;
+ if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/storaged")) return false;
+ }
+ }
+ return true;
+}
+
+static bool destroy_subdirs(const std::string& volume_uuid, int user_id, int flags) {
+ bool res = true;
+ if (volume_uuid.empty()) {
+ if (flags & android::os::IVold::STORAGE_FLAG_CE) {
+ auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
+ res &= rmrf_contents(misc_ce_path);
+ }
+ if (flags & android::os::IVold::STORAGE_FLAG_DE) {
+ auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
+ res &= rmrf_contents(misc_de_path);
+ }
+ }
+ return res;
+}
+
+int main(int argc, const char* const argv[]) {
+ android::base::InitLogging(const_cast<char**>(argv));
+ std::vector<std::string> args(argv + 1, argv + argc);
+
+ if (args.size() != 4 || !valid_uuid(args[1]) || !small_int(args[2]) || !small_int(args[3])) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ auto volume_uuid = args[1];
+ int user_id = stoi(args[2]);
+ int flags = stoi(args[3]);
+ if (args[0] == "prepare") {
+ if (!prepare_subdirs(volume_uuid, user_id, flags)) return -1;
+ } else if (args[0] == "destroy") {
+ if (!destroy_subdirs(volume_uuid, user_id, flags)) return -1;
+ } else {
+ usage(argv[0]);
+ return -1;
+ }
+ return 0;
+}