am f99dfdb5: Merge "vold: fix potential socket leak"

* commit 'f99dfdb5044ed6b120a8f2a86ddf2dd92a5bb9a2':
  vold: fix potential socket leak
diff --git a/Android.mk b/Android.mk
index b7a4905..098c3d0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,7 +8,6 @@
 	NetlinkHandler.cpp \
 	Volume.cpp \
 	DirectVolume.cpp \
-	logwrapper.c \
 	Process.cpp \
 	Ext4.cpp \
 	Fat.cpp \
@@ -16,6 +15,7 @@
 	Devmapper.cpp \
 	ResponseCode.cpp \
 	Xwarp.cpp \
+	fstrim.c \
 	cryptfs.c
 
 common_c_includes := \
@@ -26,8 +26,10 @@
 common_shared_libraries := \
 	libsysutils \
 	libcutils \
+	liblog \
 	libdiskconfig \
 	libhardware_legacy \
+	liblogwrap \
 	libcrypto
 
 include $(CLEAR_VARS)
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 2986cac..f8baff5 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -38,6 +38,7 @@
 #include "Loop.h"
 #include "Devmapper.h"
 #include "cryptfs.h"
+#include "fstrim.h"
 
 #define DUMP_ARGS 0
 
@@ -50,6 +51,7 @@
     registerCmd(new StorageCmd());
     registerCmd(new XwarpCmd());
     registerCmd(new CryptfsCmd());
+    registerCmd(new FstrimCmd());
 }
 
 void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
@@ -609,3 +611,41 @@
 
     return 0;
 }
+
+CommandListener::FstrimCmd::FstrimCmd() :
+                 VoldCommand("fstrim") {
+}
+int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
+                                                      int argc, char **argv) {
+    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
+        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
+        return 0;
+    }
+
+    if (argc < 2) {
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
+        return 0;
+    }
+
+    int rc = 0;
+
+    if (!strcmp(argv[1], "dotrim")) {
+        if (argc != 2) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
+            return 0;
+        }
+        dumpArgs(argc, argv, -1);
+        rc = fstrim_filesystems();
+    } else {
+        dumpArgs(argc, argv, -1);
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
+    }
+
+    // Always report that the command succeeded and return the error code.
+    // The caller will check the return value to see what the error was.
+    char msg[255];
+    snprintf(msg, sizeof(msg), "%d", rc);
+    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
+
+    return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index 4ef4a0c..8cc5b09 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -78,6 +78,13 @@
         virtual ~CryptfsCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
+
+    class FstrimCmd : public VoldCommand {
+    public:
+        FstrimCmd();
+        virtual ~FstrimCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
 };
 
 #endif
diff --git a/Ext4.cpp b/Ext4.cpp
index 613d623..b82b4c5 100644
--- a/Ext4.cpp
+++ b/Ext4.cpp
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
+#include <sys/wait.h>
 
 #include <linux/kdev_t.h>
 
@@ -37,13 +38,13 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+#include <logwrap/logwrap.h>
+
 #include "Ext4.h"
+#include "VoldUtil.h"
 
 #define MKEXT4FS_PATH "/system/bin/make_ext4fs";
 
-extern "C" int logwrap(int argc, const char **argv, int background);
-
-
 int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
         bool executable) {
     int rc;
@@ -68,22 +69,36 @@
 
 int Ext4::format(const char *fsPath, const char *mountpoint) {
     int fd;
-    const char *args[6];
+    const char *args[5];
     int rc;
+    int status;
 
     args[0] = MKEXT4FS_PATH;
     args[1] = "-J";
     args[2] = "-a";
     args[3] = mountpoint;
     args[4] = fsPath;
-    args[5] = NULL;
-    rc = logwrap(5, args, 1);
+    rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false,
+            true);
+    if (rc != 0) {
+        SLOGE("Filesystem (ext4) format failed due to logwrap error");
+        errno = EIO;
+        return -1;
+    }
 
-    if (rc == 0) {
+    if (!WIFEXITED(status)) {
+        SLOGE("Filesystem (ext4) format did not exit properly");
+        errno = EIO;
+        return -1;
+    }
+
+    status = WEXITSTATUS(status);
+
+    if (status == 0) {
         SLOGI("Filesystem (ext4) formatted OK");
         return 0;
     } else {
-        SLOGE("Format (ext4) failed (unknown exit code %d)", rc);
+        SLOGE("Format (ext4) failed (unknown exit code %d)", status);
         errno = EIO;
         return -1;
     }
diff --git a/Fat.cpp b/Fat.cpp
index a7fcc28..807f440 100644
--- a/Fat.cpp
+++ b/Fat.cpp
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
+#include <sys/wait.h>
 
 #include <linux/kdev_t.h>
 
@@ -37,11 +38,13 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+#include <logwrap/logwrap.h>
+
 #include "Fat.h"
+#include "VoldUtil.h"
 
 static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
 static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
-extern "C" int logwrap(int argc, const char **argv, int background);
 extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
 
 int Fat::check(const char *fsPath) {
@@ -54,16 +57,30 @@
     int pass = 1;
     int rc = 0;
     do {
-        const char *args[5];
+        const char *args[4];
+        int status;
         args[0] = FSCK_MSDOS_PATH;
         args[1] = "-p";
         args[2] = "-f";
         args[3] = fsPath;
-        args[4] = NULL;
 
-        rc = logwrap(4, args, 1);
+        rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
+                false, true);
+        if (rc != 0) {
+            SLOGE("Filesystem check failed due to logwrap error");
+            errno = EIO;
+            return -1;
+        }
 
-        switch(rc) {
+        if (!WIFEXITED(status)) {
+            SLOGE("Filesystem check did not exit properly");
+            errno = EIO;
+            return -1;
+        }
+
+        status = WEXITSTATUS(status);
+
+        switch(status) {
         case 0:
             SLOGI("Filesystem check completed OK");
             return 0;
@@ -84,7 +101,7 @@
             return -1;
 
         default:
-            SLOGE("Filesystem check failed (unknown exit code %d)", rc);
+            SLOGE("Filesystem check failed (unknown exit code %d)", status);
             errno = EIO;
             return -1;
         }
@@ -152,8 +169,9 @@
 
 int Fat::format(const char *fsPath, unsigned int numSectors) {
     int fd;
-    const char *args[11];
+    const char *args[10];
     int rc;
+    int status;
 
     args[0] = MKDOSFS_PATH;
     args[1] = "-F";
@@ -170,19 +188,33 @@
         args[7] = "-s";
         args[8] = size;
         args[9] = fsPath;
-        args[10] = NULL;
-        rc = logwrap(11, args, 1);
+        rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
+                false, true);
     } else {
         args[7] = fsPath;
-        args[8] = NULL;
-        rc = logwrap(9, args, 1);
+        rc = android_fork_execvp(8, (char **)args, &status, false,
+                true);
     }
 
-    if (rc == 0) {
+    if (rc != 0) {
+        SLOGE("Filesystem format failed due to logwrap error");
+        errno = EIO;
+        return -1;
+    }
+
+    if (!WIFEXITED(status)) {
+        SLOGE("Filesystem format did not exit properly");
+        errno = EIO;
+        return -1;
+    }
+
+    status = WEXITSTATUS(status);
+
+    if (status == 0) {
         SLOGI("Filesystem formatted OK");
         return 0;
     } else {
-        SLOGE("Format failed (unknown exit code %d)", rc);
+        SLOGE("Format failed (unknown exit code %d)", status);
         errno = EIO;
         return -1;
     }
diff --git a/VoldUtil.h b/VoldUtil.h
new file mode 100644
index 0000000..30a3add
--- /dev/null
+++ b/VoldUtil.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 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 _VOLDUTIL_H
+#define _VOLDUTIL_H
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+#endif
diff --git a/cryptfs.c b/cryptfs.c
index bcacc39..3af7a5e 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -67,8 +67,8 @@
 static char *saved_data_blkdev;
 static char *saved_mount_point;
 static int  master_key_saved = 0;
-#define FSTAB_PREFIX "/fstab."
-static char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+
+extern struct fstab *fstab;
 
 static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
 {
@@ -126,19 +126,6 @@
   return nr_sec;
 }
 
-/* Get and cache the name of the fstab file so we don't
- * keep talking over the socket to the property service.
- */
-static char *get_fstab_filename(void)
-{
-    if (fstab_filename[0] == 0) {
-        strcpy(fstab_filename, FSTAB_PREFIX);
-        property_get("ro.hardware", fstab_filename + sizeof(FSTAB_PREFIX) - 1, "");
-    }
-
-    return fstab_filename;
-}
-
 /* key or salt can be NULL, in which case just skip writing that value.  Useful to
  * update the failed mount count but not change the key.
  */
@@ -153,7 +140,7 @@
   char key_loc[PROPERTY_VALUE_MAX];
   struct stat statbuf;
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+  fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
 
   if (!strcmp(key_loc, KEY_IN_FOOTER)) {
     fname = real_blk_name;
@@ -252,7 +239,7 @@
   char *fname;
   struct stat statbuf;
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+  fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
 
   if (!strcmp(key_loc, KEY_IN_FOOTER)) {
     fname = real_blk_name;
@@ -377,6 +364,86 @@
 
 }
 
+static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
+                                     char *real_blk_name, const char *name, int fd,
+                                     char *extra_params)
+{
+  char buffer[DM_CRYPT_BUF_SIZE];
+  struct dm_ioctl *io;
+  struct dm_target_spec *tgt;
+  char *crypt_params;
+  char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
+  int i;
+
+  io = (struct dm_ioctl *) buffer;
+
+  /* Load the mapping table for this device */
+  tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+  ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+  io->target_count = 1;
+  tgt->status = 0;
+  tgt->sector_start = 0;
+  tgt->length = crypt_ftr->fs_size;
+  strcpy(tgt->target_type, "crypt");
+
+  crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+  convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+  sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
+          master_key_ascii, real_blk_name, extra_params);
+  crypt_params += strlen(crypt_params) + 1;
+  crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
+  tgt->next = crypt_params - buffer;
+
+  for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
+    if (! ioctl(fd, DM_TABLE_LOAD, io)) {
+      break;
+    }
+    usleep(500000);
+  }
+
+  if (i == TABLE_LOAD_RETRIES) {
+    /* We failed to load the table, return an error */
+    return -1;
+  } else {
+    return i + 1;
+  }
+}
+
+
+static int get_dm_crypt_version(int fd, const char *name,  int *version)
+{
+    char buffer[DM_CRYPT_BUF_SIZE];
+    struct dm_ioctl *io;
+    struct dm_target_versions *v;
+    int i;
+
+    io = (struct dm_ioctl *) buffer;
+
+    ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+
+    if (ioctl(fd, DM_LIST_VERSIONS, io)) {
+        return -1;
+    }
+
+    /* Iterate over the returned versions, looking for name of "crypt".
+     * When found, get and return the version.
+     */
+    v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
+    while (v->next) {
+        if (! strcmp(v->name, "crypt")) {
+            /* We found the crypt driver, return the version, and get out */
+            version[0] = v->version[0];
+            version[1] = v->version[1];
+            version[2] = v->version[2];
+            return 0;
+        }
+        v = (struct dm_target_versions *)(((char *)v) + v->next);
+    }
+
+    return -1;
+}
+
 static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
                                     char *real_blk_name, char *crypto_blk_name, const char *name)
 {
@@ -389,6 +456,9 @@
   int fd;
   int i;
   int retval = -1;
+  int version[3];
+  char *extra_params;
+  int load_count;
 
   if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
     SLOGE("Cannot open device-mapper\n");
@@ -412,40 +482,27 @@
   minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
   snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
 
-  /* Load the mapping table for this device */
-  tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
-
-  ioctl_init(io, 4096, name, 0);
-  io->target_count = 1;
-  tgt->status = 0;
-  tgt->sector_start = 0;
-  tgt->length = crypt_ftr->fs_size;
-  strcpy(tgt->target_type, "crypt");
-
-  crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-  convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
-  sprintf(crypt_params, "%s %s 0 %s 0", crypt_ftr->crypto_type_name,
-          master_key_ascii, real_blk_name);
-  crypt_params += strlen(crypt_params) + 1;
-  crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
-  tgt->next = crypt_params - buffer;
-
-  for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
-    if (! ioctl(fd, DM_TABLE_LOAD, io)) {
-      break;
-    }
-    usleep(500000);
+  extra_params = "";
+  if (! get_dm_crypt_version(fd, name, version)) {
+      /* Support for allow_discards was added in version 1.11.0 */
+      if ((version[0] >= 2) ||
+          ((version[0] == 1) && (version[1] >= 11))) {
+          extra_params = "1 allow_discards";
+          SLOGI("Enabling support for allow_discards in dmcrypt.\n");
+      }
   }
 
-  if (i == TABLE_LOAD_RETRIES) {
+  load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name,
+                                         fd, extra_params);
+  if (load_count < 0) {
       SLOGE("Cannot load dm-crypt mapping table.\n");
       goto errout;
-  } else if (i) {
-      SLOGI("Took %d tries to load dmcrypt table.\n", i + 1);
+  } else if (load_count > 1) {
+      SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
   }
 
   /* Resume this device to activate it */
-  ioctl_init(io, 4096, name, 0);
+  ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
 
   if (ioctl(fd, DM_DEV_SUSPEND, io)) {
     SLOGE("Cannot resume the dm-crypt device\n");
@@ -616,7 +673,7 @@
     return rc;
 }
 
-#define DATA_PREP_TIMEOUT 100
+#define DATA_PREP_TIMEOUT 200
 static int prep_data_fs(void)
 {
     int i;
@@ -626,7 +683,7 @@
     property_set("vold.decrypt", "trigger_post_fs_data");
     SLOGD("Just triggered post_fs_data\n");
 
-    /* Wait a max of 25 seconds, hopefully it takes much less */
+    /* Wait a max of 50 seconds, hopefully it takes much less */
     for (i=0; i<DATA_PREP_TIMEOUT; i++) {
         char p[PROPERTY_VALUE_MAX];
 
@@ -639,6 +696,7 @@
     }
     if (i == DATA_PREP_TIMEOUT) {
         /* Ugh, we failed to prep /data in time.  Bail. */
+        SLOGE("post_fs_data timed out!\n");
         return -1;
     } else {
         SLOGD("post_fs_data done\n");
@@ -707,7 +765,7 @@
 
     if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
         /* If that succeeded, then mount the decrypted filesystem */
-        fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, 0);
+        fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0);
 
         property_set("vold.decrypt", "trigger_load_persist_props");
         /* Create necessary paths on /data */
@@ -745,10 +803,10 @@
     return 1;
   }
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+  fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
   if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
-    fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+    fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
 
     /*
      * Only report this error if key_loc is a file and it exists.
@@ -795,7 +853,7 @@
     return -1;
   }
 
-  fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+  fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
   if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
     SLOGE("Error getting crypt footer and key\n");
@@ -824,7 +882,7 @@
    */
   sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point);
   mkdir(tmp_mount_point, 0755);
-  if (fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
+  if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
     SLOGE("Error temp mounting decrypted block device\n");
     delete_crypto_blk_dev(label);
     crypt_ftr.failed_decrypt_count++;
@@ -955,7 +1013,7 @@
         return -1;
     }
 
-    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+    fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
     if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
         SLOGE("Error getting crypt footer and key\n");
@@ -1157,7 +1215,7 @@
         goto error_unencrypted;
     }
 
-    fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+    fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
 
     if (!strcmp(howarg, "wipe")) {
       how = CRYPTO_ENABLE_WIPE;
@@ -1168,7 +1226,7 @@
       goto error_unencrypted;
     }
 
-    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+    fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
     /* Get the size of the real block device */
     fd = open(real_blkdev, O_RDONLY);
@@ -1461,7 +1519,7 @@
         return -1;
     }
 
-    fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+    fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
     if (strlen(real_blkdev) == 0) {
         SLOGE("Can't find real blkdev");
         return -1;
diff --git a/fstrim.c b/fstrim.c
new file mode 100644
index 0000000..4911778
--- /dev/null
+++ b/fstrim.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <limits.h>
+#include <linux/fs.h>
+#include <time.h>
+#include <fs_mgr.h>
+#include <pthread.h>
+#define LOG_TAG "fstrim"
+#include "cutils/log.h"
+#include "hardware_legacy/power.h"
+
+/* These numbers must match what the MountService specified in
+ * frameworks/base/services/java/com/android/server/EventLogTags.logtags
+ */
+#define LOG_FSTRIM_START  2755
+#define LOG_FSTRIM_FINISH 2756
+
+#define FSTRIM_WAKELOCK "dofstrim"
+
+static unsigned long long get_boot_time_ms(void)
+{
+    struct timespec t;
+    unsigned long long time_ms;
+
+    t.tv_sec = 0;
+    t.tv_nsec = 0;
+    clock_gettime(CLOCK_BOOTTIME, &t);
+    time_ms = (t.tv_sec * 1000LL) + (t.tv_nsec / 1000000);
+
+    return time_ms;
+}
+
+static void *do_fstrim_filesystems(void *ignored)
+{
+    int i;
+    int fd;
+    int ret = 0;
+    struct fstrim_range range = { 0 };
+    struct stat sb;
+    extern struct fstab *fstab;
+
+    SLOGI("Starting fstrim work...\n");
+
+    /* Log the start time in the event log */
+    LOG_EVENT_LONG(LOG_FSTRIM_START, get_boot_time_ms());
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Skip raw partitions */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            continue;
+        }
+        /* Skip read-only filesystems */
+        if (fstab->recs[i].flags & MS_RDONLY) {
+            continue;
+        }
+        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
+            continue; /* Should we trim fat32 filesystems? */
+        }
+
+        if (stat(fstab->recs[i].mount_point, &sb) == -1) {
+            SLOGE("Cannot stat mount point %s\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+        if (!S_ISDIR(sb.st_mode)) {
+            SLOGE("%s is not a directory\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+
+        fd = open(fstab->recs[i].mount_point, O_RDONLY);
+        if (fd < 0) {
+            SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+
+        memset(&range, 0, sizeof(range));
+        range.len = ULLONG_MAX;
+        SLOGI("Invoking FITRIM ioctl on %s", fstab->recs[i].mount_point);
+        if (ioctl(fd, FITRIM, &range)) {
+            SLOGE("FITRIM ioctl failed on %s", fstab->recs[i].mount_point);
+            ret = -1;
+        }
+        SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point);
+        close(fd);
+    }
+
+    /* Log the finish time in the event log */
+    LOG_EVENT_LONG(LOG_FSTRIM_FINISH, get_boot_time_ms());
+
+    SLOGI("Finished fstrim work.\n");
+
+    /* Release the wakelock that let us work */
+    release_wake_lock(FSTRIM_WAKELOCK);
+
+    return (void *)ret;
+}
+
+int fstrim_filesystems(void)
+{
+    pthread_t t;
+    int ret;
+
+    /* Get a wakelock as this may take a while, and we don't want the
+     * device to sleep on us.
+     */
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, FSTRIM_WAKELOCK);
+
+    /* Depending on the emmc chip and size, this can take upwards
+     * of a few minutes.  If done in the same thread as the caller
+     * of this function, that would block vold from accepting any
+     * commands until the trim is finished.  So start another thread
+     * to do the work, and return immediately.
+     *
+     * This function should not be called more than once per day, but
+     * even if it is called a second time before the first one finishes,
+     * the kernel will "do the right thing" and split the work between
+     * the two ioctls invoked in separate threads.
+     */
+    ret = pthread_create(&t, NULL, do_fstrim_filesystems, NULL);
+    if (ret) {
+        SLOGE("Cannot create thread to do fstrim");
+        return ret;
+    }
+
+    ret = pthread_detach(t);
+    if (ret) {
+        SLOGE("Cannot detach thread doing fstrim");
+        return ret;
+    }
+
+    return 0;
+}
diff --git a/fstrim.h b/fstrim.h
new file mode 100644
index 0000000..e46e804
--- /dev/null
+++ b/fstrim.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    int fstrim_filesystems(void);
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/logwrapper.c b/logwrapper.c
deleted file mode 100644
index 34a1e5a..0000000
--- a/logwrapper.c
+++ /dev/null
@@ -1,170 +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"
-#include "cutils/sched_policy.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';
-
-                ALOG(LOG_INFO, tag, "%s", &buffer[a]);
-                a = b + 1;
-            }
-        }
-
-        if (a == 0 && b == sizeof(buffer) - 1) {
-            // buffer is full, flush
-            buffer[b] = '\0';
-            ALOG(LOG_INFO, tag, "%s", &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';
-        ALOG(LOG_INFO, tag, "%s", &buffer[a]);
-    }
-    status = 0xAAAA;
-    if (wait(&status) != -1) {  // Wait for child
-        if (WIFEXITED(status)) {
-            if (WEXITSTATUS(status) != 0) {
-                ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
-                        WEXITSTATUS(status));
-            }
-            return WEXITSTATUS(status);
-        } else if (WIFSIGNALED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
-                    WTERMSIG(status));
-        else if (WIFSTOPPED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
-                    WSTOPSIG(status));
-    } else
-        ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
-                strerror(errno), errno);
-    return -EAGAIN;
-}
-
-void child(int argc, const 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 (execv(argv_child[0], argv_child)) {
-        ALOG(LOG_ERROR, "logwrapper",
-            "executing %s failed: %s", argv_child[0], strerror(errno));
-        exit(-1);
-    }
-}
-
-int logwrap(int argc, const char* argv[], int background)
-{
-    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) {
-        ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
-        return -errno;
-    }
-
-    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
-            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
-        close(parent_ptty);
-        ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
-        return -1;
-    }
-
-    pid = fork();
-    if (pid < 0) {
-        close(parent_ptty);
-        ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
-        return -errno;
-    } else if (pid == 0) {
-        /*
-         * Child
-         */
-        child_ptty = open(child_devname, O_RDWR);
-        if (child_ptty < 0) {
-            close(parent_ptty);
-            ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
-            return -errno;
-        }
-
-        // redirect stdout and stderr
-        close(parent_ptty);
-        dup2(child_ptty, 1);
-        dup2(child_ptty, 2);
-        close(child_ptty);
-
-        if (background) {
-            int err = set_sched_policy(getpid(), SP_BACKGROUND);
-            if (err < 0) {
-                ALOG(LOG_WARN, "logwrapper",
-                    "Unable to background process (%s)", strerror(-err));
-            }
-        }
-
-        child(argc, argv);
-    } else {
-        /*
-         * Parent
-         */
-        int rc = parent(argv[0], parent_ptty);
-        close(parent_ptty);
-        return rc;
-    }
-
-    return 0;
-}
diff --git a/main.cpp b/main.cpp
index 5924fe4..02506e7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -23,10 +23,13 @@
 
 #include <fcntl.h>
 #include <dirent.h>
+#include <fs_mgr.h>
 
 #define LOG_TAG "Vold"
 
+#include "cutils/klog.h"
 #include "cutils/log.h"
+#include "cutils/properties.h"
 
 #include "VolumeManager.h"
 #include "CommandListener.h"
@@ -37,6 +40,9 @@
 static int process_config(VolumeManager *vm);
 static void coldboot(const char *path);
 
+#define FSTAB_PREFIX "/fstab."
+struct fstab *fstab;
+
 int main() {
 
     VolumeManager *vm;
@@ -47,6 +53,9 @@
 
     mkdir("/dev/block/vold", 0755);
 
+    /* For when cryptfs checks and mounts an encrypted filesystem */
+    klog_set_level(6);
+
     /* Create our singleton managers */
     if (!(vm = VolumeManager::Instance())) {
         SLOGE("Unable to create VolumeManager");
@@ -142,111 +151,54 @@
     }
 }
 
-static int parse_mount_flags(char *mount_flags)
+static int process_config(VolumeManager *vm)
 {
-    char *save_ptr;
-    int flags = 0;
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROPERTY_VALUE_MAX];
+    int i;
+    int ret = -1;
+    int flags;
 
-    if (strcasestr(mount_flags, "encryptable")) {
-        flags |= VOL_ENCRYPTABLE;
-    }
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
 
-    if (strcasestr(mount_flags, "nonremovable")) {
-        flags |= VOL_NONREMOVABLE;
-    }
-
-    return flags;
-}
-
-static int process_config(VolumeManager *vm) {
-    FILE *fp;
-    int n = 0;
-    char line[255];
-
-    if (!(fp = fopen("/etc/vold.fstab", "r"))) {
+    fstab = fs_mgr_read_fstab(fstab_filename);
+    if (!fstab) {
+        SLOGE("failed to open %s\n", fstab_filename);
         return -1;
     }
 
-    while(fgets(line, sizeof(line), fp)) {
-        const char *delim = " \t";
-        char *save_ptr;
-        char *type, *label, *mount_point, *mount_flags, *sysfs_path;
-        int flags;
-
-        n++;
-        line[strlen(line)-1] = '\0';
-
-        if (line[0] == '#' || line[0] == '\0')
-            continue;
-
-        if (!(type = strtok_r(line, delim, &save_ptr))) {
-            SLOGE("Error parsing type");
-            goto out_syntax;
-        }
-        if (!(label = strtok_r(NULL, delim, &save_ptr))) {
-            SLOGE("Error parsing label");
-            goto out_syntax;
-        }
-        if (!(mount_point = strtok_r(NULL, delim, &save_ptr))) {
-            SLOGE("Error parsing mount point");
-            goto out_syntax;
-        }
-
-        if (!strcmp(type, "dev_mount")) {
+    /* Loop through entries looking for ones that vold manages */
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
             DirectVolume *dv = NULL;
-            char *part;
+            flags = 0;
 
-            if (!(part = strtok_r(NULL, delim, &save_ptr))) {
-                SLOGE("Error parsing partition");
-                goto out_syntax;
-            }
-            if (strcmp(part, "auto") && atoi(part) == 0) {
-                SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);
-                goto out_syntax;
+            dv = new DirectVolume(vm, fstab->recs[i].label,
+                                  fstab->recs[i].mount_point,
+                                  fstab->recs[i].partnum);
+
+            if (dv->addPath(fstab->recs[i].blk_device)) {
+                SLOGE("Failed to add devpath %s to volume %s",
+                      fstab->recs[i].blk_device, fstab->recs[i].label);
+                goto out_fail;
             }
 
-            if (!strcmp(part, "auto")) {
-                dv = new DirectVolume(vm, label, mount_point, -1);
-            } else {
-                dv = new DirectVolume(vm, label, mount_point, atoi(part));
+            /* Set any flags that might be set for this volume */
+            if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
+                flags |= VOL_NONREMOVABLE;
             }
-
-            while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {
-                if (*sysfs_path != '/') {
-                    /* If the first character is not a '/', it must be flags */
-                    break;
-                }
-                if (dv->addPath(sysfs_path)) {
-                    SLOGE("Failed to add devpath %s to volume %s", sysfs_path,
-                         label);
-                    goto out_fail;
-                }
+            if (fs_mgr_is_encryptable(&fstab->recs[i])) {
+                flags |= VOL_ENCRYPTABLE;
             }
-
-            /* If sysfs_path is non-null at this point, then it contains
-             * the optional flags for this volume
-             */
-            if (sysfs_path)
-                flags = parse_mount_flags(sysfs_path);
-            else
-                flags = 0;
             dv->setFlags(flags);
 
             vm->addVolume(dv);
-        } else if (!strcmp(type, "map_mount")) {
-        } else {
-            SLOGE("Unknown type '%s'", type);
-            goto out_syntax;
         }
     }
 
-    fclose(fp);
-    return 0;
+    ret = 0;
 
-out_syntax:
-    SLOGE("Syntax error on config line %d", n);
-    errno = -EINVAL;
 out_fail:
-    fclose(fp);
-    return -1;   
+    return ret;
 }