am cb9ae42: system/core: Remove old mountd code
Merge commit 'cb9ae42cd22cca46744bb964a2c412b145225748' * commit 'cb9ae42cd22cca46744bb964a2c412b145225748': system/core: Remove old mountd code
This commit is contained in:
commit
e4da6a1a79
774
mountd/ASEC.c
774
mountd/ASEC.c
|
@ -1,774 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Android Secure External Cache
|
||||
*/
|
||||
|
||||
#include "mountd.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/loop.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/misc.h>
|
||||
|
||||
#include "ASEC.h"
|
||||
|
||||
//#define MODULE_FAILURE_IS_FATAL
|
||||
|
||||
extern int init_module(void *, unsigned long, const char *);
|
||||
extern int delete_module(const char *, unsigned int);
|
||||
|
||||
struct asec_context
|
||||
{
|
||||
char *name; // Device mapper volume name
|
||||
char *srcPath; // Path to the source (original) mount
|
||||
char *backingFile; // Name of the image file
|
||||
unsigned int sectors; // Number of sectors
|
||||
char *dstPath; // Destination mount point
|
||||
char *crypt; // Crypt options
|
||||
|
||||
boolean needs_format;
|
||||
boolean started;
|
||||
int cacheFd;
|
||||
int lo_num;
|
||||
int dm_num;
|
||||
unsigned char key[16];
|
||||
};
|
||||
|
||||
static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
|
||||
"cryptomgr", "dm_crypt", "jbd",
|
||||
"twofish_common", "twofish", "cbc",
|
||||
"mbcache", "ext3",
|
||||
NULL };
|
||||
static const char KEY_PATH[] = "/data/system/asec.key";
|
||||
static const char MODULE_PATH[] = "/system/lib/modules";
|
||||
static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
|
||||
static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
|
||||
|
||||
boolean AsecIsStarted(void *Handle)
|
||||
{
|
||||
struct asec_context *ctx = (struct asec_context *) Handle;
|
||||
|
||||
return ctx->started;
|
||||
}
|
||||
|
||||
const char *AsecMountPoint(void *Handle)
|
||||
{
|
||||
struct asec_context *ctx = (struct asec_context *) Handle;
|
||||
|
||||
return ctx->dstPath;
|
||||
}
|
||||
|
||||
static boolean AsecIsEnabled()
|
||||
{
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
int enabled;
|
||||
|
||||
property_get(ASEC_ENABLED, value, "0");
|
||||
|
||||
if (atoi(value) == 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
|
||||
const char *Size, const char *DstPath, const char *Crypt)
|
||||
{
|
||||
struct asec_context *ctx;
|
||||
|
||||
if (!AsecIsEnabled())
|
||||
return NULL;
|
||||
|
||||
LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
|
||||
Name, SrcPath, BackingFile, Size, DstPath, Crypt);
|
||||
|
||||
if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
|
||||
LOG_ERROR("AsecInit(): Invalid arguments\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ctx = malloc(sizeof(struct asec_context)))) {
|
||||
LOG_ERROR("AsecInit(): Out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ctx, 0, sizeof(struct asec_context));
|
||||
ctx->name = strdup(Name);
|
||||
ctx->srcPath = strdup(SrcPath);
|
||||
ctx->backingFile = strdup(BackingFile);
|
||||
ctx->sectors = atoi(Size);
|
||||
ctx->dstPath = strdup(DstPath);
|
||||
ctx->crypt = strdup(Crypt);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void AsecDeinit(void *Handle)
|
||||
{
|
||||
struct asec_context *ctx = (struct asec_context *) Handle;
|
||||
|
||||
free(ctx->name);
|
||||
free(ctx->srcPath);
|
||||
free(ctx->backingFile);
|
||||
free(ctx->dstPath);
|
||||
free(ctx->crypt);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int AsecLoadModules()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; MODULES[i] != NULL; i++) {
|
||||
const char *moduleName = MODULES[i];
|
||||
char moduleFile[255];
|
||||
int rc = 0;
|
||||
void *module;
|
||||
unsigned int size;
|
||||
|
||||
sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
|
||||
module = load_file(moduleFile, &size);
|
||||
if (!module) {
|
||||
LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = init_module(module, size, "");
|
||||
free(module);
|
||||
if (rc && errno != EEXIST) {
|
||||
LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AsecUnloadModules()
|
||||
{
|
||||
int i, j, rc;
|
||||
|
||||
for (i = 0; MODULES[i] != NULL; i++);
|
||||
|
||||
for (j = (i - 1); j >= 0; j--) {
|
||||
const char *moduleName = MODULES[j];
|
||||
int maxretry = 10;
|
||||
while(maxretry-- > 0) {
|
||||
rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
|
||||
if (rc < 0 && errno == EAGAIN)
|
||||
usleep(500000);
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
LOG_ERROR("Failed to unload module %s\n", moduleName);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AsecGenerateKey(struct asec_context *ctx)
|
||||
{
|
||||
LOG_ASEC("AsecGenerateKey():\n");
|
||||
|
||||
memset((void *) ctx->key, 0x69, sizeof(ctx->key));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AsecLoadGenerateKey(struct asec_context *ctx)
|
||||
{
|
||||
int fd;
|
||||
int rc = 0;
|
||||
|
||||
if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
|
||||
LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
|
||||
LOG_ASEC("Generating key\n");
|
||||
if ((rc = AsecGenerateKey(ctx)) < 0) {
|
||||
LOG_ERROR("Error generating key (%d)\n", rc);
|
||||
goto out;
|
||||
}
|
||||
if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
|
||||
LOG_ERROR("Error writing keyfile (%d)\n", errno);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
close (fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecFormatFilesystem(struct asec_context *ctx)
|
||||
{
|
||||
char cmdline[255];
|
||||
int rc;
|
||||
|
||||
sprintf(cmdline,
|
||||
"%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
|
||||
MKE2FS_PATH, ctx->name, ctx->dm_num);
|
||||
|
||||
LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if ((rc = system(cmdline)) < 0) {
|
||||
LOG_ERROR("Error executing format command (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = WEXITSTATUS(rc);
|
||||
|
||||
if (!rc) {
|
||||
LOG_ASEC("Format completed\n");
|
||||
} else {
|
||||
LOG_ASEC("Format failed (%d)\n", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecCheckFilesystem(struct asec_context *ctx)
|
||||
{
|
||||
char cmdline[255];
|
||||
int rc;
|
||||
|
||||
sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
|
||||
|
||||
LOG_ASEC("Checking filesystem (%s)\n", cmdline);
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if ((rc = system(cmdline)) < 0) {
|
||||
LOG_ERROR("Error executing check command (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rc = WEXITSTATUS(rc);
|
||||
|
||||
if (rc == 0) {
|
||||
LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
|
||||
} else if (rc == 1) {
|
||||
LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
|
||||
rc = 0;
|
||||
} else if (rc == 2) {
|
||||
LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
|
||||
} else if (rc == 4) {
|
||||
LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
|
||||
} else if (rc == 8) {
|
||||
LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
|
||||
} else {
|
||||
LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecOpenCreateCache(struct asec_context *ctx)
|
||||
{
|
||||
char filepath[255];
|
||||
|
||||
sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
|
||||
|
||||
if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
|
||||
if (errno == ENOENT) {
|
||||
int rc = 0;
|
||||
|
||||
LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
|
||||
if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
|
||||
LOG_ERROR("Error creating cache (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
|
||||
LOG_ERROR("Error truncating cache (%d)\n", errno);
|
||||
close(ctx->cacheFd);
|
||||
unlink(filepath);
|
||||
return -errno;
|
||||
}
|
||||
LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
|
||||
close(ctx->cacheFd); // creat() is WRONLY
|
||||
|
||||
if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
|
||||
LOG_ERROR("Error opening cache file (%d)\n", errno);
|
||||
close(ctx->cacheFd);
|
||||
unlink(filepath);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ctx->needs_format = 1;
|
||||
} else
|
||||
return -errno;
|
||||
} else {
|
||||
struct stat stat_buf;
|
||||
|
||||
if (fstat(ctx->cacheFd, &stat_buf) < 0) {
|
||||
LOG_ERROR("Failed to fstat cache (%d)\n", errno);
|
||||
close(ctx->cacheFd);
|
||||
return -errno;
|
||||
}
|
||||
if (stat_buf.st_size != ctx->sectors * 512) {
|
||||
LOG_ERROR("Cache size %lld != configured size %u\n",
|
||||
stat_buf.st_size, ctx->sectors * 512);
|
||||
}
|
||||
|
||||
// XXX: Verify volume label matches ctx->name
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void AsecCloseCache(struct asec_context *ctx)
|
||||
{
|
||||
close(ctx->cacheFd);
|
||||
}
|
||||
|
||||
static void *_align(void *ptr, unsigned int a)
|
||||
{
|
||||
register unsigned long agn = --a;
|
||||
|
||||
return (void *) (((unsigned long) ptr + agn) & ~agn);
|
||||
}
|
||||
|
||||
static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
|
||||
{
|
||||
void *buffer;
|
||||
void *p;
|
||||
const size_t min_size = 16 * 1024;
|
||||
size_t len = sizeof(struct dm_ioctl);
|
||||
struct dm_ioctl *io;
|
||||
struct dm_target_spec *tgt;
|
||||
int i;
|
||||
char params[1024];
|
||||
char key[80];
|
||||
|
||||
key[0] = '\0';
|
||||
|
||||
for (i = 0; i < (int) sizeof(ctx->key); i++) {
|
||||
char tmp[8];
|
||||
|
||||
sprintf(tmp, "%02x", ctx->key[i]);
|
||||
strcat(key, tmp);
|
||||
}
|
||||
|
||||
// XXX: Handle ctx->crypt
|
||||
sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
|
||||
|
||||
if (len < min_size)
|
||||
len = min_size;
|
||||
|
||||
if (!(buffer = malloc(len))) {
|
||||
LOG_ERROR("Unable to allocate memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(buffer, 0, len);
|
||||
io = buffer;
|
||||
tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
|
||||
|
||||
io->version[0] = 4;
|
||||
io->version[1] = 0;
|
||||
io->version[2] = 0;
|
||||
|
||||
io->data_size = len;
|
||||
io->data_start = sizeof(struct dm_ioctl);
|
||||
|
||||
io->flags = flags;
|
||||
io->dev = 0;
|
||||
|
||||
io->target_count = 1;
|
||||
io->event_nr = 1;
|
||||
strncpy(io->name, ctx->name, sizeof(io->name));
|
||||
|
||||
tgt->status = 0;
|
||||
tgt->sector_start = 0;
|
||||
tgt->length = ctx->sectors;
|
||||
strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
|
||||
|
||||
p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
|
||||
strcpy((char *) p, params);
|
||||
p+= strlen(params) + 1;
|
||||
|
||||
p = _align(p, 8);
|
||||
tgt->next = p - buffer;
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
static int FindNextAvailableDm()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
char path[255];
|
||||
sprintf(path, "/dev/block/dm-%d", i);
|
||||
if ((access(path, F_OK) < 0) && (errno == ENOENT))
|
||||
return i;
|
||||
}
|
||||
|
||||
LOG_ERROR("Out of device mapper numbers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int AsecCreateDeviceMapping(struct asec_context *ctx)
|
||||
{
|
||||
struct dm_ioctl *io;
|
||||
int dmFd;
|
||||
int rc = 0;
|
||||
|
||||
ctx->dm_num = FindNextAvailableDm();
|
||||
|
||||
if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
|
||||
LOG_ERROR("Error opening device mapper (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!(io = _dm_ioctl_setup(ctx, 0))) {
|
||||
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
|
||||
close(dmFd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
|
||||
LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
|
||||
rc = -errno;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
free(io);
|
||||
|
||||
if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
|
||||
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_nofree;
|
||||
}
|
||||
|
||||
if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
|
||||
LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
|
||||
rc = -errno;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
free(io);
|
||||
|
||||
if (!(io = _dm_ioctl_setup(ctx, 0))) {
|
||||
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_nofree;
|
||||
}
|
||||
|
||||
if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
|
||||
LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
|
||||
rc = -errno;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
free (io);
|
||||
out_nofree:
|
||||
close (dmFd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecDestroyDeviceMapping(struct asec_context *ctx)
|
||||
{
|
||||
struct dm_ioctl *io;
|
||||
int dmFd;
|
||||
int rc = 0;
|
||||
|
||||
if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
|
||||
LOG_ERROR("Error opening device mapper (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
|
||||
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_nofree;
|
||||
}
|
||||
|
||||
if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
|
||||
LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
|
||||
rc = -errno;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
free (io);
|
||||
out_nofree:
|
||||
close (dmFd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecMountCache(struct asec_context *ctx)
|
||||
{
|
||||
int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
|
||||
char devname[255];
|
||||
|
||||
if (access(ctx->dstPath, R_OK)) {
|
||||
LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
|
||||
|
||||
if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
|
||||
LOG_ERROR("ASEC mount failed (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AsecUnmountCache(struct asec_context *ctx)
|
||||
{
|
||||
if (umount(ctx->dstPath)) {
|
||||
if (errno == EBUSY) {
|
||||
LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
|
||||
} else {
|
||||
LOG_ERROR("ASEC umount failed (%d)\n", errno);
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FindNextAvailableLoop()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LOOP; i++) {
|
||||
struct loop_info info;
|
||||
char devname[255];
|
||||
int fd;
|
||||
|
||||
sprintf(devname, "/dev/block/loop%d", i);
|
||||
|
||||
if ((fd = open(devname, O_RDONLY)) < 0) {
|
||||
LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
|
||||
close(fd);
|
||||
|
||||
if (errno == ENXIO)
|
||||
return i;
|
||||
|
||||
LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
|
||||
return -errno;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int AsecCreateLoop(struct asec_context *ctx)
|
||||
{
|
||||
char devname[255];
|
||||
int device_fd;
|
||||
int rc = 0;
|
||||
|
||||
ctx->lo_num = FindNextAvailableLoop();
|
||||
if (ctx->lo_num < 0) {
|
||||
LOG_ERROR("No loop devices available\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
|
||||
device_fd = open(devname, O_RDWR);
|
||||
if (device_fd < 0) {
|
||||
LOG_ERROR("failed to open loop device (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
|
||||
LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
|
||||
rc = -errno;
|
||||
}
|
||||
close(device_fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int AsecDestroyLoop(struct asec_context *ctx)
|
||||
{
|
||||
char devname[255];
|
||||
int device_fd;
|
||||
int rc = 0;
|
||||
|
||||
sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
|
||||
device_fd = open(devname, O_RDONLY);
|
||||
if (device_fd < 0) {
|
||||
LOG_ERROR("Failed to open loop (%d)\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
|
||||
LOG_ERROR("Failed to destroy loop (%d)\n", errno);
|
||||
rc = -errno;
|
||||
}
|
||||
|
||||
close(device_fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int AsecStart(void *Handle)
|
||||
{
|
||||
struct asec_context *ctx = (struct asec_context *) Handle;
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
int rc = 0;
|
||||
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
if (ctx->started)
|
||||
return -EBUSY;
|
||||
|
||||
LOG_ASEC("AsecStart(%s):\n", ctx->name);
|
||||
|
||||
NotifyAsecState(ASEC_BUSY, ctx->dstPath);
|
||||
|
||||
if ((rc = AsecLoadModules()) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to load kernel modules\n");
|
||||
#ifdef MODULE_FAILURE_IS_FATAL
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((rc = AsecLoadGenerateKey(ctx))) {
|
||||
LOG_ERROR("AsecStart: Failed to load / generate key\n");
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((rc = AsecOpenCreateCache(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to open / create cache\n");
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((rc = AsecCreateLoop(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to create loop\n");
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
goto fail_closecache;
|
||||
}
|
||||
|
||||
if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
goto fail_destroyloop;
|
||||
}
|
||||
|
||||
if (ctx->needs_format) {
|
||||
if ((rc = AsecFormatFilesystem(ctx))) {
|
||||
LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
goto fail_destroydm;
|
||||
}
|
||||
ctx->needs_format = 0;
|
||||
} else {
|
||||
if ((rc = AsecCheckFilesystem(ctx))) {
|
||||
LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
goto fail_destroydm;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = AsecMountCache(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
goto fail_destroydm;
|
||||
}
|
||||
|
||||
NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
|
||||
ctx->started = true;
|
||||
|
||||
return rc;
|
||||
|
||||
fail_destroydm:
|
||||
AsecDestroyDeviceMapping(ctx);
|
||||
fail_destroyloop:
|
||||
AsecDestroyLoop(ctx);
|
||||
fail_closecache:
|
||||
AsecCloseCache(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int AsecStop(void *Handle)
|
||||
{
|
||||
struct asec_context *ctx = (struct asec_context *) Handle;
|
||||
int rc = 0;
|
||||
|
||||
if (!ctx->started)
|
||||
return -EINVAL;
|
||||
|
||||
LOG_ASEC("AsecStop(%s):\n", ctx->name);
|
||||
|
||||
NotifyAsecState(ASEC_BUSY, ctx->dstPath);
|
||||
|
||||
if ((rc = AsecUnmountCache(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((rc = AsecDestroyLoop(ctx)) < 0) {
|
||||
LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
AsecCloseCache(ctx);
|
||||
|
||||
if ((rc = AsecUnloadModules()) < 0) {
|
||||
if (rc == -EAGAIN) {
|
||||
LOG_ASEC("AsecStop: Kernel modules still in use\n");
|
||||
} else {
|
||||
LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
|
||||
#ifdef MODULE_FAILURE_IS_FATAL
|
||||
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ctx->started = false;
|
||||
NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
|
||||
return rc;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
#ifndef _ASEC_H
|
||||
#define _ASEC_H
|
||||
|
||||
#define ASEC_STORES_MAX 4
|
||||
#define MAX_LOOP 8
|
||||
|
||||
typedef enum AsecState {
|
||||
// Feature disabled
|
||||
ASEC_DISABLED,
|
||||
|
||||
// Feature enabled and operational
|
||||
ASEC_AVAILABLE,
|
||||
|
||||
// Busy
|
||||
ASEC_BUSY,
|
||||
|
||||
// Internal Error
|
||||
ASEC_FAILED_INTERR,
|
||||
|
||||
// No media available
|
||||
ASEC_FAILED_NOMEDIA,
|
||||
|
||||
// Media is corrupt
|
||||
ASEC_FAILED_BADMEDIA,
|
||||
|
||||
// Key mismatch
|
||||
ASEC_FAILED_BADKEY,
|
||||
} AsecState;
|
||||
|
||||
/*
|
||||
* ASEC commands
|
||||
*/
|
||||
#define ASEC_CMD_SEND_STATUS "asec_send_status"
|
||||
#define ASEC_CMD_ENABLE "asec_enable"
|
||||
#define ASEC_CMD_DISABLE "asec_disable"
|
||||
|
||||
/*
|
||||
* ASEC events
|
||||
*/
|
||||
|
||||
// These events correspond to the states in the AsecState enum.
|
||||
// A path to the ASEC mount point follows the colon
|
||||
#define ASEC_EVENT_DISABLED "asec_disabled:"
|
||||
#define ASEC_EVENT_AVAILABLE "asec_available:"
|
||||
#define ASEC_EVENT_BUSY "asec_busy:"
|
||||
#define ASEC_EVENT_FAILED_INTERR "asec_failed_interror:"
|
||||
#define ASEC_EVENT_FAILED_NOMEDIA "asec_failed_nomedia"
|
||||
#define ASEC_EVENT_FAILED_BADMEDIA "asec_failed_badmedia:"
|
||||
#define ASEC_EVENT_FAILED_BADKEY "asec_failed_badkey:"
|
||||
|
||||
/*
|
||||
* System Properties
|
||||
*/
|
||||
|
||||
#define ASEC_ENABLED "asec.enabled"
|
||||
|
||||
#define ASEC_STATUS "ro.asec.status"
|
||||
#define ASEC_STATUS_DISABLED "disabled"
|
||||
#define ASEC_STATUS_AVAILABLE "available"
|
||||
#define ASEC_STATUS_BUSY "busy"
|
||||
#define ASEC_STATUS_FAILED_INTERR "internal_error"
|
||||
#define ASEC_STATUS_FAILED_NOMEDIA "no_media"
|
||||
#define ASEC_STATUS_FAILED_BADMEDIA "bad_media"
|
||||
#define ASEC_STATUS_FAILED_BADKEY "bad_key"
|
||||
|
||||
#endif
|
|
@ -1,22 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
AutoMount.c \
|
||||
ProcessKiller.c \
|
||||
Server.c \
|
||||
mountd.c \
|
||||
ASEC.c \
|
||||
logwrapper.c
|
||||
|
||||
LOCAL_MODULE:= mountd
|
||||
|
||||
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
|
||||
|
||||
LOCAL_CFLAGS := -DCREATE_MOUNT_POINTS=0
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libcutils
|
||||
|
||||
# disabled - we are using vold now instead
|
||||
# include $(BUILD_EXECUTABLE)
|
1062
mountd/AutoMount.c
1062
mountd/AutoMount.c
File diff suppressed because it is too large
Load Diff
190
mountd/NOTICE
190
mountd/NOTICE
|
@ -1,190 +0,0 @@
|
|||
|
||||
Copyright (c) 2005-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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
|
@ -1,222 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
** mountd process killer
|
||||
*/
|
||||
|
||||
#include "mountd.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
static boolean ReadSymLink(const char* path, char* link)
|
||||
{
|
||||
struct stat s;
|
||||
int length;
|
||||
|
||||
if (lstat(path, &s) < 0)
|
||||
return false;
|
||||
if ((s.st_mode & S_IFMT) != S_IFLNK)
|
||||
return false;
|
||||
|
||||
// we have a symlink
|
||||
length = readlink(path, link, PATH_MAX - 1);
|
||||
if (length <= 0)
|
||||
return false;
|
||||
link[length] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean 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 true;
|
||||
// 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 false;
|
||||
}
|
||||
|
||||
static void GetProcessName(int pid, char buffer[PATH_MAX])
|
||||
{
|
||||
int fd;
|
||||
sprintf(buffer, "/proc/%d/cmdline", pid);
|
||||
fd = open(buffer, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
strcpy(buffer, "???");
|
||||
} else {
|
||||
int length = read(fd, buffer, PATH_MAX - 1);
|
||||
buffer[length] = 0;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
boolean fileOpen = false;
|
||||
char path[PATH_MAX];
|
||||
char link[PATH_MAX];
|
||||
int parent_length;
|
||||
|
||||
// compute path to process's directory of open files
|
||||
sprintf(path, "/proc/%d/fd", pid);
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
// remember length of the path
|
||||
parent_length = strlen(path);
|
||||
// append a trailing '/'
|
||||
path[parent_length++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != 0 && !fileOpen) {
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// append the file name, after truncating to parent directory
|
||||
path[parent_length] = 0;
|
||||
strcat(path, de->d_name);
|
||||
|
||||
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link);
|
||||
fileOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return fileOpen;
|
||||
}
|
||||
|
||||
static boolean CheckFileMaps(int pid, const char* mountPoint)
|
||||
{
|
||||
FILE* file;
|
||||
char buffer[PATH_MAX + 100];
|
||||
boolean mapOpen = false;
|
||||
|
||||
sprintf(buffer, "/proc/%d/maps", pid);
|
||||
file = fopen(buffer, "r");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
while (!mapOpen && fgets(buffer, sizeof(buffer), file))
|
||||
{
|
||||
// skip to the path
|
||||
const char* path = strchr(buffer, '/');
|
||||
if (path && PathMatchesMountPoint(path, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path);
|
||||
mapOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return mapOpen;
|
||||
}
|
||||
|
||||
static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char link[PATH_MAX];
|
||||
|
||||
sprintf(path, "/proc/%d/%s", pid, name);
|
||||
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
GetProcessName(pid, name);
|
||||
LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int get_pid(const char* s)
|
||||
{
|
||||
int result = 0;
|
||||
while (*s) {
|
||||
if (!isdigit(*s)) return -1;
|
||||
result = 10 * result + (*s++ - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// hunt down and kill processes that have files open on the given mount point
|
||||
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
|
||||
LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint);
|
||||
dir = opendir("/proc");
|
||||
if (!dir) return;
|
||||
|
||||
while ((de = readdir(dir)) != 0)
|
||||
{
|
||||
boolean killed = false;
|
||||
// does the name look like a process ID?
|
||||
int pid = get_pid(de->d_name);
|
||||
if (pid == -1) continue;
|
||||
|
||||
if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
|
||||
|| CheckFileMaps(pid, mountPoint) // check for mmap()
|
||||
|| CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
|
||||
|| CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
|
||||
|| CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
|
||||
)
|
||||
{
|
||||
int i;
|
||||
boolean hit = false;
|
||||
|
||||
for (i = 0; i < num_excluded; i++) {
|
||||
if (pid == excluded[i]) {
|
||||
LOG_ERROR("I just need a little more TIME captain!\n");
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hit) {
|
||||
LOG_ERROR("Killing process %d\n", pid);
|
||||
kill(pid, (sigkill ? SIGKILL : SIGTERM));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
313
mountd/Server.c
313
mountd/Server.c
|
@ -1,313 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
** mountd server support
|
||||
*/
|
||||
|
||||
#include "mountd.h"
|
||||
#include "ASEC.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
|
||||
// current client file descriptor
|
||||
static int sFD = -1;
|
||||
|
||||
// to synchronize writing to client
|
||||
static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// path for media that failed to mount before the runtime is connected
|
||||
static char* sDeferredUnmountableMediaPath = NULL;
|
||||
|
||||
// last asec msg before the runtime was connected
|
||||
static char* sAsecDeferredMessage = NULL;
|
||||
static char* sAsecDeferredArgument = NULL;
|
||||
|
||||
static int Write(const char* message)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
pthread_mutex_lock(&sWriteMutex);
|
||||
|
||||
LOG_SERVER("Write: %s\n", message);
|
||||
if (sFD >= 0)
|
||||
result = write(sFD, message, strlen(message) + 1);
|
||||
|
||||
pthread_mutex_unlock(&sWriteMutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int Write2(const char* message, const char* data)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
|
||||
if (!buffer)
|
||||
{
|
||||
LOG_ERROR("alloca failed in Write2\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(buffer, message);
|
||||
strcat(buffer, data);
|
||||
return Write(buffer);
|
||||
}
|
||||
|
||||
static void SendStatus()
|
||||
{
|
||||
Write(IsMassStorageConnected() ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
|
||||
Write(IsMassStorageEnabled() ? MOUNTD_UMS_ENABLED : MOUNTD_UMS_DISABLED);
|
||||
}
|
||||
|
||||
static void DoCommand(const char* command)
|
||||
{
|
||||
LOG_SERVER("DoCommand %s\n", command);
|
||||
|
||||
if (strcmp(command, MOUNTD_ENABLE_UMS) == 0)
|
||||
{
|
||||
EnableMassStorage(true);
|
||||
Write(MOUNTD_UMS_ENABLED);
|
||||
}
|
||||
else if (strcmp(command, MOUNTD_DISABLE_UMS) == 0)
|
||||
{
|
||||
EnableMassStorage(false);
|
||||
Write(MOUNTD_UMS_DISABLED);
|
||||
}
|
||||
else if (strcmp(command, MOUNTD_SEND_STATUS) == 0)
|
||||
{
|
||||
SendStatus();
|
||||
}
|
||||
else if (strncmp(command, MOUNTD_MOUNT_MEDIA, strlen(MOUNTD_MOUNT_MEDIA)) == 0)
|
||||
{
|
||||
const char* path = command + strlen(MOUNTD_MOUNT_MEDIA);
|
||||
MountMedia(path);
|
||||
}
|
||||
else if (strncmp(command, MOUNTD_EJECT_MEDIA, strlen(MOUNTD_EJECT_MEDIA)) == 0)
|
||||
{
|
||||
const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
|
||||
UnmountMedia(path);
|
||||
}
|
||||
else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
|
||||
LOG_ASEC("Got ASEC_CMD_ENABLE\n");
|
||||
// XXX: SAN: Impliment
|
||||
}
|
||||
else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
|
||||
LOG_ASEC("Got ASEC_CMD_DISABLE\n");
|
||||
// XXX: SAN: Impliment
|
||||
}
|
||||
else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
|
||||
LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
|
||||
// XXX: SAN: Impliment
|
||||
}
|
||||
else
|
||||
LOGE("unknown command %s\n", command);
|
||||
}
|
||||
|
||||
int RunServer()
|
||||
{
|
||||
int socket = android_get_control_socket(MOUNTD_SOCKET);
|
||||
if (socket < 0) {
|
||||
LOGE("Obtaining file descriptor for socket '%s' failed: %s",
|
||||
MOUNTD_SOCKET, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(socket, 4) < 0) {
|
||||
LOGE("Unable to listen on file descriptor '%d' for socket '%s': %s",
|
||||
socket, MOUNTD_SOCKET, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
struct ucred cred;
|
||||
socklen_t size;
|
||||
|
||||
alen = sizeof(addr);
|
||||
sFD = accept(socket, &addr, &alen);
|
||||
if (sFD < 0)
|
||||
continue;
|
||||
|
||||
if (sDeferredUnmountableMediaPath) {
|
||||
NotifyMediaState(sDeferredUnmountableMediaPath, MEDIA_UNMOUNTABLE, false);
|
||||
free(sDeferredUnmountableMediaPath);
|
||||
sDeferredUnmountableMediaPath = NULL;
|
||||
}
|
||||
|
||||
if (sAsecDeferredMessage) {
|
||||
|
||||
if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
|
||||
LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
|
||||
free(sAsecDeferredMessage);
|
||||
free(sAsecDeferredArgument);
|
||||
sAsecDeferredMessage = sAsecDeferredArgument = NULL;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char buffer[101];
|
||||
int result = read(sFD, buffer, sizeof(buffer) - 1);
|
||||
if (result > 0)
|
||||
{
|
||||
int start = 0;
|
||||
int i;
|
||||
// command should be zero terminated, but just in case
|
||||
buffer[result] = 0;
|
||||
for (i = 0; i < result; i++)
|
||||
{
|
||||
if (buffer[i] == 0)
|
||||
{
|
||||
DoCommand(buffer + start);
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
close(sFD);
|
||||
sFD = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should never get here
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SendMassStorageConnected(boolean connected)
|
||||
{
|
||||
Write(connected ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
|
||||
}
|
||||
|
||||
void SendUnmountRequest(const char* path)
|
||||
{
|
||||
Write2(MOUNTD_REQUEST_EJECT, path);
|
||||
}
|
||||
|
||||
void NotifyAsecState(AsecState state, const char *argument)
|
||||
{
|
||||
const char *event = NULL;
|
||||
const char *status = NULL;
|
||||
boolean deferr = true;;
|
||||
|
||||
switch (state) {
|
||||
case ASEC_DISABLED:
|
||||
event = ASEC_EVENT_DISABLED;
|
||||
status = ASEC_STATUS_DISABLED;
|
||||
break;
|
||||
case ASEC_AVAILABLE:
|
||||
event = ASEC_EVENT_AVAILABLE;
|
||||
status = ASEC_STATUS_AVAILABLE;
|
||||
break;
|
||||
case ASEC_BUSY:
|
||||
event = ASEC_EVENT_BUSY;
|
||||
status = ASEC_STATUS_BUSY;
|
||||
deferr = false;
|
||||
break;
|
||||
case ASEC_FAILED_INTERR:
|
||||
event = ASEC_EVENT_FAILED_INTERR;
|
||||
status = ASEC_STATUS_FAILED_INTERR;
|
||||
break;
|
||||
case ASEC_FAILED_NOMEDIA:
|
||||
event = ASEC_EVENT_FAILED_NOMEDIA;
|
||||
status = ASEC_STATUS_FAILED_NOMEDIA;
|
||||
break;
|
||||
case ASEC_FAILED_BADMEDIA:
|
||||
event = ASEC_EVENT_FAILED_BADMEDIA;
|
||||
status = ASEC_STATUS_FAILED_BADMEDIA;
|
||||
break;
|
||||
case ASEC_FAILED_BADKEY:
|
||||
event = ASEC_EVENT_FAILED_BADKEY;
|
||||
status = ASEC_STATUS_FAILED_BADKEY;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
|
||||
return;
|
||||
}
|
||||
|
||||
property_set(ASEC_STATUS, status);
|
||||
|
||||
int result = Write2(event, argument);
|
||||
if ((result < 0) && deferr) {
|
||||
if (sAsecDeferredMessage)
|
||||
free(sAsecDeferredMessage);
|
||||
sAsecDeferredMessage = strdup(event);
|
||||
if (sAsecDeferredArgument)
|
||||
free(sAsecDeferredArgument);
|
||||
sAsecDeferredArgument = strdup(argument);
|
||||
LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
|
||||
{
|
||||
const char* event = NULL;
|
||||
const char* propertyValue = NULL;
|
||||
|
||||
switch (state) {
|
||||
case MEDIA_REMOVED:
|
||||
event = MOUNTD_MEDIA_REMOVED;
|
||||
propertyValue = EXTERNAL_STORAGE_REMOVED;
|
||||
break;
|
||||
case MEDIA_UNMOUNTED:
|
||||
event = MOUNTD_MEDIA_UNMOUNTED;
|
||||
propertyValue = EXTERNAL_STORAGE_UNMOUNTED;
|
||||
break;
|
||||
case MEDIA_MOUNTED:
|
||||
event = (readOnly ? MOUNTD_MEDIA_MOUNTED_READ_ONLY : MOUNTD_MEDIA_MOUNTED);
|
||||
propertyValue = (readOnly ? EXTERNAL_STORAGE_MOUNTED_READ_ONLY : EXTERNAL_STORAGE_MOUNTED);
|
||||
break;
|
||||
case MEDIA_SHARED:
|
||||
event = MOUNTD_MEDIA_SHARED;
|
||||
propertyValue = EXTERNAL_STORAGE_SHARED;
|
||||
break;
|
||||
case MEDIA_BAD_REMOVAL:
|
||||
event = MOUNTD_MEDIA_BAD_REMOVAL;
|
||||
propertyValue = EXTERNAL_STORAGE_BAD_REMOVAL;
|
||||
break;
|
||||
case MEDIA_UNMOUNTABLE:
|
||||
event = MOUNTD_MEDIA_UNMOUNTABLE;
|
||||
propertyValue = EXTERNAL_STORAGE_UNMOUNTABLE;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("unknown MediaState %d in NotifyMediaState\n", state);
|
||||
return;
|
||||
}
|
||||
|
||||
property_set(EXTERNAL_STORAGE_STATE, propertyValue);
|
||||
int result = Write2(event, path);
|
||||
if (result < 0 && state == MEDIA_UNMOUNTABLE) {
|
||||
|
||||
// if we cannot communicate with the runtime, defer this message until the runtime is available
|
||||
sDeferredUnmountableMediaPath = strdup(path);
|
||||
}
|
||||
}
|
|
@ -1,154 +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 <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "private/android_filesystem_config.h"
|
||||
#include "cutils/log.h"
|
||||
|
||||
int parent(const char *tag, int parent_read) {
|
||||
int status;
|
||||
char buffer[4096];
|
||||
|
||||
int a = 0; // start index of unprocessed data
|
||||
int b = 0; // end index of unprocessed data
|
||||
int sz;
|
||||
while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
|
||||
|
||||
sz += b;
|
||||
// Log one line at a time
|
||||
for (b = 0; b < sz; b++) {
|
||||
if (buffer[b] == '\r') {
|
||||
buffer[b] = '\0';
|
||||
} else if (buffer[b] == '\n') {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
a = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (a == 0 && b == sizeof(buffer) - 1) {
|
||||
// buffer is full, flush
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
b = 0;
|
||||
} else if (a != b) {
|
||||
// Keep left-overs
|
||||
b -= a;
|
||||
memmove(buffer, &buffer[a], b);
|
||||
a = 0;
|
||||
} else {
|
||||
a = 0;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
}
|
||||
// Flush remaining data
|
||||
if (a != b) {
|
||||
buffer[b] = '\0';
|
||||
LOG(LOG_INFO, tag, &buffer[a]);
|
||||
}
|
||||
status = 0xAAAA;
|
||||
if (wait(&status) != -1) { // Wait for child
|
||||
if (WIFEXITED(status)) {
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
|
||||
WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
|
||||
WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status))
|
||||
LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
|
||||
WSTOPSIG(status));
|
||||
} else
|
||||
LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
|
||||
strerror(errno), errno);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
void child(int argc, char* argv[]) {
|
||||
// create null terminated argv_child array
|
||||
char* argv_child[argc + 1];
|
||||
memcpy(argv_child, argv, argc * sizeof(char *));
|
||||
argv_child[argc] = NULL;
|
||||
|
||||
// XXX: PROTECT FROM VIKING KILLER
|
||||
if (execvp(argv_child[0], argv_child)) {
|
||||
LOG(LOG_ERROR, "logwrapper",
|
||||
"executing %s failed: %s\n", argv_child[0], strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int logwrap(int argc, char* argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
int parent_ptty;
|
||||
int child_ptty;
|
||||
char *child_devname = NULL;
|
||||
|
||||
/* Use ptty instead of socketpair so that STDOUT is not buffered */
|
||||
parent_ptty = open("/dev/ptmx", O_RDWR);
|
||||
if (parent_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
|
||||
((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
|
||||
return -errno;
|
||||
} else if (pid == 0) {
|
||||
child_ptty = open(child_devname, O_RDWR);
|
||||
if (child_ptty < 0) {
|
||||
LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// redirect stdout and stderr
|
||||
close(parent_ptty);
|
||||
dup2(child_ptty, 1);
|
||||
dup2(child_ptty, 2);
|
||||
close(child_ptty);
|
||||
|
||||
child(argc, argv);
|
||||
} else {
|
||||
// switch user and group to "log"
|
||||
// this may fail if we are not root,
|
||||
// but in that case switching user/group is unnecessary
|
||||
|
||||
// setgid(AID_LOG);
|
||||
// setuid(AID_LOG);
|
||||
|
||||
return parent(argv[0], parent_ptty);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
174
mountd/mountd.c
174
mountd/mountd.c
|
@ -1,174 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
** mountd main program
|
||||
*/
|
||||
|
||||
#include "mountd.h"
|
||||
|
||||
#include <cutils/config_utils.h>
|
||||
#include <cutils/cpu_info.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/prctl.h>
|
||||
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#ifdef MOUNTD_LOG
|
||||
FILE* logFile;
|
||||
#endif
|
||||
|
||||
struct asec_cfg {
|
||||
const char *name;
|
||||
const char *backing_file;
|
||||
const char *size;
|
||||
const char *mount_point;
|
||||
const char *crypt;
|
||||
};
|
||||
|
||||
static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
|
||||
{
|
||||
cnode *child = node->first_child;
|
||||
const char *name = NULL;
|
||||
const char *file = NULL;
|
||||
const char *size = NULL;
|
||||
const char *mp = NULL;
|
||||
const char *crypt = NULL;
|
||||
|
||||
LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
|
||||
|
||||
while (child) {
|
||||
if (!strcmp(child->name, "name"))
|
||||
name = child->value;
|
||||
else if (!strcmp(child->name, "backing_file"))
|
||||
file = child->value;
|
||||
else if (!strcmp(child->name, "size"))
|
||||
size = child->value;
|
||||
else if (!strcmp(child->name, "mount_point"))
|
||||
mp = child->value;
|
||||
else if (!strcmp(child->name, "crypt"))
|
||||
crypt = child->value;
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
if (!name || !file || !size || !mp || !crypt) {
|
||||
LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
|
||||
return -1;
|
||||
} else if (idx == ASEC_STORES_MAX) {
|
||||
LOG_ERROR("Maximum # of ASEC stores already defined\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
stores[idx].name = name;
|
||||
stores[idx].backing_file = file;
|
||||
stores[idx].size = size;
|
||||
stores[idx].mount_point = mp;
|
||||
stores[idx].crypt = crypt;
|
||||
return ++idx;
|
||||
}
|
||||
|
||||
static void ReadConfigFile(const char* path)
|
||||
{
|
||||
cnode* root = config_node("", "");
|
||||
cnode* node;
|
||||
|
||||
config_load_file(root, path);
|
||||
node = root->first_child;
|
||||
|
||||
while (node)
|
||||
{
|
||||
if (strcmp(node->name, "mount") == 0)
|
||||
{
|
||||
const char* block_device = NULL;
|
||||
const char* mount_point = NULL;
|
||||
const char* driver_store_path = NULL;
|
||||
boolean enable_ums = false;
|
||||
cnode* child = node->first_child;
|
||||
struct asec_cfg asec_stores[ASEC_STORES_MAX];
|
||||
int asec_idx = 0;
|
||||
|
||||
memset(asec_stores, 0, sizeof(asec_stores));
|
||||
|
||||
while (child)
|
||||
{
|
||||
const char* name = child->name;
|
||||
const char* value = child->value;
|
||||
|
||||
if (!strncmp(name, "asec_", 5)) {
|
||||
int rc = ProcessAsecData(child, asec_stores, asec_idx);
|
||||
if (rc < 0) {
|
||||
LOG_ERROR("Error processing ASEC cfg data\n");
|
||||
} else
|
||||
asec_idx = rc;
|
||||
} else if (strcmp(name, "block_device") == 0)
|
||||
block_device = value;
|
||||
else if (strcmp(name, "mount_point") == 0)
|
||||
mount_point = value;
|
||||
else if (strcmp(name, "driver_store_path") == 0)
|
||||
driver_store_path = value;
|
||||
else if (strcmp(name, "enable_ums") == 0 &&
|
||||
strcmp(value, "true") == 0)
|
||||
enable_ums = true;
|
||||
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
// mount point and removable fields are optional
|
||||
if (block_device && mount_point)
|
||||
{
|
||||
void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < asec_idx; i++) {
|
||||
AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
|
||||
asec_stores[i].size, asec_stores[i].mount_point,
|
||||
asec_stores[i].crypt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* configPath = "/system/etc/mountd.conf";
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
const char* arg = argv[i];
|
||||
|
||||
if (strcmp(arg, "-f") == 0)
|
||||
{
|
||||
if (i < argc - 1)
|
||||
configPath = argv[++i];
|
||||
}
|
||||
}
|
||||
|
||||
ReadConfigFile(configPath);
|
||||
StartAutoMounter();
|
||||
return RunServer();
|
||||
}
|
190
mountd/mountd.h
190
mountd/mountd.h
|
@ -1,190 +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 MOUNTD_H__
|
||||
#define MOUNTD_H__
|
||||
|
||||
#define LOG_TAG "mountd"
|
||||
#include "cutils/log.h"
|
||||
|
||||
#include "ASEC.h"
|
||||
|
||||
typedef int boolean;
|
||||
enum {
|
||||
false = 0,
|
||||
true = 1
|
||||
};
|
||||
|
||||
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
|
||||
// Set this for logging error messages
|
||||
#define ENABLE_LOG_ERROR
|
||||
|
||||
// set this to log automounter events
|
||||
#define ENABLE_LOG_MOUNT
|
||||
|
||||
// set this to log server events
|
||||
//#define ENABLE_LOG_SERVER
|
||||
|
||||
// set this to log ASEC events
|
||||
#define ENABLE_LOG_ASEC
|
||||
|
||||
#ifdef ENABLE_LOG_ERROR
|
||||
#define LOG_ERROR(fmt, args...) \
|
||||
{ LOGE(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_ERROR(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_ERROR */
|
||||
|
||||
#ifdef ENABLE_LOG_MOUNT
|
||||
#define LOG_MOUNT(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_MOUNT(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_MOUNT */
|
||||
|
||||
#ifdef ENABLE_LOG_SERVER
|
||||
#define LOG_SERVER(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_SERVER(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_SERVER */
|
||||
|
||||
#ifdef ENABLE_LOG_ASEC
|
||||
#define LOG_ASEC(fmt, args...) \
|
||||
{ LOGD(fmt , ## args); }
|
||||
#else
|
||||
#define LOG_ASEC(fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif /* ENABLE_LOG_ASEC */
|
||||
|
||||
|
||||
typedef enum MediaState {
|
||||
// no media in SD card slot
|
||||
MEDIA_REMOVED,
|
||||
|
||||
// media in SD card slot, but not mounted
|
||||
MEDIA_UNMOUNTED,
|
||||
|
||||
// media in SD card slot and mounted at its mount point
|
||||
MEDIA_MOUNTED,
|
||||
|
||||
// media in SD card slot, unmounted, and shared as a mass storage device
|
||||
MEDIA_SHARED,
|
||||
|
||||
// media was removed from SD card slot, but mount point was not unmounted
|
||||
// this state is cleared after the mount point is unmounted
|
||||
MEDIA_BAD_REMOVAL,
|
||||
|
||||
// media in SD card slot could not be mounted (corrupt file system?)
|
||||
MEDIA_UNMOUNTABLE,
|
||||
} MediaState;
|
||||
|
||||
// socket name for connecting to mountd
|
||||
#define MOUNTD_SOCKET "mountd"
|
||||
|
||||
// mountd commands
|
||||
// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
|
||||
#define MOUNTD_ENABLE_UMS "enable_ums"
|
||||
#define MOUNTD_DISABLE_UMS "disable_ums"
|
||||
#define MOUNTD_SEND_STATUS "send_status"
|
||||
|
||||
// these commands should contain a mount point following the colon
|
||||
#define MOUNTD_MOUNT_MEDIA "mount_media:"
|
||||
#define MOUNTD_EJECT_MEDIA "eject_media:"
|
||||
|
||||
// mountd events
|
||||
// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
|
||||
#define MOUNTD_UMS_ENABLED "ums_enabled"
|
||||
#define MOUNTD_UMS_DISABLED "ums_disabled"
|
||||
#define MOUNTD_UMS_CONNECTED "ums_connected"
|
||||
#define MOUNTD_UMS_DISCONNECTED "ums_disconnected"
|
||||
|
||||
// these events correspond to the states in the MediaState enum.
|
||||
// a path to the mount point follows the colon.
|
||||
#define MOUNTD_MEDIA_REMOVED "media_removed:"
|
||||
#define MOUNTD_MEDIA_UNMOUNTED "media_unmounted:"
|
||||
#define MOUNTD_MEDIA_MOUNTED "media_mounted:"
|
||||
#define MOUNTD_MEDIA_MOUNTED_READ_ONLY "media_mounted_ro:"
|
||||
#define MOUNTD_MEDIA_SHARED "media_shared:"
|
||||
#define MOUNTD_MEDIA_BAD_REMOVAL "media_bad_removal:"
|
||||
#define MOUNTD_MEDIA_UNMOUNTABLE "media_unmountable:"
|
||||
|
||||
// this event sent to request unmount for media mount point
|
||||
#define MOUNTD_REQUEST_EJECT "request_eject:"
|
||||
|
||||
// system properties
|
||||
// these must match the corresponding strings in //device/java/android/android/os/Environment.java
|
||||
#define EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
|
||||
#define EXTERNAL_STORAGE_REMOVED "removed"
|
||||
#define EXTERNAL_STORAGE_UNMOUNTED "unmounted"
|
||||
#define EXTERNAL_STORAGE_MOUNTED "mounted"
|
||||
#define EXTERNAL_STORAGE_MOUNTED_READ_ONLY "mounted_ro"
|
||||
#define EXTERNAL_STORAGE_SHARED "shared"
|
||||
#define EXTERNAL_STORAGE_BAD_REMOVAL "bad_removal"
|
||||
#define EXTERNAL_STORAGE_UNMOUNTABLE "unmountable"
|
||||
|
||||
// AutoMount.c
|
||||
|
||||
boolean IsMassStorageEnabled();
|
||||
boolean IsMassStorageConnected();
|
||||
|
||||
void MountMedia(const char* mountPoint);
|
||||
void UnmountMedia(const char* mountPoint);
|
||||
void EnableMassStorage(boolean enable);
|
||||
|
||||
// call this before StartAutoMounter() to add a mount point to monitor
|
||||
void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
|
||||
boolean enableUms);
|
||||
|
||||
int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
|
||||
const char *size, const char *mount_point, const char *crypt);
|
||||
|
||||
// start automounter thread
|
||||
void StartAutoMounter();
|
||||
|
||||
// check /proc/mounts for mounted file systems, and notify mount or unmount for any that are in our automount list
|
||||
void NotifyExistingMounts();
|
||||
|
||||
|
||||
// ASEC.c
|
||||
|
||||
void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
|
||||
const char *Size, const char *DstPath, const char *Crypt);
|
||||
int AsecStart(void *Handle);
|
||||
int AsecStop(void *Handle);
|
||||
void AsecDeinit(void *Handle);
|
||||
boolean AsecIsStarted(void *Handle);
|
||||
const char *AsecMountPoint(void *Handle);
|
||||
|
||||
// ProcessKiller.c
|
||||
|
||||
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
|
||||
|
||||
// logwrapper.c
|
||||
int logwrap(int argc, char* argv[]);
|
||||
|
||||
// Server.c
|
||||
|
||||
int RunServer();
|
||||
void SendMassStorageConnected(boolean connected);
|
||||
void SendUnmountRequest(const char* path);
|
||||
void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
|
||||
void NotifyAsecState(AsecState state, const char *argument);
|
||||
#endif // MOUNTD_H__
|
Loading…
Reference in New Issue