Code drop from //branches/cupcake/...@124589
diff --git a/mountd/ASEC.c b/mountd/ASEC.c
new file mode 100644
index 0000000..3d8e50e
--- /dev/null
+++ b/mountd/ASEC.c
@@ -0,0 +1,770 @@
+/*
+ * 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/loop.h>
+
+#include <cutils/properties.h>
+#include <cutils/misc.h>
+
+#include "ASEC.h"
+#include "dm-ioctl.h"
+
+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;
+
+    LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
+             Name, SrcPath, BackingFile, Size, DstPath, Crypt);
+
+    if (!AsecIsEnabled()) {
+        LOG_ERROR("AsecInit(): Disabled\n");
+        return NULL;
+    }
+
+    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\n", moduleFile);
+            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");
+        NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	return rc;
+    }
+
+    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);
+            NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
+	    return rc;
+        }
+    }
+
+    ctx->started = false;
+    NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
+    return rc;
+}
diff --git a/mountd/ASEC.h b/mountd/ASEC.h
new file mode 100644
index 0000000..c87b288
--- /dev/null
+++ b/mountd/ASEC.h
@@ -0,0 +1,66 @@
+#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
diff --git a/mountd/Android.mk b/mountd/Android.mk
index 87bcef3..bc128ac 100644
--- a/mountd/Android.mk
+++ b/mountd/Android.mk
@@ -6,7 +6,8 @@
     AutoMount.c          \
     ProcessKiller.c      \
     Server.c             \
-    mountd.c
+    mountd.c		 \
+    ASEC.c
 
 LOCAL_MODULE:= mountd
 
diff --git a/mountd/AutoMount.c b/mountd/AutoMount.c
index bfe8ad1..0aac871 100644
--- a/mountd/AutoMount.c
+++ b/mountd/AutoMount.c
@@ -76,17 +76,20 @@
     
     // mount point for device
     const char* mountPoint;
+
+    // path to the UMS driver file for specifying the block device path
+    const char* driverStorePath;
     
     // true if device can be shared via
     // USB mass storage
     boolean enableUms;
-    
+ 
+    // Array of ASEC handles
+    void *asecHandles[ASEC_STORES_MAX];
+
     // true if the device is being shared via USB mass storage
     boolean umsActive;
     
-    // logical unit number (for UMS)
-    int lun;
-    
     // current state of the mount point
     MountState state;
     
@@ -100,11 +103,13 @@
 
 // list of our mount points (does not change after initialization)
 static MountPoint* sMountPointList = NULL;
-static int sNextLun = 0;
 boolean gMassStorageEnabled = false;
 boolean gMassStorageConnected = false;
 
 static pthread_t sAutoMountThread = 0;
+static pid_t gExcludedPids[2] = {-1, -1};
+
+static const char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
 
 // number of mount points that have timeouts pending
 static int sRetriesPending = 0;
@@ -116,15 +121,18 @@
 // via USB mass storage.
 static void SetBackingStore(MountPoint* mp, boolean enable) 
 {
-    char path[PATH_MAX];
     int fd;
 
+    if (!mp->driverStorePath) {
+        LOG_ERROR("no driver_store_path specified in config file for %s", mp->device);
+        return;
+    }
+
     LOG_MOUNT("SetBackingStore enable: %s\n", (enable ? "true" : "false"));
-    snprintf(path, sizeof(path), "/sys/devices/platform/usb_mass_storage/lun%d/file", mp->lun);
-    fd = open(path, O_WRONLY);
+    fd = open(mp->driverStorePath, O_WRONLY);
     if (fd < 0)
     {
-        LOG_ERROR("could not open %s\n", path);
+        LOG_ERROR("could not open driver_store_path %s\n", mp->driverStorePath);
     }
     else
     {
@@ -192,6 +200,56 @@
     return result;
 }
 
+static int CheckFilesystem(const char *device)
+{
+    char cmdline[255];
+    int rc;
+
+    // XXX: SAN: Check for FAT signature
+    
+    int result = access(FSCK_MSDOS_PATH, X_OK);
+    if (result != 0) {
+        LOG_MOUNT("CheckFilesystem(%s): fsck_msdos not found (skipping checks)\n", device);
+        return 0;
+    }
+ 
+    sprintf(cmdline, "%s -p %s", FSCK_MSDOS_PATH, device);
+    LOG_MOUNT("Checking filesystem (%s)\n", cmdline);
+
+    // XXX: Notify framework we're disk checking
+  
+    // XXX: PROTECT FROM VIKING KILLER
+    if ((rc = system(cmdline)) < 0) {
+        LOG_ERROR("Error executing disk check command (%d)\n", errno);
+        return -errno;
+    } 
+
+    rc = WEXITSTATUS(rc);
+  
+    if (rc == 0) {
+        LOG_MOUNT("Filesystem check completed OK\n");
+        return 0;
+    } else if (rc == 1) {
+        LOG_MOUNT("Filesystem check failed (invalid usage)\n");
+        return -EINVAL;
+    } else if (rc == 2) {
+        LOG_MOUNT("Filesystem check failed (unresolved issues)\n");
+        return -EIO;
+    } else if (rc == 4) {
+        LOG_MOUNT("Filesystem check failed (root changed)\n");
+        return -EIO;
+    } else if (rc == 8) {
+        LOG_MOUNT("Filesystem check failed (general failure)\n");
+        return -EIO;
+    } else if (rc == 12) {
+        LOG_MOUNT("Filesystem check failed (exit signaled)\n");
+        return -EIO;
+    } else {
+        LOG_MOUNT("Filesystem check failed (unknown exit code %d)\n", rc);
+        return -EIO;
+    }
+}
+
 static int DoMountDevice(const char* device, const char* mountPoint)
 {
     LOG_MOUNT("mounting %s at %s\n", device, mountPoint);
@@ -237,6 +295,17 @@
     if (result != 0)
         return result;
 
+    if ((result = CheckFilesystem(device))) {
+        LOG_ERROR("Not mounting filesystem due to check failure (%d)\n", result);
+        // XXX:  Notify framework - need a new SDCARD state for the following:
+        //       - SD cards which are not present
+        //       - SD cards with no partition table
+        //       - SD cards with no filesystem
+        //       - SD cards with bad filesystem
+        return result;
+    }
+    
+
     // Extra safety measures:
     flags |= MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
     // Also, set fmask = 711 so that files cannot be marked executable,
@@ -254,6 +323,24 @@
 
     if (result == 0) {
         NotifyMediaState(mountPoint, MEDIA_MOUNTED, (flags & MS_RDONLY) != 0);
+
+        MountPoint* mp = sMountPointList;
+        while (mp) {
+            if (!strcmp(mountPoint, mp->mountPoint)) {
+                int i;
+             
+                for (i = 0; i < ASEC_STORES_MAX; i++) {
+                    if (mp->asecHandles[i] != NULL) {
+                        int a_result;
+                        if ((a_result = AsecStart(mp->asecHandles[i])) < 0) {
+                            LOG_ERROR("ASEC start failure (%d)\n", a_result);
+                        }
+                    }
+                }
+                break;
+            }
+            mp = mp -> next;
+        }
     } else if (errno == EBUSY) {
     // ignore EBUSY, since it usually means the device is already mounted
         result = 0;
@@ -267,32 +354,39 @@
     return result;
 }
 
-static int DoUnmountDevice(const char* mountPoint)
+static int DoUnmountDevice(MountPoint *mp)
 {
-    boolean loop = IsLoopMounted(mountPoint);
-    int result = umount(mountPoint);
+    boolean loop = IsLoopMounted(mp->mountPoint);
+    int i;
+
+    for (i = 0; i < ASEC_STORES_MAX; i++) {
+        if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i]))
+            AsecStop(mp->asecHandles[i]);
+    }
+
+    int result = umount(mp->mountPoint);
     LOG_MOUNT("umount returned %d errno: %d\n", result, errno);
 
     if (result == 0)
     {
-        if (loop)
-        {
-            // free the loop device
-            int loop_fd = open(LOOP_DEVICE, O_RDONLY);
-            if (loop_fd < -1) {
-                LOG_ERROR("open loop device failed\n");
-            }
-            if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
-                LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
-            }
-
-            close(loop_fd);
-        }
-
 #if CREATE_MOUNT_POINTS
         rmdir(mountPoint);
 #endif
-        NotifyMediaState(mountPoint, MEDIA_UNMOUNTED, false);
+        NotifyMediaState(mp->mountPoint, MEDIA_UNMOUNTED, false);
+    }
+
+    if (loop)
+    {
+        // free the loop device
+        int loop_fd = open(LOOP_DEVICE, O_RDONLY);
+        if (loop_fd < -1) {
+            LOG_ERROR("open loop device failed\n");
+        }
+        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+            LOG_ERROR("ioctl LOOP_CLR_FD failed\n");
+        }
+
+        close(loop_fd);
     }
 
     // ignore EINVAL and ENOENT, since it usually means the device is already unmounted
@@ -408,7 +502,7 @@
         sync();
         DropSystemCaches();
 
-        if (DoUnmountDevice(mp->mountPoint) == 0) 
+        if (DoUnmountDevice(mp) == 0) 
         {
             SetState(mp, kUnmounted);
             if (retryState == kUnmountingForUms) 
@@ -502,6 +596,8 @@
 {
     MountPoint* mp = sMountPointList;
     
+    LOG_MOUNT("HandleMediaInserted(%s):\n", device);
+
     while (mp)
     {
         // see if the device matches mount point's block device
@@ -573,7 +669,7 @@
        } 
        else if (mp->state == kUnmountingForEject || mp->state == kUnmountingForUms)
        {
-            if (DoUnmountDevice(mp->mountPoint) == 0)
+            if (DoUnmountDevice(mp) == 0)
             {
                 // unmounting succeeded
                 // start mass storage, if state is kUnmountingForUms
@@ -594,8 +690,25 @@
                     // send SIGKILL instead of SIGTERM if the first attempt did not succeed
                     boolean sigkill = (mp->retryCount > MAX_UNMOUNT_RETRIES);
                     
+                    int i;
+
+                    for (i = 0; i < ASEC_STORES_MAX; i++) {
+                        if (mp->asecHandles[i] && AsecIsStarted(mp->asecHandles[i])) {
+                            LOG_MOUNT("Killing processes for ASEC path '%s'\n",
+                                      AsecMountPoint(mp->asecHandles[i]));
+                            KillProcessesWithOpenFiles(AsecMountPoint(mp->asecHandles[i]),
+                                                       sigkill,
+                                                       gExcludedPids, sizeof(gExcludedPids) / sizeof(pid_t));
+
+                            // Now that we've killed the processes, try to stop the volume again
+                            AsecStop(mp->asecHandles[i]);
+                        }
+                    }
+
                     // unmounting the device is failing, so start killing processes
-                    KillProcessesWithOpenFiles(mp->mountPoint, sigkill);
+                    KillProcessesWithOpenFiles(mp->mountPoint, sigkill, gExcludedPids, 
+                                               sizeof(gExcludedPids) / sizeof(pid_t));
+
                 }
             }
        } 
@@ -676,6 +789,8 @@
     int id;
     struct sigaction    actions;
 
+    gExcludedPids[1] = getpid();
+
     memset(&actions, 0, sizeof(actions));
     sigemptyset(&actions.sa_mask);
     actions.sa_flags = 0;
@@ -829,7 +944,9 @@
 void MountMedia(const char* mountPoint)
 {
     MountPoint* mp = sMountPointList;
-    
+ 
+    LOG_MOUNT("MountMedia(%s)\n", mountPoint);
+   
     pthread_mutex_lock(&sMutex);
     while (mp)
     {
@@ -883,27 +1000,48 @@
  * 
  ***********************************************/
  
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms)
+void *AddMountPoint(const char* device, const char* mountPoint, const char * driverStorePath, boolean enableUms)
 {
     MountPoint* newMountPoint;
     
-    LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s\n", device, mountPoint);
+    LOG_MOUNT("AddMountPoint device: %s, mountPoint: %s driverStorePath: %s\n", device, mountPoint, driverStorePath);
     // add a new MountPoint to the head of our linked list
     newMountPoint = (MountPoint *)malloc(sizeof(MountPoint));
     newMountPoint->device = device;
     newMountPoint->mountPoint = mountPoint;
+    newMountPoint->driverStorePath = driverStorePath;
     newMountPoint->enableUms = enableUms;
     newMountPoint->umsActive = false;
-    if (enableUms)
-        newMountPoint->lun = sNextLun++;
     newMountPoint->state = kUnmounted;
     newMountPoint->retryCount = 0;
 
     // add to linked list
     newMountPoint->next = sMountPointList;
     sMountPointList = newMountPoint;
+    return newMountPoint;
 }
 
+int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file, const char *size,
+                        const char *mount_point, const char *crypt)
+{
+    MountPoint *mp = (MountPoint *) Mp;
+    int i;
+
+    for (i = 0; i < ASEC_STORES_MAX; i++) {
+        if (!mp->asecHandles[i])
+            break;   
+    }
+
+    if (i == ASEC_STORES_MAX) {
+        LOG_ERROR("Maximum # of ASEC stores exceeded\n");
+        return -EINVAL;
+    }
+
+    if (!(mp->asecHandles[i] = AsecInit(name, mp->mountPoint, backing_file, size, mount_point, crypt)))
+        return -1;
+
+    return 0;
+}
 static void MountDevices()
 {
     MountPoint* mp = sMountPointList;
@@ -916,6 +1054,8 @@
 
 void StartAutoMounter()
 {
+    gExcludedPids[0] = getpid();
+
     gMassStorageConnected = ReadMassStorageState();
     LOG_MOUNT(gMassStorageConnected ? "USB online\n" : "USB offline\n");
 
diff --git a/mountd/ProcessKiller.c b/mountd/ProcessKiller.c
index 3ce7aa8..e377774 100644
--- a/mountd/ProcessKiller.c
+++ b/mountd/ProcessKiller.c
@@ -177,7 +177,7 @@
 }
 
 // hunt down and kill processes that have files open on the given mount point
-void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill)
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
 {
     DIR*    dir;
     struct dirent* de;
@@ -200,8 +200,21 @@
                 || CheckSymLink(pid, mountPoint, "exe", "executable path")      // check executable path
             ) 
         {
-            LOG_ERROR("Killing process %d\n", pid);
-            kill(pid, (sigkill ? SIGKILL : SIGTERM));
+            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));
+            }
         }
     }
 
diff --git a/mountd/Server.c b/mountd/Server.c
index 14b3830..64459bd 100644
--- a/mountd/Server.c
+++ b/mountd/Server.c
@@ -19,6 +19,7 @@
 */
 
 #include "mountd.h"
+#include "ASEC.h"
 
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
@@ -43,6 +44,10 @@
 // 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;
@@ -107,6 +112,18 @@
     {
         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);
@@ -145,6 +162,15 @@
             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];
@@ -187,6 +213,61 @@
     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;
diff --git a/mountd/dm-ioctl.h b/mountd/dm-ioctl.h
new file mode 100644
index 0000000..ee5c350
--- /dev/null
+++ b/mountd/dm-ioctl.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_V4_H
+#define _LINUX_DM_IOCTL_V4_H
+
+#ifdef linux
+#  include <linux/types.h>
+#endif
+
+#define DM_DIR "mapper"		/* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+/*
+ * A traditional ioctl interface for the device mapper.
+ *
+ * Each device can have two tables associated with it, an
+ * 'active' table which is the one currently used by io passing
+ * through the device, and an 'inactive' one which is a table
+ * that is being prepared as a replacement for the 'active' one.
+ *
+ * DM_VERSION:
+ * Just get the version information for the ioctl interface.
+ *
+ * DM_REMOVE_ALL:
+ * Remove all dm devices, destroy all tables.  Only really used
+ * for debug.
+ *
+ * DM_LIST_DEVICES:
+ * Get a list of all the dm device names.
+ *
+ * DM_DEV_CREATE:
+ * Create a new device, neither the 'active' or 'inactive' table
+ * slots will be filled.  The device will be in suspended state
+ * after creation, however any io to the device will get errored
+ * since it will be out-of-bounds.
+ *
+ * DM_DEV_REMOVE:
+ * Remove a device, destroy any tables.
+ *
+ * DM_DEV_RENAME:
+ * Rename a device.
+ *
+ * DM_SUSPEND:
+ * This performs both suspend and resume, depending which flag is
+ * passed in.
+ * Suspend: This command will not return until all pending io to
+ * the device has completed.  Further io will be deferred until
+ * the device is resumed.
+ * Resume: It is no longer an error to issue this command on an
+ * unsuspended device.  If a table is present in the 'inactive'
+ * slot, it will be moved to the active slot, then the old table
+ * from the active slot will be _destroyed_.  Finally the device
+ * is resumed.
+ *
+ * DM_DEV_STATUS:
+ * Retrieves the status for the table in the 'active' slot.
+ *
+ * DM_DEV_WAIT:
+ * Wait for a significant event to occur to the device.  This
+ * could either be caused by an event triggered by one of the
+ * targets of the table in the 'active' slot, or a table change.
+ *
+ * DM_TABLE_LOAD:
+ * Load a table into the 'inactive' slot for the device.  The
+ * device does _not_ need to be suspended prior to this command.
+ *
+ * DM_TABLE_CLEAR:
+ * Destroy any table in the 'inactive' slot (ie. abort).
+ *
+ * DM_TABLE_DEPS:
+ * Return a set of device dependencies for the 'active' table.
+ *
+ * DM_TABLE_STATUS:
+ * Return the targets status for the 'active' table.
+ *
+ * DM_TARGET_MSG:
+ * Pass a message string to the target at a specific offset of a device.
+ *
+ * DM_DEV_SET_GEOMETRY:
+ * Set the geometry of a device by passing in a string in this format:
+ *
+ * "cylinders heads sectors_per_track start_sector"
+ *
+ * Beware that CHS geometry is nearly obsolete and only provided
+ * for compatibility with dm devices that can be booted by a PC
+ * BIOS.  See struct hd_geometry for range limits.  Also note that
+ * the geometry is erased if the device size changes.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start.  If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+	/*
+	 * The version number is made up of three parts:
+	 * major - no backward or forward compatibility,
+	 * minor - only backwards compatible,
+	 * patch - both backwards and forwards compatible.
+	 *
+	 * All clients of the ioctl interface should fill in the
+	 * version number of the interface that they were
+	 * compiled with.
+	 *
+	 * All recognised ioctl commands (ie. those that don't
+	 * return -ENOTTY) fill out this field, even if the
+	 * command failed.
+	 */
+	uint32_t version[3];	/* in/out */
+	uint32_t data_size;	/* total size of data passed in
+				 * including this struct */
+
+	uint32_t data_start;	/* offset to start of data
+				 * relative to start of this struct */
+
+	uint32_t target_count;	/* in/out */
+	int32_t open_count;	/* out */
+	uint32_t flags;		/* in/out */
+	uint32_t event_nr;      	/* in/out */
+	uint32_t padding;
+
+	uint64_t dev;		/* in/out */
+
+	char name[DM_NAME_LEN];	/* device name */
+	char uuid[DM_UUID_LEN];	/* unique identifier for
+				 * the block device */
+	char data[7];		/* padding or data */
+};
+
+/*
+ * Used to specify tables.  These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+	uint64_t sector_start;
+	uint64_t length;
+	int32_t status;		/* used when reading from kernel only */
+
+	/*
+	 * Location of the next dm_target_spec.
+	 * - When specifying targets on a DM_TABLE_LOAD command, this value is
+	 *   the number of bytes from the start of the "current" dm_target_spec
+	 *   to the start of the "next" dm_target_spec.
+	 * - When retrieving targets on a DM_TABLE_STATUS command, this value
+	 *   is the number of bytes from the start of the first dm_target_spec
+	 *   (that follows the dm_ioctl struct) to the start of the "next"
+	 *   dm_target_spec.
+	 */
+	uint32_t next;
+
+	char target_type[DM_MAX_TYPE_NAME];
+
+	/*
+	 * Parameter string starts immediately after this object.
+	 * Be careful to add padding after string to ensure correct
+	 * alignment of subsequent dm_target_spec.
+	 */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+	uint32_t count;	/* Array size */
+	uint32_t padding;	/* unused */
+	uint64_t dev[0];	/* out */
+};
+
+/*
+ * Used to get a list of all dm devices.
+ */
+struct dm_name_list {
+	uint64_t dev;
+	uint32_t next;		/* offset to the next record from
+				   the _start_ of this */
+	char name[0];
+};
+
+/*
+ * Used to retrieve the target versions
+ */
+struct dm_target_versions {
+        uint32_t next;
+        uint32_t version[3];
+
+        char name[0];
+};
+
+/*
+ * Used to pass message to a target
+ */
+struct dm_target_msg {
+	uint64_t sector;	/* Device sector */
+
+	char message[0];
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Top level cmds */
+	DM_VERSION_CMD = 0,
+	DM_REMOVE_ALL_CMD,
+	DM_LIST_DEVICES_CMD,
+
+	/* device level cmds */
+	DM_DEV_CREATE_CMD,
+	DM_DEV_REMOVE_CMD,
+	DM_DEV_RENAME_CMD,
+	DM_DEV_SUSPEND_CMD,
+	DM_DEV_STATUS_CMD,
+	DM_DEV_WAIT_CMD,
+
+	/* Table level cmds */
+	DM_TABLE_LOAD_CMD,
+	DM_TABLE_CLEAR_CMD,
+	DM_TABLE_DEPS_CMD,
+	DM_TABLE_STATUS_CMD,
+
+	/* Added later */
+	DM_LIST_VERSIONS_CMD,
+	DM_TARGET_MSG_CMD,
+	DM_DEV_SET_GEOMETRY_CMD
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+#define DM_LIST_DEVICES  _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+#define DM_DEV_WAIT      _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
+
+#define DM_TABLE_LOAD    _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
+#define DM_TABLE_CLEAR   _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
+#define DM_TABLE_DEPS    _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
+#define DM_TABLE_STATUS  _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
+
+#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
+
+#define DM_TARGET_MSG	 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
+#define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR	4
+#define DM_VERSION_MINOR	13
+#define DM_VERSION_PATCHLEVEL	0
+#define DM_VERSION_EXTRA	"-ioctl (2007-10-18)"
+
+/* Status bits */
+#define DM_READONLY_FLAG	(1 << 0) /* In/Out */
+#define DM_SUSPEND_FLAG		(1 << 1) /* In/Out */
+#define DM_PERSISTENT_DEV_FLAG	(1 << 3) /* In */
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG	(1 << 4) /* In */
+
+/*
+ * Flags that indicate whether a table is present in either of
+ * the two table slots that a device has.
+ */
+#define DM_ACTIVE_PRESENT_FLAG   (1 << 5) /* Out */
+#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
+
+/*
+ * Indicates that the buffer passed in wasn't big enough for the
+ * results.
+ */
+#define DM_BUFFER_FULL_FLAG	(1 << 8) /* Out */
+
+/*
+ * This flag is now ignored.
+ */
+#define DM_SKIP_BDGET_FLAG	(1 << 9) /* In */
+
+/*
+ * Set this to avoid attempting to freeze any filesystem when suspending.
+ */
+#define DM_SKIP_LOCKFS_FLAG	(1 << 10) /* In */
+
+/*
+ * Set this to suspend without flushing queued ios.
+ */
+#define DM_NOFLUSH_FLAG		(1 << 11) /* In */
+
+#endif				/* _LINUX_DM_IOCTL_H */
diff --git a/mountd/mountd.c b/mountd/mountd.c
index fb54fe6..27ec8de 100644
--- a/mountd/mountd.c
+++ b/mountd/mountd.c
@@ -39,6 +39,54 @@
 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)
 {
@@ -54,18 +102,31 @@
         {
             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 (strcmp(name, "block_device") == 0)
+
+                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;
@@ -76,7 +137,14 @@
             // mount point and removable fields are optional
             if (block_device && mount_point)
             {
-                AddMountPoint(block_device, mount_point, enable_ums);
+                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);
+                }
             }
         }
             
diff --git a/mountd/mountd.h b/mountd/mountd.h
index 746a414..9b62484 100644
--- a/mountd/mountd.h
+++ b/mountd/mountd.h
@@ -20,21 +20,28 @@
 #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
+#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); }
@@ -59,6 +66,14 @@
     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
@@ -135,7 +150,11 @@
 void EnableMassStorage(boolean enable);
 
 // call this before StartAutoMounter() to add a mount point to monitor
-void AddMountPoint(const char* device, const char* mountPoint, boolean enableUms);
+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();
@@ -144,9 +163,19 @@
 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);
+void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
 
 
 // Server.c
@@ -155,5 +184,5 @@
 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__