Merge "Make the root/unroot test more robust."
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index db63bcc..028791c 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -42,9 +42,24 @@
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
 
+#define FSTAB_PREFIX "/fstab."
+
 #define VERITY_METADATA_SIZE 32768
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 
+#define VERITY_STATE_HEADER 0x83c0ae9d
+#define VERITY_STATE_VERSION 1
+
+#define VERITY_KMSG_RESTART "dm-verity device corrupted"
+#define VERITY_KMSG_BUFSIZE 1024
+
+struct verity_state {
+    uint32_t header;
+    uint32_t version;
+    uint32_t size;
+    int32_t mode;
+};
+
 extern struct fs_info info;
 
 static RSAPublicKey *load_key(char *path)
@@ -294,10 +309,12 @@
     return 0;
 }
 
-static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table,
+        int mode)
 {
     char *verity_params;
     char *buffer = (char*) io;
+    size_t bufsize;
     uint64_t device_size = 0;
 
     if (get_target_device_size(blockdev, &device_size) < 0) {
@@ -317,7 +334,17 @@
 
     // build the verity params here
     verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-    strcpy(verity_params, table);
+    bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+    if (mode == VERITY_MODE_EIO) {
+        // allow operation with older dm-verity drivers that are unaware
+        // of the mode parameter by omitting it; this also means that we
+        // cannot use logging mode with these drivers, they always cause
+        // an I/O error for corrupted blocks
+        strcpy(verity_params, table);
+    } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
+        return -1;
+    }
 
     // set next target boundary
     verity_params += strlen(verity_params) + 1;
@@ -359,31 +386,316 @@
     char *key;
     ret = asprintf(&key, "partition.%s.verified", name);
     if (ret < 0) {
-        ERROR("Error formatting verified property");
+        ERROR("Error formatting verified property\n");
         return ret;
     }
     ret = PROP_NAME_MAX - strlen(key);
     if (ret < 0) {
-        ERROR("Verified property name is too long");
+        ERROR("Verified property name is too long\n");
+        free(key);
         return -1;
     }
     ret = property_set(key, "1");
     if (ret < 0)
-        ERROR("Error setting verified property %s: %d", key, ret);
+        ERROR("Error setting verified property %s: %d\n", key, ret);
     free(key);
     return ret;
 }
 
+static int check_verity_restart(const char *fname)
+{
+    char buffer[VERITY_KMSG_BUFSIZE + 1];
+    int fd;
+    int rc = 0;
+    ssize_t size;
+    struct stat s;
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        if (errno != ENOENT) {
+            ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        }
+        goto out;
+    }
+
+    if (fstat(fd, &s) == -1) {
+        ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    size = VERITY_KMSG_BUFSIZE;
+
+    if (size > s.st_size) {
+        size = s.st_size;
+    }
+
+    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
+        ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
+            strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
+        ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
+            strerror(errno));
+        goto out;
+    }
+
+    buffer[size] = '\0';
+
+    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
+        rc = 1;
+    }
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int was_verity_restart()
+{
+    static const char *files[] = {
+        "/sys/fs/pstore/console-ramoops",
+        "/proc/last_kmsg",
+        NULL
+    };
+    int i;
+
+    for (i = 0; files[i]; ++i) {
+        if (check_verity_restart(files[i])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
+{
+    int fd;
+    int rc = -1;
+
+    struct verity_state s = {
+        VERITY_STATE_HEADER,
+        VERITY_STATE_VERSION,
+        sizeof(struct verity_state),
+        mode
+    };
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(lseek64(fd, offset, SEEK_SET)) < 0) {
+        ERROR("Failed to seek %s to %" PRIu64 " (%s)\n", fname, offset, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(write(fd, &s, sizeof(s))) != sizeof(s)) {
+        ERROR("Failed to write %zu bytes to %s (%s)\n", sizeof(s), fname, strerror(errno));
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int get_verity_state_location(char *location, off64_t *offset)
+{
+    char state_off[PROPERTY_VALUE_MAX];
+
+    if (property_get("ro.verity.state.location", location, NULL) <= 0) {
+        return -1;
+    }
+
+    if (*location != '/' || access(location, R_OK | W_OK) == -1) {
+        ERROR("Failed to access verity state %s (%s)\n", location, strerror(errno));
+        return -1;
+    }
+
+    *offset = 0;
+
+    if (property_get("ro.verity.state.offset", state_off, NULL) > 0) {
+        *offset = strtoll(state_off, NULL, 0);
+
+        if (errno == ERANGE || errno == EINVAL) {
+            ERROR("Invalid value in ro.verity.state.offset (%s)\n", state_off);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int fs_mgr_load_verity_state(int *mode)
+{
+    char fname[PROPERTY_VALUE_MAX];
+    int fd = -1;
+    int rc = -1;
+    off64_t offset = 0;
+    struct verity_state s;
+
+    if (get_verity_state_location(fname, &offset) < 0) {
+        /* location for dm-verity state is not specified, fall back to
+         * default behavior: return -EIO for corrupted blocks */
+        *mode = VERITY_MODE_EIO;
+        rc = 0;
+        goto out;
+    }
+
+    if (was_verity_restart()) {
+        /* device was restarted after dm-verity detected a corrupted
+         * block, so switch to logging mode */
+        *mode = VERITY_MODE_LOGGING;
+        rc = write_verity_state(fname, offset, *mode);
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(lseek64(fd, offset, SEEK_SET)) < 0) {
+        ERROR("Failed to seek %s to %" PRIu64 " (%s)\n", fname, offset, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(read(fd, &s, sizeof(s))) != sizeof(s)) {
+        ERROR("Failed to read %zu bytes from %s (%s)\n", sizeof(s), fname, strerror(errno));
+        goto out;
+    }
+
+    if (s.header != VERITY_STATE_HEADER) {
+        goto out;
+    }
+
+    if (s.version != VERITY_STATE_VERSION) {
+        ERROR("Unsupported verity state version (%u)\n", s.version);
+        goto out;
+    }
+
+    if (s.size != sizeof(s)) {
+        ERROR("Unexpected verity state size (%u)\n", s.size);
+        goto out;
+    }
+
+    if (s.mode < VERITY_MODE_EIO ||
+        s.mode > VERITY_MODE_LAST) {
+        ERROR("Unsupported verity mode (%u)\n", s.mode);
+        goto out;
+    }
+
+    *mode = s.mode;
+    rc = 0;
+
+out:
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+int fs_mgr_update_verity_state()
+{
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char *mount_point;
+    char propbuf[PROPERTY_VALUE_MAX];
+    char state_loc[PROPERTY_VALUE_MAX];
+    char *status;
+    int fd = -1;
+    int i;
+    int rc = -1;
+    off64_t offset = 0;
+    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+    struct fstab *fstab = NULL;
+
+    if (get_verity_state_location(state_loc, &offset) < 0) {
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Error opening device mapper (%s)\n", strerror(errno));
+        goto out;
+    }
+
+    property_get("ro.hardware", propbuf, "");
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+    fstab = fs_mgr_read_fstab(fstab_filename);
+
+    if (!fstab) {
+        ERROR("Failed to read %s\n", fstab_filename);
+        goto out;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_mgr_is_verified(&fstab->recs[i])) {
+            continue;
+        }
+
+        mount_point = basename(fstab->recs[i].mount_point);
+        verity_ioctl_init(io, mount_point, 0);
+
+        if (ioctl(fd, DM_TABLE_STATUS, io)) {
+            ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
+                strerror(errno));
+            goto out;
+        }
+
+        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+        if (*status == 'C') {
+            rc = write_verity_state(state_loc, offset, VERITY_MODE_LOGGING);
+            goto out;
+        }
+    }
+
+    /* Don't overwrite possible previous state if there's no corruption. */
+    rc = 0;
+
+out:
+    if (fstab) {
+        fs_mgr_free_fstab(fstab);
+    }
+
+    if (fd) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
 int fs_mgr_setup_verity(struct fstab_rec *fstab) {
 
-    int retval = -1;
+    int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
+    int mode;
 
     char *verity_blk_name = 0;
     char *verity_table = 0;
     char *verity_table_signature = 0;
 
-    char buffer[DM_BUF_SIZE];
+    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     char *mount_point = basename(fstab->mount_point);
 
@@ -407,6 +719,8 @@
         goto out;
     }
 
+    retval = FS_MGR_SETUP_VERITY_FAIL;
+
     // get the device mapper fd
     if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
         ERROR("Error opening device mapper (%s)", strerror(errno));
@@ -432,8 +746,13 @@
         goto out;
     }
 
+    if (fs_mgr_load_verity_state(&mode) < 0) {
+        mode = VERITY_MODE_RESTART; /* default dm-verity mode */
+    }
+
     // load the verity mapping table
-    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+    if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table,
+            mode) < 0) {
         goto out;
     }
 
@@ -455,8 +774,12 @@
         goto out;
     }
 
-    // set the property indicating that the partition is verified
-    retval = set_verified_property(mount_point);
+    if (mode == VERITY_MODE_LOGGING) {
+        retval = FS_MGR_SETUP_VERITY_SUCCESS;
+    } else {
+        // set the property indicating that the partition is verified
+        retval = set_verified_property(mount_point);
+    }
 
 out:
     if (fd != -1) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 5ec3b99..57600ef 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -27,6 +27,14 @@
 // turn verity off in userdebug builds.
 #define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
 
+// Verity modes
+enum verity_mode {
+    VERITY_MODE_EIO = 0,
+    VERITY_MODE_LOGGING = 1,
+    VERITY_MODE_RESTART = 2,
+    VERITY_MODE_LAST = VERITY_MODE_RESTART
+};
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -75,6 +83,8 @@
 int fs_mgr_unmount_all(struct fstab *fstab);
 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
                           char *real_blk_device, int size);
+int fs_mgr_load_verity_state(int *mode);
+int fs_mgr_update_verity_state();
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
                      const char *blk_device);
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index cc7ba30..724ca51 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -41,4 +41,46 @@
     log_time realtime;
 } android_log_header_t;
 
+/* Event Header Structure to logd */
+typedef struct __attribute__((__packed__)) {
+    int32_t tag;  // Little Endian Order
+} android_event_header_t;
+
+/* Event payload EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_INT
+    int32_t data; // Little Endian Order
+} android_event_int_t;
+
+/* Event with single EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_int_t payload;
+} android_log_event_int_t;
+
+/* Event payload EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;  // EVENT_TYPE_LONG
+    int64_t data; // Little Endian Order
+} android_event_long_t;
+
+/* Event with single EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_long_t payload;
+} android_log_event_long_t;
+
+/* Event payload EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+    int8_t type;    // EVENT_TYPE_STRING;
+    int32_t length; // Little Endian Order
+    char data[];
+} android_event_string_t;
+
+/* Event with single EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+    android_event_header_t header;
+    android_event_string_t payload;
+} android_log_event_string_t;
+
 #endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9f3dcc1..b4204d8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -712,6 +712,20 @@
     return 0;
 }
 
+int do_verity_load_state(int nargs, char **args) {
+    if (nargs == 1) {
+        int mode = -1;
+        int rc = fs_mgr_load_verity_state(&mode);
+
+        if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+            action_for_each_trigger("verity-logging", action_add_queue_tail);
+        }
+
+        return rc;
+    }
+    return -1;
+}
+
 int do_write(int nargs, char **args)
 {
     const char *path = args[1];
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 5715862..d6082aa 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -1,12 +1,9 @@
 #!/bin/sh
 #
-# this script is used to retrieve the bootchart log generated
-# by init when compiled with INIT_BOOTCHART=true.
-#
+# This script is used to retrieve a bootchart log generated by init.
 # All options are passed to adb, for better or for worse.
-#
-# for all details, see //device/system/init/README.BOOTCHART
-#
+# See the readme in this directory for more on bootcharting.
+
 TMPDIR=/tmp/android-bootchart
 rm -rf $TMPDIR
 mkdir -p $TMPDIR
@@ -22,4 +19,4 @@
 (cd $TMPDIR && tar -czf $TARBALL $FILES)
 bootchart ${TMPDIR}/${TARBALL}
 gnome-open ${TARBALL%.tgz}.png
-echo "Clean up ${TMPDIR}/ & ./${TARBALL%.tgz}.png when done"
+echo "Clean up ${TMPDIR}/ and ./${TARBALL%.tgz}.png when done"
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 61a5e0a..3932357 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -204,6 +204,9 @@
     case 'u':
         if (!strcmp(s, "ser")) return K_user;
         break;
+    case 'v':
+        if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
+        break;
     case 'w':
         if (!strcmp(s, "rite")) return K_write;
         if (!strcmp(s, "ait")) return K_wait;
diff --git a/init/keywords.h b/init/keywords.h
index a8f29d1..60931f1 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -41,6 +41,7 @@
 int do_loglevel(int nargs, char **args);
 int do_load_persist_props(int nargs, char **args);
 int do_load_all_props(int nargs, char **args);
+int do_verity_load_state(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -97,6 +98,7 @@
     KEYWORD(symlink,     COMMAND, 1, do_symlink)
     KEYWORD(sysclktz,    COMMAND, 1, do_sysclktz)
     KEYWORD(user,        OPTION,  0, 0)
+    KEYWORD(verity_load_state,      COMMAND, 0, do_verity_load_state)
     KEYWORD(wait,        COMMAND, 1, do_wait)
     KEYWORD(write,       COMMAND, 2, do_write)
     KEYWORD(copy,        COMMAND, 2, do_copy)
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 5756c54..4e6424a 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,6 +16,14 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
+# This is what we want to do:
+#  liblog_cflags := $(shell \
+#   sed -n \
+#       's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
+#       $(LOCAL_PATH)/event.logtags)
+# so make sure we do not regret hard-coding it as follows:
+liblog_cflags := -DLIBLOG_LOG_TAG=1005
+
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_sources := logd_write.c
 else
@@ -25,28 +33,20 @@
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
-WITH_MINGW :=
-ifeq ($(HOST_OS),windows)
-    ifeq ($(strip $(USE_CYGWIN)),)
-        WITH_MINGW := true
-    endif
-endif
-# USE_MINGW is defined when we build against Mingw on Linux
-ifneq ($(strip $(USE_MINGW)),)
-    WITH_MINGW := true
-endif
 
-ifndef WITH_MINGW
+ifeq ($(strip $(USE_MINGW)),)
     liblog_sources += \
-        logprint.c \
         event_tag_map.c
 else
     liblog_sources += \
         uio.c
 endif
 
-liblog_host_sources := $(liblog_sources) fake_log_device.c
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
 liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c
+ifeq ($(strip $(USE_MINGW)),)
+liblog_target_sources += logprint.c
+endif
 ifneq ($(TARGET_USES_LOGD),false)
 liblog_target_sources += log_read.c
 else
@@ -57,7 +57,7 @@
 # ========================================================
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -76,13 +76,13 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := liblog
 LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index 461dfbe..f29ac04 100644
--- a/liblog/README
+++ b/liblog/README
@@ -131,6 +131,33 @@
        when  opening  the  sub-log.    It  is  recommended  to  open  the  log
        ANDROID_LOG_RDONLY in these cases.
 
+ERRORS
+       If messages fail, a negative error code will be returned to the caller.
+
+       The -ENOTCONN return code indicates that the logger daemon is stopped.
+
+       The  -EBADF return code indicates that the log access point can not be
+       opened, or the log buffer id is out of range.
+
+       For the  -EAGAIN  return code,  this means that the logging message was
+       temporarily backed-up either because of Denial Of Service (DOS) logging
+       pressure from some chatty application or service in the Android system,
+       or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen.
+       To aid in diagnosing the occurence of this,  a binary event from liblog
+       will be sent to the  log  daemon  once a  new  message  can get through
+       indicating how many  messages were  dropped  as a result.   Please take
+       action to resolve the structural problems at the source.
+
+       It is generally not advised for the caller to retry the  -EAGAIN return
+       code as  this  will  only  make the  problem(s)  worse  and  cause your
+       application to temporarily drop to the  logger daemon  priority,  BATCH
+       scheduling policy and background task cgroup. If you require a group of
+       messages to be passed atomically,  merge  them  into  one  message with
+       embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD.
+
+       Other return codes  from  writing operation can be returned.  Since the
+       library retries on EINTR, -EINTR should never be returned.
+
 SEE ALSO
        syslogd(8)
 
diff --git a/liblog/event.logtags b/liblog/event.logtags
new file mode 100644
index 0000000..72ecab1
--- /dev/null
+++ b/liblog/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1005  liblog (dropped|1)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 0208c73..a865093 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,12 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#if (FAKE_LOG_DEVICE == 0)
+#include <endian.h>
+#endif
 #include <errno.h>
 #include <fcntl.h>
 #if !defined(_WIN32)
 #include <pthread.h>
 #endif
 #include <stdarg.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -172,6 +176,7 @@
     size_t i, payload_size;
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
     static pid_t last_pid = (pid_t) -1;
+    static atomic_int_fast32_t dropped;
 
     if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
         last_uid = getuid();
@@ -206,7 +211,6 @@
     pmsg_header.uid = last_uid;
     pmsg_header.pid = last_pid;
 
-    header.id = log_id;
     header.tid = gettid();
     header.realtime.tv_sec = ts.tv_sec;
     header.realtime.tv_nsec = ts.tv_nsec;
@@ -216,6 +220,28 @@
     newVec[1].iov_base   = (unsigned char *) &header;
     newVec[1].iov_len    = sizeof(header);
 
+    if (logd_fd > 0) {
+        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_EVENTS;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+            }
+        }
+    }
+
+    header.id = log_id;
+
     for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
         newVec[i].iov_base = vec[i - header_length].iov_base;
         payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
@@ -281,6 +307,8 @@
 
     if (ret > (ssize_t)sizeof(header)) {
         ret -= sizeof(header);
+    } else if (ret == -EAGAIN) {
+        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
     }
 #endif
 
@@ -463,7 +491,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 2ca3c94..ca63067 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -266,7 +266,7 @@
     }
 
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-    __builtin_trap(); /* trap so we have a chance to debug the situation */
+    abort(); /* abort so we have a chance to debug the situation */
     /* NOTREACHED */
 }
 
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index ba7b74d..3937449 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -24,7 +24,8 @@
 LOCAL_STATIC_LIBRARIES := libz
 LOCAL_SHARED_LIBRARIES := libutils
 LOCAL_MODULE:= libziparchive
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -Wold-style-cast
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index ebbab9f..59a1734 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,8 @@
  * Read-only access to Zip archives, with minimal heap allocation.
  */
 
+#include <memory>
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -293,7 +295,7 @@
 
   /* mapped central directory area */
   off64_t directory_offset;
-  android::FileMap* directory_map;
+  android::FileMap directory_map;
 
   /* number of entries in the Zip archive */
   uint16_t num_entries;
@@ -311,7 +313,6 @@
       fd(fd),
       close_file(assume_ownership),
       directory_offset(0),
-      directory_map(NULL),
       num_entries(0),
       hash_table_size(0),
       hash_table(NULL) {}
@@ -321,25 +322,10 @@
       close(fd);
     }
 
-    delete directory_map;
     free(hash_table);
   }
 };
 
-// Returns 0 on success and negative values on failure.
-static android::FileMap* MapFileSegment(const int fd, const off64_t start,
-                                        const size_t length, const bool read_only,
-                                        const char* debug_file_name) {
-  android::FileMap* file_map = new android::FileMap;
-  const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
-  if (!success) {
-    delete file_map;
-    return NULL;
-  }
-
-  return file_map;
-}
-
 static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
   static const uint32_t kBufSize = 32768;
   uint8_t buf[kBufSize];
@@ -521,16 +507,12 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  android::FileMap* map = MapFileSegment(fd,
-      static_cast<off64_t>(eocd->cd_start_offset),
-      static_cast<size_t>(eocd->cd_size),
-      true /* read only */, debug_file_name);
-  if (map == NULL) {
-    archive->directory_map = NULL;
+  if (!archive->directory_map.create(debug_file_name, fd,
+          static_cast<off64_t>(eocd->cd_start_offset),
+          static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
     return kMmapFailed;
   }
 
-  archive->directory_map = map;
   archive->num_entries = eocd->num_records;
   archive->directory_offset = eocd->cd_start_offset;
 
@@ -557,7 +539,7 @@
     return kInvalidFile;
   }
 
-  if (file_length > (off64_t) 0xffffffff) {
+  if (file_length > static_cast<off64_t>(0xffffffff)) {
     ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
     return kInvalidFile;
   }
@@ -599,9 +581,9 @@
  * Returns 0 on success.
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
-  int32_t result = -1;
-  const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
-  const size_t cd_length = archive->directory_map->getDataLength();
+  const uint8_t* const cd_ptr =
+      reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
+  const size_t cd_length = archive->directory_map.getDataLength();
   const uint16_t num_entries = archive->num_entries;
 
   /*
@@ -610,8 +592,8 @@
    * least one unused entry to avoid an infinite loop during creation.
    */
   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
-  archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
-      sizeof(ZipEntryName));
+  archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
+      sizeof(ZipEntryName)));
 
   /*
    * Walk through the central directory, adding entries to the hash
@@ -624,18 +606,19 @@
         reinterpret_cast<const CentralDirectoryRecord*>(ptr);
     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
       ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
-      goto bail;
+      return -1;
     }
 
     const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
-      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
-      goto bail;
+      ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
+          static_cast<int64_t>(local_header_offset), i);
+      return -1;
     }
 
     const uint16_t file_name_length = cdr->file_name_length;
@@ -645,7 +628,7 @@
 
     /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
     if (!IsValidEntryName(file_name, file_name_length)) {
-      goto bail;
+      return -1;
     }
 
     /* add the CDE filename to the hash table */
@@ -654,25 +637,21 @@
     entry_name.name_length = file_name_length;
     const int add_result = AddToHash(archive->hash_table,
         archive->hash_table_size, entry_name);
-    if (add_result) {
+    if (add_result != 0) {
       ALOGW("Zip: Error adding entry to hash table %d", add_result);
-      result = add_result;
-      goto bail;
+      return add_result;
     }
 
     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
           ptr - cd_ptr, cd_length, i);
-      goto bail;
+      return -1;
     }
   }
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
 
-  result = 0;
-
-bail:
-  return result;
+  return 0;
 }
 
 static int32_t OpenArchiveInternal(ZipArchive* archive,
@@ -713,7 +692,7 @@
  * Close a ZipArchive, closing the file and freeing the contents.
  */
 void CloseArchive(ZipArchiveHandle handle) {
-  ZipArchive* archive = (ZipArchive*) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   ALOGV("Closing archive %p", archive);
   delete archive;
 }
@@ -774,8 +753,8 @@
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
   const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
-    archive->directory_map->getDataPtr());
-  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
+    archive->directory_map.getDataPtr());
+  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -810,7 +789,8 @@
   ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
                                  local_header_offset);
   if (actual != sizeof(lfh_buf)) {
-    ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
+    ALOGW("Zip: failed reading lfh name from offset %" PRId64,
+        static_cast<int64_t>(local_header_offset));
     return kIoError;
   }
 
@@ -848,12 +828,12 @@
       return kInvalidOffset;
     }
 
-    uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+    uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
     ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
                                   name_offset);
 
     if (actual != nameLen) {
-      ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
+      ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
       free(name_buf);
       return kIoError;
     }
@@ -872,20 +852,21 @@
   const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
       + lfh->file_name_length + lfh->extra_field_length;
   if (data_offset > cd_offset) {
-    ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
+    ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
     return kInvalidOffset;
   }
 
-  if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+  if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
     ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-      (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
+      static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
     return kInvalidOffset;
   }
 
   if (data->method == kCompressStored &&
-    (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+    static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
      ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
-       (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
+       static_cast<int64_t>(data_offset), data->uncompressed_length,
+       static_cast<int64_t>(cd_offset));
      return kInvalidOffset;
   }
 
@@ -917,7 +898,7 @@
 
 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
                        const ZipEntryName* optional_prefix) {
-  ZipArchive* archive = (ZipArchive *) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
 
   if (archive == NULL || archive->hash_table == NULL) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
@@ -939,7 +920,7 @@
 
 int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
                   ZipEntry* data) {
-  const ZipArchive* archive = (ZipArchive*) handle;
+  const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   if (entryName.name_length == 0) {
     ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
     return kInvalidEntryName;
@@ -957,7 +938,7 @@
 }
 
 int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
-  IterationHandle* handle = (IterationHandle *) cookie;
+  IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
   if (handle == NULL) {
     return kInvalidHandle;
   }
@@ -991,10 +972,17 @@
   return kIterationEnd;
 }
 
+// This method is using libz macros with old-style-casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
+  return inflateInit2(stream, window_bits);
+}
+#pragma GCC diagnostic pop
+
 static int32_t InflateToFile(int fd, const ZipEntry* entry,
                              uint8_t* begin, uint32_t length,
                              uint64_t* crc_out) {
-  int32_t result = -1;
   const uint32_t kBufSize = 32768;
   uint8_t read_buf[kBufSize];
   uint8_t write_buf[kBufSize];
@@ -1010,7 +998,7 @@
   zstream.opaque = Z_NULL;
   zstream.next_in = NULL;
   zstream.avail_in = 0;
-  zstream.next_out = (Bytef*) write_buf;
+  zstream.next_out = reinterpret_cast<Bytef*>(write_buf);
   zstream.avail_out = kBufSize;
   zstream.data_type = Z_UNKNOWN;
 
@@ -1018,7 +1006,7 @@
    * Use the undocumented "negative window bits" feature to tell zlib
    * that there's no zlib header waiting for it.
    */
-  zerr = inflateInit2(&zstream, -MAX_WBITS);
+  zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
   if (zerr != Z_OK) {
     if (zerr == Z_VERSION_ERROR) {
       ALOGE("Installed zlib is not compatible with linked version (%s)",
@@ -1030,6 +1018,12 @@
     return kZlibError;
   }
 
+  auto zstream_deleter = [](z_stream* stream) {
+    inflateEnd(stream);  /* free up any allocated structures */
+  };
+
+  std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
+
   const uint32_t uncompressed_length = entry->uncompressed_length;
 
   uint32_t compressed_length = entry->compressed_length;
@@ -1041,8 +1035,7 @@
       const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
       if (actual != getSize) {
         ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
-        result = kIoError;
-        goto z_bail;
+        return kIoError;
       }
 
       compressed_length -= getSize;
@@ -1057,8 +1050,7 @@
       ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
           zerr, zstream.next_in, zstream.avail_in,
           zstream.next_out, zstream.avail_out);
-      result = kZlibError;
-      goto z_bail;
+      return kZlibError;
     }
 
     /* write when we're full or when we're done */
@@ -1067,7 +1059,7 @@
       const size_t write_size = zstream.next_out - write_buf;
       // The file might have declared a bogus length.
       if (write_size + write_count > length) {
-        goto z_bail;
+        return -1;
       }
       memcpy(begin + write_count, write_buf, write_size);
       write_count += write_size;
@@ -1085,26 +1077,20 @@
   if (zstream.total_out != uncompressed_length || compressed_length != 0) {
     ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
         zstream.total_out, uncompressed_length);
-    result = kInconsistentInformation;
-    goto z_bail;
+    return kInconsistentInformation;
   }
 
-  result = 0;
-
-z_bail:
-  inflateEnd(&zstream);    /* free up any allocated structures */
-
-  return result;
+  return 0;
 }
 
 int32_t ExtractToMemory(ZipArchiveHandle handle,
                         ZipEntry* entry, uint8_t* begin, uint32_t size) {
-  ZipArchive* archive = (ZipArchive*) handle;
+  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
   const uint16_t method = entry->method;
   off64_t data_offset = entry->offset;
 
   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
-    ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
+    ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
     return kIoError;
   }
 
@@ -1148,7 +1134,7 @@
   int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
   if (result == -1) {
     ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
-          (int64_t)(declared_length + current_offset), strerror(errno));
+          static_cast<int64_t>(declared_length + current_offset), strerror(errno));
     return kIoError;
   }
 
@@ -1159,16 +1145,14 @@
       return 0;
   }
 
-  android::FileMap* map  = MapFileSegment(fd, current_offset, declared_length,
-                                          false, kTempMappingFileName);
-  if (map == NULL) {
+  android::FileMap map;
+  if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
     return kMmapFailed;
   }
 
   const int32_t error = ExtractToMemory(handle, entry,
-                                        reinterpret_cast<uint8_t*>(map->getDataPtr()),
-                                        map->getDataLength());
-  delete map;
+                                        reinterpret_cast<uint8_t*>(map.getDataPtr()),
+                                        map.getDataLength());
   return error;
 }
 
@@ -1181,6 +1165,6 @@
 }
 
 int GetFileDescriptor(const ZipArchiveHandle handle) {
-  return ((ZipArchive*) handle)->fd;
+  return reinterpret_cast<ZipArchive*>(handle)->fd;
 }
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index cd5003e..7e4eadd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -38,14 +38,12 @@
     struct logger *logger;
     struct logger_list *logger_list;
     bool printed;
-    char label;
 
     log_device_t* next;
 
-    log_device_t(const char* d, bool b, char l) {
+    log_device_t(const char* d, bool b) {
         device = d;
         binary = b;
-        label = l;
         next = NULL;
         printed = false;
     }
@@ -61,9 +59,7 @@
 static int g_outFD = -1;
 static off_t g_outByteCount = 0;
 static int g_printBinary = 0;
-static int g_devCount = 0;
-
-static EventTagMap* g_eventTagMap = NULL;
+static int g_devCount = 0;                              // >1 means multiple
 
 static int openLogFile (const char *pathname)
 {
@@ -133,8 +129,15 @@
     char binaryMsgBuf[1024];
 
     if (dev->binary) {
+        static bool hasOpenedEventTagMap = false;
+        static EventTagMap *eventTagMap = NULL;
+
+        if (!eventTagMap && !hasOpenedEventTagMap) {
+            eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+            hasOpenedEventTagMap = true;
+        }
         err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
-                                                 g_eventTagMap,
+                                                 eventTagMap,
                                                  binaryMsgBuf,
                                                  sizeof(binaryMsgBuf));
         //printf(">>> pri=%d len=%d msg='%s'\n",
@@ -147,16 +150,6 @@
     }
 
     if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
-        if (false && g_devCount > 1) {
-            binaryMsgBuf[0] = dev->label;
-            binaryMsgBuf[1] = ' ';
-            bytesWritten = write(g_outFD, binaryMsgBuf, 2);
-            if (bytesWritten < 0) {
-                perror("output error");
-                exit(-1);
-            }
-        }
-
         bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
 
         if (bytesWritten < 0) {
@@ -331,7 +324,6 @@
     const char *forceFilters = NULL;
     log_device_t* devices = NULL;
     log_device_t* dev;
-    bool needBinary = false;
     bool printDividers = false;
     struct logger_list *logger_list;
     unsigned int tail_lines = 0;
@@ -469,7 +461,6 @@
 
                     devices = dev = NULL;
                     android::g_devCount = 0;
-                    needBinary = false;
                     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
@@ -479,7 +470,7 @@
                         }
 
                         bool binary = strcmp(name, "events") == 0;
-                        log_device_t* d = new log_device_t(name, binary, *name);
+                        log_device_t* d = new log_device_t(name, binary);
 
                         if (dev) {
                             dev->next = d;
@@ -488,26 +479,20 @@
                             devices = dev = d;
                         }
                         android::g_devCount++;
-                        if (binary) {
-                            needBinary = true;
-                        }
                     }
                     break;
                 }
 
                 bool binary = strcmp(optarg, "events") == 0;
-                if (binary) {
-                    needBinary = true;
-                }
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary, optarg[0]);
+                    dev->next = new log_device_t(optarg, binary);
                 } else {
-                    devices = new log_device_t(optarg, binary, optarg[0]);
+                    devices = new log_device_t(optarg, binary);
                 }
                 android::g_devCount++;
             }
@@ -641,14 +626,14 @@
     }
 
     if (!devices) {
-        dev = devices = new log_device_t("main", false, 'm');
+        dev = devices = new log_device_t("main", false);
         android::g_devCount = 1;
         if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
-            dev = dev->next = new log_device_t("system", false, 's');
+            dev = dev->next = new log_device_t("system", false);
             android::g_devCount++;
         }
         if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
-            dev = dev->next = new log_device_t("crash", false, 'c');
+            dev = dev->next = new log_device_t("crash", false);
             android::g_devCount++;
         }
     }
@@ -848,17 +833,15 @@
     //LOG_EVENT_LONG(11, 0x1122334455667788LL);
     //LOG_EVENT_STRING(0, "whassup, doc?");
 
-    if (needBinary)
-        android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
-
     dev = NULL;
+    log_device_t unexpected("unexpected", false);
     while (1) {
         struct log_msg log_msg;
         log_device_t* d;
         int ret = android_logger_list_read(logger_list, &log_msg);
 
         if (ret == 0) {
-            fprintf(stderr, "read: Unexpected EOF!\n");
+            fprintf(stderr, "read: unexpected EOF!\n");
             exit(EXIT_FAILURE);
         }
 
@@ -868,7 +851,7 @@
             }
 
             if (ret == -EIO) {
-                fprintf(stderr, "read: Unexpected EOF!\n");
+                fprintf(stderr, "read: unexpected EOF!\n");
                 exit(EXIT_FAILURE);
             }
             if (ret == -EINVAL) {
@@ -885,8 +868,9 @@
             }
         }
         if (!d) {
-            fprintf(stderr, "read: Unexpected log ID!\n");
-            exit(EXIT_FAILURE);
+            android::g_devCount = 2; // set to Multiple
+            d = &unexpected;
+            d->binary = log_msg.id() == LOG_ID_EVENTS;
         }
 
         if (dev != d) {
diff --git a/logd/Android.mk b/logd/Android.mk
index 188511f..127a66b 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -26,7 +26,16 @@
     libcutils \
     libutils
 
-LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
+# This is what we want to do:
+#  event_logtags = $(shell \
+#    sed -n \
+#        "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
+#        $(LOCAL_PATH)/$2/event.logtags)
+#  event_flag := $(call event_logtags,auditd)
+# so make sure we do not regret hard-coding it as follows:
+event_flag := -DAUDITD_LOG_TAG=1003
+
+LOCAL_CFLAGS := -Werror $(event_flag)
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index c7c0249..af0b775 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <endian.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
@@ -23,6 +24,8 @@
 #include <sys/uio.h>
 #include <syslog.h>
 
+#include <private/android_logger.h>
+
 #include "libaudit.h"
 #include "LogAudit.h"
 
@@ -138,29 +141,23 @@
     // log to events
 
     size_t l = strlen(str);
-    size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+    size_t n = l + sizeof(android_log_event_string_t);
 
     bool notify = false;
 
-    char *newstr = reinterpret_cast<char *>(malloc(n));
-    if (!newstr) {
+    android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n));
+    if (!event) {
         rc = -ENOMEM;
     } else {
-        cp = newstr;
-        *cp++ = AUDITD_LOG_TAG & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
-        *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
-        *cp++ = EVENT_TYPE_STRING;
-        *cp++ = l & 0xFF;
-        *cp++ = (l >> 8) & 0xFF;
-        *cp++ = (l >> 16) & 0xFF;
-        *cp++ = (l >> 24) & 0xFF;
-        memcpy(cp, str, l);
+        event->header.tag = htole32(AUDITD_LOG_TAG);
+        event->payload.type = EVENT_TYPE_STRING;
+        event->payload.length = htole32(l);
+        memcpy(event->payload.data, str, l);
 
-        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+        logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+                    reinterpret_cast<char *>(event),
                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
-        free(newstr);
+        free(event);
 
         notify = true;
     }
@@ -190,7 +187,7 @@
     }
     n = (estr - str) + strlen(ecomm) + l + 2;
 
-    newstr = reinterpret_cast<char *>(malloc(n));
+    char *newstr = static_cast<char *>(malloc(n));
     if (!newstr) {
         rc = -ENOMEM;
     } else {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 3d0b38f..edda6c4 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -93,8 +93,7 @@
 }
 
 LogBuffer::LogBuffer(LastLogTimes *times)
-        : dgramQlenStatistics(false)
-        , mTimes(*times) {
+        : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
 
     static const char global_tuneable[] = "persist.logd.size"; // Settings App
@@ -150,23 +149,6 @@
     while (last != mLogElements.begin()) {
         --it;
         if ((*it)->getRealTime() <= realtime) {
-            // halves the peak performance, use with caution
-            if (dgramQlenStatistics) {
-                LogBufferElementCollection::iterator ib = it;
-                unsigned short buckets, num = 1;
-                for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
-                    buckets -= num;
-                    num += buckets;
-                    while (buckets && (--ib != mLogElements.begin())) {
-                        --buckets;
-                    }
-                    if (buckets) {
-                        break;
-                    }
-                    stats.recordDiff(
-                        elem->getRealTime() - (*ib)->getRealTime(), i);
-                }
-            }
             break;
         }
         last = it;
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 879baea..b0003de 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -37,7 +37,6 @@
     pthread_mutex_t mLogElementsLock;
 
     LogStatistics stats;
-    bool dgramQlenStatistics;
 
     PruneList mPrune;
 
@@ -63,11 +62,6 @@
     // *strp uses malloc, use free to release.
     void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
 
-    void enableDgramQlenStatistics() {
-        stats.enableDgramQlenStatistics();
-        dgramQlenStatistics = true;
-    }
-
     void enableStatistics() {
         stats.enableStatistics();
     }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 53036e6..5a70689 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -395,71 +395,11 @@
 
 LogStatistics::LogStatistics()
         : mStatistics(false)
-        , dgramQlenStatistics(false)
         , start(CLOCK_MONOTONIC) {
     log_id_for_each(i) {
         mSizes[i] = 0;
         mElements[i] = 0;
     }
-
-    for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
-        mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
-        mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
-    }
-}
-
-//   Each bucket below represents a dgramQlen of log messages. By
-//   finding the minimum period of time from start to finish
-//   of each dgramQlen, we can get a performance expectation for
-//   the user space logger. The net result is that the period
-//   of time divided by the dgramQlen will give us the average time
-//   between log messages; at the point where the average time
-//   is greater than the throughput capability of the logger
-//   we will not longer require the benefits of the FIFO formed
-//   by max_dgram_qlen. We will also expect to see a very visible
-//   knee in the average time between log messages at this point,
-//   so we do not necessarily have to compare the rate against the
-//   measured performance (BM_log_maximum_retry) of the logger.
-//
-//   for example (reformatted):
-//
-//       Minimum time between log events per dgramQlen:
-//       1   2   3   5   10  20  30  50  100  200 300 400 500 600
-//       5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
-//
-//   demonstrates a clear knee rising at 100, so this means that for this
-//   case max_dgram_qlen = 100 would be more than sufficient to handle the
-//   worst that the system could stuff into the logger. The
-//   BM_log_maximum_retry performance (derated by the log collection) on the
-//   same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
-//   BM_log_maxumum_retry with statistics off is roughly 20us, so
-//   max_dgram_qlen = 20 would work. We will be more than willing to have
-//   a large engineering margin so the rule of thumb that lead us to 100 is
-//   fine.
-//
-// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
-const unsigned short LogStatistics::mBuckets[] = {
-    1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
-};
-
-unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
-    if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
-        return 0;
-    }
-    return mBuckets[bucket];
-}
-
-unsigned long long LogStatistics::minimum(unsigned short bucket) {
-    if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
-        return 0;
-    }
-    return mMinimum[bucket].nsec();
-}
-
-void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
-    if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
-        mMinimum[bucket] = diff;
-    }
 }
 
 void LogStatistics::add(unsigned short size,
@@ -709,55 +649,6 @@
         pids.clear();
     }
 
-    if (dgramQlenStatistics) {
-        const unsigned short spaces_time = 6;
-        const unsigned long long max_seconds = 100000;
-        spaces = 0;
-        string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
-        for(unsigned short i = 0; dgramQlen(i); ++i) {
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
-            spaces += spaces_time + oldLength - string.length();
-        }
-        string.append("\n");
-        spaces = 0;
-        unsigned short n;
-        for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
-            unsigned long long duration = minimum(i);
-            if (duration) {
-                duration /= n;
-                if (duration >= (NS_PER_SEC * max_seconds)) {
-                    duration = NS_PER_SEC * (max_seconds - 1);
-                }
-                oldLength = string.length();
-                if (spaces < 0) {
-                    spaces = 0;
-                }
-                string.appendFormat("%*s", spaces, "");
-                if (duration >= (NS_PER_SEC * 10)) {
-                    string.appendFormat("%llu",
-                        (duration + (NS_PER_SEC / 2))
-                            / NS_PER_SEC);
-                } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
-                    string.appendFormat("%llum",
-                        (duration + (NS_PER_SEC / 2 / 1000))
-                            / (NS_PER_SEC / 1000));
-                } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
-                    string.appendFormat("%lluu",
-                        (duration + (NS_PER_SEC / 2 / 1000000))
-                            / (NS_PER_SEC / 1000000));
-                } else {
-                    string.appendFormat("%llun", duration);
-                }
-                spaces -= string.length() - oldLength;
-            }
-            spaces += spaces_time;
-        }
-    }
-
     log_id_for_each(i) {
         if (!(logMask & (1 << i))) {
             continue;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f6c4329..f892cd0 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -145,7 +145,6 @@
     size_t mElements[LOG_ID_MAX];
 
     bool mStatistics;
-    bool dgramQlenStatistics;
 
     static const unsigned short mBuckets[14];
     log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
@@ -157,11 +156,7 @@
 
     LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
 
-    void enableDgramQlenStatistics() { dgramQlenStatistics = true; }
     void enableStatistics() { mStatistics = true; }
-    static unsigned short dgramQlen(unsigned short bucket);
-    unsigned long long minimum(unsigned short bucket);
-    void recordDiff(log_time diff, unsigned short bucket);
 
     void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
     void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
diff --git a/logd/README.property b/logd/README.property
index b7fcece..60542b2 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -7,12 +7,6 @@
 logd.statistics             bool depends Enable logcat -S statistics.
 ro.config.low_ram           bool  false  if true, logd.statistics default false
 ro.build.type               string       if user, logd.statistics default false
-logd.statistics.dgram_qlen  bool  false  Record dgram_qlen statistics. This
-                                         represents a performance impact and
-                                         is used to determine the platform's
-                                         minimum domain socket network FIFO
-                                         size (see source for details) based
-                                         on typical load (logcat -S to view)
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/main.cpp b/logd/main.cpp
index 7a1ae54..243bee4 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -155,9 +155,6 @@
 
     LogBuffer *logBuf = new LogBuffer(times);
 
-    if (property_get_bool("logd.statistics.dgram_qlen", false)) {
-        logBuf->enableDgramQlenStatistics();
-    }
     {
         char property[PROPERTY_VALUE_MAX];
         property_get("ro.build.type", property, "");
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 96877a9..46bd9c0 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -192,164 +192,6 @@
     EXPECT_TRUE(NULL != events_logs);
 #endif
 
-    // Parse timing stats
-
-    cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
-
-    if (cp) {
-        while (*cp && (*cp != '\n')) {
-            ++cp;
-        }
-        if (*cp == '\n') {
-            ++cp;
-        }
-
-        char *list_of_spans = cp;
-        EXPECT_NE('\0', *list_of_spans);
-
-        unsigned short number_of_buckets = 0;
-        unsigned short *dgram_qlen = NULL;
-        unsigned short bucket = 0;
-        while (*cp && (*cp != '\n')) {
-            bucket = 0;
-            while (isdigit(*cp)) {
-                bucket = bucket * 10 + *cp - '0';
-                ++cp;
-            }
-            while (*cp == ' ') {
-                ++cp;
-            }
-            if (!bucket) {
-                break;
-            }
-            unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
-            EXPECT_TRUE(new_dgram_qlen != NULL);
-            if (dgram_qlen) {
-                memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
-                delete [] dgram_qlen;
-            }
-
-            dgram_qlen = new_dgram_qlen;
-            dgram_qlen[number_of_buckets++] = bucket;
-        }
-
-        char *end_of_spans = cp;
-        EXPECT_NE('\0', *end_of_spans);
-
-        EXPECT_LT(5, number_of_buckets);
-
-        unsigned long long *times = new unsigned long long [number_of_buckets];
-        ASSERT_TRUE(times != NULL);
-
-        memset(times, 0, sizeof(*times) * number_of_buckets);
-
-        while (*cp == '\n') {
-            ++cp;
-        }
-
-        unsigned short number_of_values = 0;
-        unsigned long long value;
-        while (*cp && (*cp != '\n')) {
-            EXPECT_GE(number_of_buckets, number_of_values);
-
-            value = 0;
-            while (isdigit(*cp)) {
-                value = value * 10ULL + *cp - '0';
-                ++cp;
-            }
-
-            switch(*cp) {
-            case ' ':
-            case '\n':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'm':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'u':
-                value *= 1000ULL;
-                /* FALLTHRU */
-            case 'n':
-            default:
-                break;
-            }
-            while (*++cp == ' ');
-
-            if (!value) {
-                break;
-            }
-
-            times[number_of_values] = value;
-            ++number_of_values;
-        }
-
-#ifdef TARGET_USES_LOGD
-        EXPECT_EQ(number_of_values, number_of_buckets);
-#endif
-
-        FILE *fp;
-        ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
-
-        unsigned max_dgram_qlen = 0;
-        fscanf(fp, "%u", &max_dgram_qlen);
-
-        fclose(fp);
-
-        // Find launch point
-        unsigned short launch = 0;
-        unsigned long long total = 0;
-        do {
-            total += times[launch];
-        } while (((++launch < number_of_buckets)
-                && ((total / launch) >= (times[launch] / 8ULL)))
-            || (launch == 1)); // too soon
-
-        bool failure = number_of_buckets <= launch;
-        if (!failure) {
-            unsigned short l = launch;
-            if (l >= number_of_buckets) {
-                l = number_of_buckets - 1;
-            }
-            failure = max_dgram_qlen < dgram_qlen[l];
-        }
-
-        // We can get failure if at any time liblog_benchmarks has been run
-        // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
-        // at excessive values like 20000. It does so to measure the raw processing
-        // performance of logd.
-        if (failure) {
-            cp = find_benchmark_spam(cp);
-        }
-
-        if (cp) {
-            // Fake a failure, but without the failure code
-            if (number_of_buckets <= launch) {
-                printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
-                        number_of_buckets, launch);
-            }
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            if (max_dgram_qlen < dgram_qlen[launch]) {
-                printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
-                            " actual: %u vs %u\n",
-                        launch, max_dgram_qlen, dgram_qlen[launch]);
-            }
-        } else
-#ifndef TARGET_USES_LOGD
-        if (total)
-#endif
-        {
-            EXPECT_GT(number_of_buckets, launch);
-            if (launch >= number_of_buckets) {
-                launch = number_of_buckets - 1;
-            }
-            EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
-        }
-
-        delete [] dgram_qlen;
-        delete [] times;
-    }
     delete [] buf;
 }
 
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 05b83a2..d60dab4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -71,7 +71,6 @@
     umount \
     uptime \
     watchprops \
-    wipe \
 
 ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
 
diff --git a/toolbox/wipe.c b/toolbox/wipe.c
deleted file mode 100644
index 650a0d6..0000000
--- a/toolbox/wipe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <cutils/android_reboot.h>
-#include <sys/stat.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-
-/* Directories created by init defined in system/rootdir/init.rc */
-static char *INIT_DIRS[] = {
-    "/system/etc/ppp",
-    "/data/misc",
-    "/data/local",
-    "/data/local/tmp",
-    "/data/data",
-    "/data/app_private",
-    "/data/app",
-    NULL
-};
-
-static void wipe (const char *path);
-
-static int usage()
-{
-    fprintf(stderr, "wipe <system|data|all>\n\n"
-                    "system means '/system'\n"
-                    "data means '/data'\n");
-
-    return -1;
-}
-
-int wipe_main (int argc, char *argv[])
-{
-    char *whatToWipe;
-
-    if (argc != 2) return usage();
-
-    whatToWipe = argv[1];
-
-    if (0 == strcmp (whatToWipe, "system")) {
-        fprintf(stdout, "Wiping /system\n");
-        wipe ("/system");
-        fprintf(stdout, "Done wiping /android\n");
-    } else if (0 == strcmp (whatToWipe, "data")) {
-        fprintf(stdout, "Wiping /data\n");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /data\n");
-    } else if (0 == strcmp (whatToWipe, "all")) {
-        fprintf(stdout, "Wiping /system and /data\n");
-        wipe ("/system");
-        wipe ("/data");
-        fprintf(stdout, "Done wiping /system and /data\n");
-    } else if (0 == strcmp(whatToWipe, "nuke")) {
-		int ret;
-		fprintf(stdout, "Nuking the device...\n");
-		wipe ("/system");
-        wipe ("/data");
-		fprintf(stdout, "Device nuked! Rebooting...\n");
-		ret = android_reboot(ANDROID_RB_RESTART, 0, 0);
-	    if (ret < 0) {
-	        fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
-	        return 1;
-	    }
-	} else {
-        return usage();
-    }
-
-    return 0;
-}
-
-static char nameBuffer[PATH_MAX];
-static struct stat statBuffer;
-
-static void wipe (const char *path) 
-{
-    DIR *dir;
-    struct dirent *de;
-    int ret;
-
-    dir = opendir(path);
-
-    if (dir == NULL) {
-        fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                    path, strerror(errno));
-        return;
-    }
-
-    char *filenameOffset;
-
-    strcpy(nameBuffer, path);
-    strcat(nameBuffer, "/");
-
-    filenameOffset = nameBuffer + strlen(nameBuffer);
-
-    for (;;) {
-        de = readdir(dir);
-
-        if (de == NULL) {
-            break;
-        }
-
-        if (0 == strcmp(de->d_name, ".")
-                || 0 == strcmp(de->d_name, "..")
-                || 0 == strcmp(de->d_name, "lost+found")
-        ) {
-            continue;
-        }
-
-        strcpy(filenameOffset, de->d_name);
-
-        ret = lstat (nameBuffer, &statBuffer);
-
-        if (ret != 0) {
-            fprintf(stderr, "stat() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-        }
-
-        if(S_ISDIR(statBuffer.st_mode)) {
-            int i;
-            char *newpath;
-
-#if 0
-            closedir(dir);
-#endif
-
-            newpath = strdup(nameBuffer);
-            wipe(newpath);
-
-            /* Leave directories created by init, they have special permissions. */
-            for (i = 0; INIT_DIRS[i]; i++) {
-                if (strcmp(INIT_DIRS[i], newpath) == 0) {
-                    break;
-                }
-            }
-            if (INIT_DIRS[i] == NULL) {
-                ret = rmdir(newpath);
-                if (ret != 0) {
-                    fprintf(stderr, "rmdir() error on '%s' '%s'\n", 
-                        newpath, strerror(errno));
-                }
-            }
-
-            free(newpath);
-
-#if 0
-            dir = opendir(path);
-            if (dir == NULL) {
-                fprintf (stderr, "Error opendir'ing %s '%s'\n",
-                            path, strerror(errno));
-                return;
-            }
-#endif
-
-            strcpy(nameBuffer, path);
-            strcat(nameBuffer, "/");
-
-        } else {
-            ret = unlink(nameBuffer);
-
-            if (ret != 0) {
-                fprintf(stderr, "unlink() error on '%s' '%s'\n", 
-                    nameBuffer, strerror(errno));
-            }
-        }
-    }
-
-    closedir(dir);
-
-}