Merge "Destroy vold socket interface completely."

This commit is contained in:
Jeff Sharkey 2017-09-19 05:11:08 +00:00 committed by Android (Google) Code Review
commit 49672b9351
33 changed files with 40 additions and 3378 deletions

View file

@ -2,9 +2,6 @@ LOCAL_PATH:= $(call my-dir)
common_src_files := \
VolumeManager.cpp \
CommandListener.cpp \
CryptCommandListener.cpp \
VoldCommand.cpp \
NetlinkManager.cpp \
NetlinkHandler.cpp \
Process.cpp \
@ -13,7 +10,6 @@ common_src_files := \
fs/Vfat.cpp \
Loop.cpp \
Devmapper.cpp \
ResponseCode.cpp \
CheckBattery.cpp \
Ext4Crypt.cpp \
VoldUtil.c \

43
Asec.h
View file

@ -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

View file

@ -17,7 +17,6 @@
#include "BenchmarkTask.h"
#include "BenchmarkGen.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/file.h>
#include <android-base/logging.h>

View file

@ -1,689 +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 "model/VolumeBase.h"
#include "ResponseCode.h"
#include "Process.h"
#include "Loop.h"
#include "Devmapper.h"
#include "MoveTask.h"
#include "TrimTask.h"
#define DUMP_ARGS 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, nullptr))->start();
return sendGenericOkFail(cli, 0);
} else if (cmd == "benchmark" && argc > 2) {
// benchmark [volId]
std::string id(argv[2]);
LOG(WARNING) << "Benchmarking has moved to Binder interface";
nsecs_t res = 0;
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 == "dodtrim") {
flags = android::vold::TrimTask::Flags::kDeepTrim;
} else if (cmd == "dodtrimbench") {
flags = android::vold::TrimTask::Flags::kDeepTrim;
}
(new android::vold::TrimTask(flags, nullptr))->start();
return sendGenericOkFail(cli, 0);
}
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;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
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 int mountId = atoi(argv[4]);
unique_fd device_fd;
int result = vm->mountAppFuse(uid, pid, mountId, &device_fd);
if (result != 0) {
return sendGenericOkFail(cli, result);
} else {
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 int mountId = atoi(argv[4]);
int result = vm->unmountAppFuse(uid, pid, mountId);
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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -34,7 +34,6 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <sysutils/SocketClient.h>
#include "Devmapper.h"
@ -44,82 +43,6 @@ using android::base::StringPrintf;
static const char* kVoldPrefix = "vold:";
int Devmapper::dumpState(SocketClient *c) {
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;
}
void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
const char *name, unsigned flags) {
memset(io, 0, dataSize);

View file

@ -20,8 +20,6 @@
#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,
@ -29,7 +27,6 @@ public:
static int destroy(const char *name);
static int destroyAll();
static int lookupActive(const char *name, char *buffer, size_t len);
static int dumpState(SocketClient *c);
private:
static void *_align(void *ptr, unsigned int a);

View file

@ -36,9 +36,7 @@
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <sysutils/SocketClient.h>
#include "Loop.h"
#include "Asec.h"
#include "VoldUtil.h"
#include "sehandle.h"
@ -47,48 +45,6 @@ using android::base::unique_fd;
static const char* kVoldPrefix = "vold:";
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_raw, char *buffer, size_t len) {
auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
const char* id = id_string.c_str();
@ -380,46 +336,3 @@ int Loop::resizeImageFile(const char *file, unsigned long numSectors) {
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;
}

5
Loop.h
View file

@ -21,22 +21,17 @@
#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 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

View file

@ -17,7 +17,6 @@
#include "MoveTask.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>

View file

@ -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);
}

View file

@ -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

View file

@ -17,7 +17,6 @@
#include "TrimTask.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>

View file

@ -29,8 +29,6 @@
struct DIR;
#define ENABLE_BINDER 1
namespace android {
namespace vold {

View file

@ -1,21 +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 "VoldCommand.h"
VoldCommand::VoldCommand(const char *cmd) :
FrameworkCommand(cmd) {
}

View file

@ -1,28 +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 _VOLD_COMMAND_H
#define _VOLD_COMMAND_H
#include <sysutils/FrameworkCommand.h>
class VoldCommand : public FrameworkCommand {
public:
explicit VoldCommand(const char *cmd);
virtual ~VoldCommand() {}
};
#endif

View file

@ -211,6 +211,20 @@ binder::Status VoldNativeService::setListener(
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;

View file

@ -33,6 +33,7 @@ public:
binder::Status setListener(const android::sp<android::os::IVoldListener>& listener);
binder::Status monitor();
binder::Status reset();
binder::Status shutdown();
binder::Status mountAll();

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,6 @@
#include <cutils/multiuser.h>
#include <utils/List.h>
#include <utils/Timers.h>
#include <sysutils/SocketListener.h>
#include <sysutils/NetlinkEvent.h>
#include "android/os/IVoldListener.h"
@ -41,56 +40,18 @@
#include "model/Disk.h"
#include "model/VolumeBase.h"
/* The length of an MD5 hash when encoded into ASCII hex characters */
#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
#define DEBUG_APPFUSE 0
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;
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();
@ -150,52 +111,11 @@ public:
/* 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
@ -215,9 +135,6 @@ public:
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);

View file

@ -23,6 +23,7 @@ import android.os.IVoldTaskListener;
interface IVold {
void setListener(IVoldListener listener);
void monitor();
void reset();
void shutdown();
void mountAll();

View file

@ -16,8 +16,6 @@
#include "model/Disk.h"
#include "VolumeManager.h"
#include "CommandListener.h"
#include "CryptCommandListener.h"
#include "NetlinkManager.h"
#include "VoldNativeService.h"
#include "cryptfs.h"
@ -27,7 +25,6 @@
#include <android-base/stringprintf.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <stdio.h>
#include <stdlib.h>
@ -62,8 +59,6 @@ int main(int argc, char** argv) {
<< (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;
NetlinkManager *nm;
parse_args(argc, argv);
@ -73,10 +68,6 @@ int main(int argc, char** argv) {
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 */
@ -97,11 +88,6 @@ int main(int argc, char** argv) {
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);
@ -124,19 +110,6 @@ int main(int argc, char** argv) {
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);
}
// 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");

View file

@ -20,7 +20,6 @@
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "Ext4Crypt.h"
#include <android-base/file.h>
@ -151,12 +150,10 @@ void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
#if ENABLE_BINDER
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskCreated(getId(), mFlags);
#else
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
#endif
readMetadata();
readPartitions();
return OK;
@ -166,12 +163,10 @@ status_t Disk::destroy() {
CHECK(mCreated);
destroyAllVolumes();
mCreated = false;
#if ENABLE_BINDER
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskDestroyed(getId());
#else
notifyEvent(ResponseCode::DiskDestroyed);
#endif
return OK;
}
@ -291,15 +286,10 @@ status_t Disk::readMetadata() {
}
}
#if ENABLE_BINDER
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskMetadataChanged(getId(),
mSize, mLabel, mSysPath);
#else
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
#endif
return OK;
}
@ -322,12 +312,10 @@ status_t Disk::readPartitions() {
status_t res = ForkExecvp(cmd, output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
#if ENABLE_BINDER
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskScanned(getId());
#else
notifyEvent(ResponseCode::DiskScanned);
#endif
mJustPartitioned = false;
return res;
}
@ -393,12 +381,9 @@ status_t Disk::readPartitions() {
}
}
#if ENABLE_BINDER
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskScanned(getId());
#else
notifyEvent(ResponseCode::DiskScanned);
#endif
mJustPartitioned = false;
return OK;
}
@ -560,16 +545,6 @@ status_t Disk::partitionMixed(int8_t ratio) {
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);

View file

@ -79,9 +79,6 @@ public:
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;

View file

@ -20,7 +20,6 @@
#include "EmulatedVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "cryptfs.h"
#include <android-base/stringprintf.h>
@ -55,14 +54,10 @@ PrivateVolume::~PrivateVolume() {
status_t PrivateVolume::readMetadata() {
status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel);
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
#else
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
#endif
return res;
}

View file

@ -18,7 +18,6 @@
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
@ -54,14 +53,10 @@ PublicVolume::~PublicVolume() {
status_t PublicVolume::readMetadata() {
status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
#else
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
#endif
return res;
}

View file

@ -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,12 +43,9 @@ VolumeBase::~VolumeBase() {
void VolumeBase::setState(State state) {
mState = state;
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState));
#else
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
#endif
}
status_t VolumeBase::setDiskId(const std::string& diskId) {
@ -119,12 +115,10 @@ status_t VolumeBase::setPath(const std::string& path) {
}
mPath = path;
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumePathChanged(getId(), mPath);
#else
notifyEvent(ResponseCode::VolumePathChanged, mPath);
#endif
return OK;
}
@ -135,27 +129,13 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) {
}
mInternalPath = internalPath;
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath);
#else
notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath);
#endif
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;
@ -186,14 +166,11 @@ status_t VolumeBase::create() {
mCreated = true;
status_t res = doCreate();
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeCreated(getId(),
static_cast<int32_t>(mType), mDiskId, mPartGuid);
#else
notifyEvent(ResponseCode::VolumeCreated,
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
#endif
setState(State::kUnmounted);
return res;
}
@ -212,12 +189,10 @@ status_t VolumeBase::destroy() {
setState(State::kRemoved);
}
#if ENABLE_BINDER
auto listener = getListener();
if (listener) listener->onVolumeDestroyed(getId());
#else
notifyEvent(ResponseCode::VolumeDestroyed);
#endif
status_t res = doDestroy();
mCreated = false;
return res;

View file

@ -115,9 +115,6 @@ protected:
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:

View file

@ -34,31 +34,4 @@ protected:
}
};
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";
}
}

129
vdc.cpp
View file

@ -24,7 +24,6 @@
#include <stdlib.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
@ -36,23 +35,13 @@
#include <android-base/stringprintf.h>
#include <binder/IServiceManager.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#define ENABLE_BINDER 1
static void usage(char *progname);
#if !ENABLE_BINDER
static int do_monitor(int sock, int stop_after_cmd);
static int do_cmd(int sock, int argc, char **argv);
#endif
static constexpr int kCommandTimeoutMs = 20 * 1000;
int main(int argc, char **argv) {
int sock;
int wait_for_socket;
int wait;
char *progname;
progname = argv[0];
@ -64,8 +53,8 @@ int main(int argc, char **argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
}
wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0;
if (wait_for_socket) {
wait = argc > 1 && strcmp(argv[1], "--wait") == 0;
if (wait) {
argv++;
argc--;
}
@ -75,7 +64,6 @@ int main(int argc, char **argv) {
exit(5);
}
#if ENABLE_BINDER
std::string arg1 = argv[1];
std::string arg2 = argv[2];
@ -104,119 +92,8 @@ int main(int argc, char **argv) {
LOG(ERROR) << "Raw commands are no longer supported";
exit(EINVAL);
}
#else
const char* sockname = "vold";
if (!strcmp(argv[1], "cryptfs")) {
sockname = "cryptd";
}
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));
} else {
exit(do_cmd(sock, argc, argv));
}
#endif
}
#if !ENABLE_BINDER
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;
}
#endif
static void usage(char *progname) {
LOG(INFO) << "Usage: " << progname << " [--wait] <monitor>|<cmd> [arg1] [arg2...]";
}

View file

@ -2,9 +2,6 @@ service vold /system/bin/vold \
--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